浏览代码

Implement cancel / redo operations

main
Tissevert 7 个月前
父节点
当前提交
303c4dcf19
共有 14 个文件被更改,包括 192 次插入76 次删除
  1. +4
    -0
      css/toolbar.css
  2. +0
    -4
      css/toolbar/zoom.css
  3. +10
    -0
      index.html
  4. +30
    -51
      js/GUI.js
  5. +62
    -0
      js/GUI/Editor.js
  6. +25
    -4
      js/GUI/Keys.js
  7. +2
    -0
      js/Main.js
  8. +6
    -5
      js/Scoria.js
  9. +13
    -4
      js/Toolbar/EditMode.js
  10. +15
    -0
      js/Toolbar/Help.js
  11. +1
    -2
      js/Toolbar/Menu.js
  12. +3
    -1
      js/Toolbar/Page.js
  13. +12
    -3
      js/View.js
  14. +9
    -2
      js/XML/ALTO.js

+ 4
- 0
css/toolbar.css 查看文件

@ -17,3 +17,7 @@
#wcThreshold {
width: 3.5em;
}
#toolbar button {
padding: 0;
}

+ 0
- 4
css/toolbar/zoom.css 查看文件

@ -1,7 +1,3 @@
#zoom button {
padding: 0;
}
#zoom input[type="number"] {
width: 3em;
}

+ 10
- 0
index.html 查看文件

@ -17,6 +17,12 @@
<li id="loadScoria" class="disabled">Importer des scories</li>
<li id="saveScoria" class="disabled">Exporter les scories</li>
</ul>
</div><div id="edit" class="menu">
<span>Édition</span>
<ul>
<li id="editCancel" class="disabled">Annuler</li>
<li id="editRedo" class="disabled">Refaire</li>
</ul>
</div><div id="help" class="menu">
<span>Aide</span>
<ul>
@ -43,6 +49,10 @@
<option value="blockOrder">Ordre des blocs</option>
</select>
</span>
<span>
<button id="cancel" title="Annuler" disabled></button>
<button id="redo" title="Refaire" disabled></button>
</span>
<span id="zoom">
<button id="fitWidth" title="Pleine largeur" ></button>
<input type="number" id="zoomAmount" value="100" step="10" min="30" max="250" title="Zoom"/>


+ 30
- 51
js/GUI.js 查看文件

