Skip to content

Commit

Permalink
Painel de Configuração com opção de editar código por bloco ou por linha
Browse files Browse the repository at this point in the history
  • Loading branch information
Vamoss committed Dec 25, 2023
1 parent cfad270 commit dd254f6
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 29 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

Este é um protótipo de editor de texto compatível com leitores de telas.

Demonstração em: https://vamoss.github.io/codigoAcessivel/

O objetivo é proporcionar uma primeira experiência de programação para pessoas cegas utilizando o celular, facilitando a navegação e edição do código.

Identificamos que os editores de texto em celulares não permitem uma experiência de navegação e edição do código que se localizar com facilitade.

Por isso a estratégia deste projeto foi segmentar o código em linhas, e cada estrutura do código da linha em bloco editáveis individualmente.
Por isso a estratégia deste projeto foi segmentar o código em linhas, e cada estrutura do código da linha em bloco editáveis individualmente. Pelo menu de Configuração é possível alterar esse comportamento para editar a linha inteira em um único bloco de comando.

## Como rodar o projeto

Expand Down
49 changes: 46 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,63 @@
<script src="script.js"></script>
</head>
<body>
<!-- descrição do projeto -->
<div>
<h1>Protótipo de editor de texto compatível com leitores de telas</h1>
<p>O objetivo é proporcionar uma primeira experiência de programação para pessoas cegas utilizando o celular.</p>
<p>Abaixo você vai encontrar dois botões, um para editar o código e outro para executar o código.</p>
<p>No editor de código, cada linha é ativada por um botão. Após ativar a linha, você poderá editar cada bloco da linha separadamente.</p>
<p>Nesta fase do protótipo, é interessante saber se quebrar a linha em blocos ajuda ou dificulta a experiência de edição do código.</p>
<p>Abaixo você vai encontrar três botões: editar o código, executar o código e configurações de navegação e edição.</p>
<p>Em seguida você encontrará o código navegável por linha. É necessário ativar a linha para poder editá-la.</p>
<p>Como limitação conhecida, o editor ainda não permite quebra de linhas.</p>
</div>

<!-- menu de navegação -->
<nav id="editorMenu">
<button aria-label="Editar código" tabindex="0" id="botaoEditor" class="btn btn-light bi-code-slash"></button>
<button aria-label="Executar código" tabindex="0" id="botaoExecutar" class="btn btn-light bi-play-circle-fill"></button>
<button aria-label="Configurações" tabindex="0" id="botaoConfigurar" class="btn btn-light bi-gear-fill" data-bs-toggle="modal" data-bs-target="#configModal"></button>
</nav>

<!-- container onde ficará o código editável -->
<div id="editorDiv"></div>

<!-- iframe onde o código editado será executado -->
<iframe id="execucaoIframe" src="about:blank"></iframe>

<!-- Modal de configurações -->
<div class="modal fade" id="configModal" tabindex="-1" aria-labelledby="configModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="configModalLabel">Configurações</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fechar configurações"></button>
</div>
<div class="modal-body">

<fieldset>
<label for="modoEdicao">Modo de edição:</label>
<select id="modoEdicao" class="form-select" aria-label="Modo de edição:">
<option value="bloco" selected>Editar código por blocos (Cada estrutura do código é editável separadamente)</option>
<option value="linha">Editar código por linha inteira (A linha é editável de forma única)</option>
</select>
</fieldset>

<fieldset>
<label for="exibirLinha">Escrever numeração das linhas:</label>
<select id="exibirLinha" class="form-select" aria-label="Escrever numeração das linhas:">
<option value="sim" selected>Sim, exibir numeração das linhas.</option>
<option value="nao">Não, esconder numeração das linhas.</option>
</select>
</fieldset>

</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="botaoSalvarConfiguracao">Salvar Configurações</button>
</div>
</div>
</div>
</div>

<!-- script do bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
</body>
</html>
107 changes: 82 additions & 25 deletions script.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ var blocoSelecionadoDiv;//div editável selecionada na linha atual
var cursorIndex;//index do cursor na caixa de texto editável selecionada
var cursorMaxIndex;//máximo de caracteres da caixa de texto editável selecionada