@ -1,61 +1,40 @@
return {
/* Display */
var windowCatchAll = document.getElementById('windowCatchAll');
var workzone = document.getElementById('workzone');
var page = document.getElementById('page');
var selector = document.getElementById('selector');
windowCatchAll: document.getElementById('windowCatchAll'),
workzone: document.getElementById('workzone'),
page: document.getElementById('page'),
selector: document.getElementById('selector'),
/** Toolbar **/
/* Menus */
var menus = document.getElementsByClassName('menu');
var fileMenu = document.getElementById('file');
var loadALTO = document.getElementById('loadALTO');
var saveALTO = document.getElementById('saveALTO');
var loadScoria = document.getElementById('loadScoria');
var saveScoria = document.getElementById('saveScoria');
var helpMenu = document.getElementById('help');
var documentation = document.getElementById('documentation');
var reposLink = document.getElementById('reposLink');
[documentation, reposLink].forEach(function(elem) {
elem.addEventListener('click', function(e) {
if(e.target.tagName != 'A') {
e.target.children[0].click();
}
});
});
/* Controls */
var fileNumber = document.getElementById('fileNumber');
var fileName = document.getElementById('fileName');
var wcThreshold = document.getElementById('wcThreshold');
var mode = document.getElementById('mode');
var saveScoria = document.getElementById('saveScoria');
menus: document.getElementsByClassName('menu'),
fileMenu: document.getElementById('file'),
loadALTO: document.getElementById('loadALTO'),
saveALTO: document.getElementById('saveALTO'),
loadScoria: document.getElementById('loadScoria'),
saveScoria: document.getElementById('saveScoria'),
/* Zoom */
var zoom = document.getElementById('zoom');
var fitWidth = document.getElementById('fitWidth');
var zoomAmount = document.getElementById('zoomAmount');
var fitHeight = document.getElementById('fitHeight');
editMenu: document.getElementById('edit'),
editCancel: document.getElementById('editCancel'),
editRedo: document.getElementById('editRedo'),
return {
mode: mode,
fileMenu: fileMenu,
fileName: fileName,
fileNumber: fileNumber,
helpMenu: document.getElementById('help'),
documentation: document.getElementById('documentation'),
reposLink: document.getElementById('reposLink'),
loadALTO: loadALTO,
saveALTO: saveALTO,
loadScoria: loadScoria,
saveScoria: saveScoria,
/* Controls */
fileNumber: document.getElementById('fileNumber'),
fileName: document.getElementById('fileName'),
wcThreshold: document.getElementById('wcThreshold'),
mode: document.getElementById('mode'),
menus: menus,
page: page,
selector: selector,
wcThreshold: wcThreshold,
windowCatchAll: windowCatchAll,
workzone: workzone,
/* Cancel / Redo */
cancel: document.getElementById('cancel'),
redo: document.getElementById('redo'),
fitWidth: fitWidth,
zoomAmount: zoomAmount,
fitHeight: fitHeight
/* Zoom */
zoom: document.getElementById('zoom'),
fitWidth: document.getElementById('fitWidth'),
zoomAmount: document.getElementById('zoomAmount'),
fitHeight: document.getElementById('fitHeight')
};

+ 62
- 0
js/GUI/Editor.js 查看文件

@ -0,0 +1,62 @@
import GUI;
import bind from GUI.Keys;
import toggleWord from Scoria;
var edits = [];
var cursor = -1;
GUI.cancel.addEventListener('click', cancel);
GUI.editCancel.addEventListener('click', cancel);
GUI.redo.addEventListener('click', redo);
GUI.editRedo.addEventListener('click', redo);
bind('Ctrl+z', cancel);
bind('Ctrl+y', redo);
return {
push: push
};
function cancel(e) {
if(cursor >= 0) {
edits[cursor--].wordIds.forEach(function(wordId) {toggleWord(wordId);});
updateButtons();
} else if(e != undefined) {
e.stopPropagation();
}
}
function redo(e) {
if(cursor < edits.length - 1) {
edits[++cursor].wordIds.forEach(function(wordId) {toggleWord(wordId);});
updateButtons();
} else if(e != undefined) {
e.stopPropagation();
}
}
function push(description, wordIds, perform) {
edits.length = ++cursor + 1;
edits[cursor] = {description: description, wordIds: wordIds};
if(perform) {
wordIds.forEach(function(wordId) {toggleWord(wordId);});
}
updateButtons();
}
function setState(action, disabled) {
if(action == 'redo') {
var label = 'Refaire' + (disabled ? '' : ' ' + edits[cursor + 1].description);
} else {
var label = 'Annuler' + (disabled ? '' : ' ' + edits[cursor].description);
}
GUI[action].title = label;
GUI[action].disabled = disabled;
var menuElem = GUI['edit' + action[0].toUpperCase() + action.slice(1)];
menuElem.textContent = label;
menuElem.classList.toggle('disabled', disabled);
}
function updateButtons() {
setState('cancel', cursor < 0);
setState('redo', cursor >= edits.length - 1);
}

+ 25
- 4
js/GUI/Keys.js 查看文件

@ -1,18 +1,39 @@
var bindings = {};
var bindings = binTree(4);
return {
bind: bind,
init: init
};
function binTree(n) {
if(n == 0) {
return {};
} else {
return {false: binTree(n-1), true: binTree(n-1)};
}
}
function bind(keyCode, f) {
bindings[keyCode] = f;
var components = keyCode.match(/((?:Alt|Ctrl|Meta|Shift)\+)*(.+)$/);
if(components) {
var key = components[2];
var modifiers = components[0].split('+');
bindings
[modifiers.includes('Alt')]
[modifiers.includes('Ctrl')]
[modifiers.includes('Meta')]
[modifiers.includes('Shift')]
[key] = f;
} else {
console.log("Did not add binding for invalid key code '" + keyCode + "'");
}
}
function init() {
window.addEventListener('keydown', function(e) {
if(bindings[e.key] != undefined) {
bindings[e.key]();
var binding = bindings[e.altKey][e.ctrlKey][e.metaKey][e.shiftKey][e.key];
if(binding != undefined) {
binding();
}
});
}

+ 2
- 0
js/Main.js 查看文件

@ -1,9 +1,11 @@
import * as Keys from GUI.Keys;
import * as EditMode from Toolbar.EditMode;
import * as Help from Toolbar.Help;
import * as Menu from Toolbar.Menu;
import * as Page from Toolbar.Page;
EditMode.sync();
Page.syncNumber();
Help.init();
Menu.init();
Keys.init();

+ 6
- 5
js/Scoria.js 查看文件

@ -29,10 +29,11 @@ function setScoria(wordId, state) {
}
}
function toggleWord(domElem, forceState) {
if(mode.value == 'edit') {
var state = forceState != undefined ? forceState : !scoriae[domElem.id];
setScoria(domElem.id, state);
domElem.classList.toggle('deleted', state);
function toggleWord(wordId) {
var state = !scoriae[wordId];
setScoria(wordId, state);
var word = document.getElementById(wordId);
if(word != undefined) {
word.classList.toggle('deleted', state);
}
}

+ 13
- 4
js/Toolbar/EditMode.js 查看文件

@ -1,4 +1,5 @@
import {mode, page, selector, workzone} from GUI;
import GUI.Editor;
import * as Rectangle from Geometry.Rectangle;
import toggleWord from Scoria;
@ -48,6 +49,7 @@ function moveRectangle(e) {
function endRectangle(e) {
if(mode.value == 'edit') {
recordEdit();
selection = {words: {}, x: {from: null, to: null}, y: {from: null, to: null}};
selector.style.left = selector.style.top = selector.style.width =
selector.style.height = null;
@ -60,8 +62,8 @@ function updateSelection() {
var rectangle = Rectangle.make(selection);
updateSelected(rectangle, page);
for(var id in selection.words) {
if(!Rectangle.contains(rectangle, selection.words[id].rectangle)) {
toggleWord(selection.words[id].domElem);
if(!Rectangle.contains(rectangle, selection.words[id])) {
toggleWord(id);
delete selection.words[id];
}
}
@ -82,7 +84,14 @@ function updateSelected(rectangle, domElem) {
function updateWord(rectangle, domElem) {
var elemRectangle = Rectangle.make(domElem);
if(Rectangle.contains(rectangle, elemRectangle) && !selection.words[domElem.id]) {
selection.words[domElem.id] = {rectangle: elemRectangle, domElem: domElem};
toggleWord(domElem);
selection.words[domElem.id] = elemRectangle;
toggleWord(domElem.id);
}
}
function recordEdit() {
var edit = Object.keys(selection.words);
if(edit.length > 0) {
GUI.Editor.push('la sélection rectangulaire de ' + edit.length + ' mots', edit);
}
}

+ 15
- 0
js/Toolbar/Help.js 查看文件

@ -0,0 +1,15 @@
import {documentation, reposLink} from GUI;
return {
init: init
};
function init() {
[documentation, reposLink].forEach(function(elem) {
elem.addEventListener('click', function(e) {
if(e.target.tagName != 'A') {
e.target.children[0].click();
}
});
});
}

+ 1
- 2
js/Toolbar/Menu.js 查看文件

@ -41,8 +41,7 @@ function toggleMenu(menu) {
}
function closeMenu(e) {
if(selectedMenu != undefined
&& !(e != undefined && e.target.classList.contains('disabled'))) {
if(selectedMenu != undefined) {
selectedMenu.classList.remove('open');
selectedMenu = null;
windowCatchAll.className = '';


+ 3
- 1
js/Toolbar/Page.js 查看文件

@ -26,7 +26,7 @@ GUI.loadALTO.addEventListener('click', function() {
);
});
GUI.saveALTO.addEventListener('click', function() {
GUI.saveALTO.addEventListener('click', function(e) {
if(!GUI.saveALTO.classList.contains('disabled')) {
var file = files[GUI.fileNumber.value];
Async.run(
@ -39,6 +39,8 @@ GUI.saveALTO.addEventListener('click', function() {
})
)
);
} else {
e.stopPropagation();
}
});


+ 12
- 3
js/View.js 查看文件

@ -1,5 +1,6 @@
import File;
import GUI;
import push from GUI.Editor;
import * as Keys from GUI.Keys;
import Scoria;
import * as Zoom from Toolbar.Zoom;
@ -53,7 +54,7 @@ function scale(o) {
}
}
function importScoria() {
function importScoria(e) {
if(!GUI.loadScoria.classList.contains('disabled')) {
Async.run(
Async.bind(
@ -69,21 +70,29 @@ function importScoria() {
Async.map(refresh)
)
);
} else {
e.stopPropagation();
}
}
function setFromFiles(files) {
var edit = [];
files.forEach(function(file) {
file.split('\n').slice(1).forEach(function(line) {
var wordIds = file.split('\n').slice(1);
wordIds.forEach(function(line) {
Scoria.setScoria(line);
});
edit = edit.concat(wordIds);
});
push('le chargement des ' + files.length + ' fichiers de scories', edit);
}
function exportScoria() {
function exportScoria(e) {
if(!GUI.saveScoria.classList.contains('disabled')) {
var column = ['ID'].concat(Scoria.getScoriae());
var data = 'data:text/csv,' + encodeURIComponent(column.join('\n'));
File.save(data, 'scoria.csv');
} else {
e.stopPropagation();
}
}

+ 9
- 2
js/XML/ALTO.js 查看文件

@ -1,7 +1,8 @@
import * as Element from XML.ALTO.Element;
import {isScoria, toggleWord} from Scoria;
import isScoria from Scoria;
import Quality;
import GUI;
import push from GUI.Editor;
import * as Dom from UnitJS.Dom;
import * as Zoom from Toolbar.Zoom;
@ -46,7 +47,13 @@ function setAttributes(element, attributes) {
attributes.class = attributes.class
.concat(Quality.isLow(element.get('WC')) ? 'lowQuality' : [])
.concat(isScoria(element.get('ID')) ? 'deleted' : []);
attributes.onClick = function(e) {toggleWord(e.target)};
attributes.onClick = function(e) {
if(GUI.mode.value == 'edit') {
var word = e.target;
var action = isScoria(word.id) ? "l'ajout" : "la suppression";
push(action + ' du mot «' + word.textContent + '»', [word.id], true);
}
};
}
function blockPositionElem() {


正在加载...
取消
保存