//configurações
var modoEdicaoField;//Selection box que determina o modo de edição do código, por blocos ou por linhas
var exibirLinhaField;//Selection box que determina se deve exibir ou não a numeração das linhas
var modalConfiguracoes;//objeto bootstrap.Modal, controla a janela de configurações
window.addEventListener("DOMContentLoaded", function(){
if(document.contentEditable != undefined) {
alert("Seu navegador não suporta edição de texto HTML5");
Expand All @@ -104,6 +108,21 @@ function inicializa()
document.getElementById("botaoEditor").addEventListener("click", mostraEditor);
document.getElementById("botaoExecutar").addEventListener("click", executarCodigo);

//inicializa configurações
modoEdicaoField = document.getElementById("modoEdicao");
exibirLinhaField = document.getElementById("exibirLinha");
const configModal = document.getElementById('configModal');
configModal.addEventListener('hidden.bs.modal', carregaConfiguracao);
modalConfiguracoes = new bootstrap.Modal(configModal);
document.getElementById('botaoSalvarConfiguracao').addEventListener("click", () =>{
salvaConfiguracao();
converteCodigoParaEditor(codigoAtual());
modalConfiguracoes.hide();
document.getElementById("botaoConfigurar").focus();
});
carregaConfiguracao();


//inicializa o monitoramento de teclas apertadas
document.addEventListener('keydown', onKeyDown);

Expand All @@ -121,15 +140,15 @@ function inicializa()
xhr.send();
}

//Função acionada pela interface que apresenta o editor de conteúdo
//Função que apresenta o editor de conteúdo
function mostraEditor(event)
{
editorDiv.style.display = "block";
execucaoIframe.style.display = "none";
execucaoIframe.contentWindow.location = "about:blank";
}

//Função acionada pela interface que executa a última versão editada do código
//Função que executa a última versão editada do código
function executarCodigo(event)
{
editorDiv.style.display = "none";
Expand All @@ -143,19 +162,31 @@ function executarCodigo(event)
}

//Função que converte uma string no editor de código
function converteCodigoParaEditor(code){
//parse code
function converteCodigoParaEditor(codigo){
var codigoHTML = "";
var linhas = code.split("\n");
linhas.forEach((linha, counter) => {
var linhas = codigo.split("\n");
linhas.forEach((linha, contador) => {
linha = linha.replace("\r", "");//remove um caracter extra de quebra de linhas no windows
codigoHTML += `<div class="linha">`;
codigoHTML += `<button class="botaoLinha" onclick="expandirLinha(this)" onfocus="botaoLinhaFocado(this)" aria-rotulo="Linha ${counter+1}. ${converteCodigoEmAria(linha)}" data-contador="${counter+1}" data-codigo="${encodeURI(linha)}">Linha ${counter+1}. ${linha}</button>`
codigoHTML += `<button class="botaoLinha" onclick="expandirLinha(this)" onfocus="botaoLinhaFocado(this)" aria-label="${criaCodigoAudivel(true, contador+1, linha)}" data-contador="${contador+1}" data-codigo="${encodeURI(linha)}">${criaCodigoAudivel(false, contador+1, linha)}</button>`
codigoHTML += `<div hidden></div>`;
codigoHTML += `</div>\n`;
})
editorDiv.innerHTML = codigoHTML;
}

//Função que cria o código audível de acorod com as configurações
function criaCodigoAudivel(ariaMode, contador, codigo){
var resultado = codigo;
if(ariaMode){
resultado = converteCodigoEmAria(resultado);
}
if(exibirLinhaField.value == "sim"){
resultado = "Linha " + contador + ". " + resultado;
}
return resultado;
}

//Função que divide uma string em uma array separada por uma lista de caracteres
function divideStringPorCaracteres(str, separadoresArray) {
// Função auxiliar para dividir a string com base em um único caractere
Expand Down Expand Up @@ -211,12 +242,14 @@ function converteCodigoEmAria(str){
//Função que converte a última versão do código para uma string
function codigoAtual(){
atualizaERecolheLinhaSelecionada();
var buttons = Array.from(document.querySelectorAll('.botaoLinha'));
var code = "";
buttons.forEach(button => {
code += decodeURI(button.getAttribute("data-codigo")) + "\n";
var botoes = Array.from(document.querySelectorAll('.botaoLinha'));
var codigo = "";
botoes.forEach((botao, index) => {
codigo += decodeURI(botao.getAttribute("data-codigo"));
if(index < botoes.length-1)
codigo += "\n";
})
return code;
return codigo;
}

//Função que recolhe a linha editada e atualiza o botão com a última versão do código
Expand All @@ -231,9 +264,9 @@ function atualizaERecolheLinhaSelecionada(){
}
var botao = linhaSelecionadaDiv.previousSibling;
var contador = botao.getAttribute("data-contador");
botao.setAttribute("aria-label", `Linha ${contador}. ${converteCodigoEmAria(codigo)}`);
botao.setAttribute("aria-label", criaCodigoAudivel(true, contador, codigo));
botao.setAttribute("data-codigo", encodeURI(codigo));
botao.textContent = `Linha ${contador}. ${codigo}`;
botao.textContent = criaCodigoAudivel(false, contador, codigo);
}
linhaSelecionadaDiv = null;
}
Expand All @@ -243,14 +276,20 @@ function expandirLinha(botao){
atualizaERecolheLinhaSelecionada();
botao.nextSibling.hidden = false;
linhaSelecionadaDiv = botao.nextSibling;
var code = decodeURI(botao.getAttribute("data-codigo"));
var words = divideStringPorCaracteres(code, separators.map(s => s.char));
var computedCode = "";
words.forEach(palavra => {
var editavel = ignorarEdicao.includes(palavra) ? "" : `contenteditable="true"`;
computedCode += `<div ${editavel} spellcheck="false" class="palavra">${palavra}</div>`;
})
linhaSelecionadaDiv.innerHTML = computedCode;
var codigo = decodeURI(botao.getAttribute("data-codigo"));
var estruturaHTML = "";
if(modoEdicaoField.value == "bloco"){
//quebra o código em vários blocos editáveis individualmente
var blocos = divideStringPorCaracteres(codigo, separators.map(s => s.char));
blocos.forEach(bloco => {
var editavel = ignorarEdicao.includes(bloco) ? "" : `contenteditable="true"`;
estruturaHTML += `<div ${editavel} spellcheck="false" class="palavra">${bloco}</div>`;
})
}else{
//mantém um único bloco editável para toda a linha
estruturaHTML += `<div contenteditable="true" spellcheck="false" class="palavra">${codigo}</div>`;
}
linhaSelecionadaDiv.innerHTML = estruturaHTML;
linhaSelecionadaDiv.firstChild.focus();
}

Expand Down Expand Up @@ -290,7 +329,7 @@ function onKeyDown(e) {
}
else if (e.keyCode == '39') {
// seta para direita
procuraProximoBloco();
procuraBlocoADireita();
}
}

Expand All @@ -299,7 +338,7 @@ function onKeyDown(e) {
function procuraBlocoADireita(){
if(blocoSelecionadoDiv){
if(cursorIndex == cursorMaxIndex){
if(blocoSelecionadoDiv.nextSibling)
if(blocoSelecionadoDiv.nextSibling)
blocoSelecionadoDiv.nextSibling.focus();
else {
blocoSelecionadoDiv.parentNode.nextSibling.nextSibling.firstChild.focus();
Expand All @@ -324,12 +363,30 @@ function procuraBlocoAEsquerda(){
}
var range = document.createRange()
var sel = window.getSelection()
console.log(blocoSelecionadoDiv);
range.setStart(blocoSelecionadoDiv.firstChild, blocoSelecionadoDiv.firstChild.length)
range.collapse(true)

sel.removeAllRanges()
sel.addRange(range)
}
}
}

//Função que carrega a configuração
function carregaConfiguracao() {
if(localStorage.getItem("modoEdicao") === null){
//ainda não há configuração salva
//configura valores padrões
modoEdicaoField.value = "bloco";
exibirLinhaField.value = "sim";
}else{
modoEdicaoField.value = localStorage.getItem("modoEdicao");
exibirLinhaField.value = localStorage.getItem("exibirLinha");
}
}

//Função que salva a configuração
function salvaConfiguracao() {
localStorage.setItem("modoEdicao", modoEdicaoField.value);
localStorage.setItem("exibirLinha", exibirLinhaField.value);
}

0 comments on commit dd254f6

Please sign in to comment.