Commit 4b8792f0 authored by Robin Tissot's avatar Robin Tissot
Browse files

fully working prototype (no reordering).

parent c5773736
......@@ -14,8 +14,13 @@ var diploLine = LineBase.extend({
}
}
},
mounted() {
Vue.nextTick(function() {
this.$parent.appendLine();
}.bind(this));
},
watch: {
'line.order': function(o, n) {
'line.order': function(n,o) {
// make sure it's at the right place,
// in case it was just created or the ordering got recalculated
let index = Array.from(this.$el.parentNode.children).indexOf(this.$el);
......@@ -24,48 +29,17 @@ var diploLine = LineBase.extend({
this.$el,
this.$el.parentNode.children[this.line.order]);
}
},
'line.currentTrans': function(n, o) {
let line = this.getEl();
if (n!=undefined && n.content) {
line.textContent = n.content;
}
}
},
methods: {
cleanSource(dirtyText) {
// cleanup html and possibly other tags (?)
var tmp = document.createElement("DIV");
tmp.innerHTML = dirtyText;
let clean = tmp.textContent || tmp.innerText || "";
tmp.remove();
return clean;
},
onPaste(e) {
let pastedData = e.clipboardData.getData('text/plain');
let pasted_data_split = pastedData.split('\n');
if (pasted_data_split.length == 1) {
// all of this just to call cleanSource on the data
let paste = (event.clipboardData || window.clipboardData).getData('text');
paste = this.cleanSource(paste);
const selection = window.getSelection();
if (!selection.rangeCount) return false;
selection.deleteFromDocument();
selection.getRangeAt(0).insertNode(document.createTextNode(paste));
} else {
//remove the last line if it's empty
if (pasted_data_split[pasted_data_split.length - 1] == "") {
pasted_data_split.pop();
}
let index = this.$parent.$children.indexOf(this);
for (let i = 0; i < pasted_data_split.length; i++) {
let content = pasted_data_split[i];
let child = this.$parent.$children[index + i];
if (child) {
child.$el.textContent = this.cleanSource(content);
}
}
}
e.preventDefault();
},
getContentOrFake() {
return this.line.currentTrans.content;
getEl() {
return this.$parent.editor.querySelector('div:nth-child('+parseInt(this.line.order+1)+')');
},
getRegion() {
return this.$parent.part.regions.findIndex(r => r.pk == this.line.region);
......
var timer ;
var DiploPanel = BasePanel.extend({
data() { return {
updatedLines : [],
......@@ -9,38 +8,90 @@ var DiploPanel = BasePanel.extend({
components: {
'diploline': diploLine,
},
/* mounted(){
* Vue.nextTick(function() {
* var vm = this ;
* var el = document.getElementById('list');
* sortable = Sortable.create(el, {
* group: 'shared',
* multiDrag: true,
* multiDragKey : 'CTRL',
* selectedClass: "selected",
* animation: 150,
* onEnd: function(evt) {
* vm.onDragginEnd(evt);
* }
* });
* }.bind(this));
* }, */
methods:{
startEdit(ev){
created() {
// vue.js quirck, have to dinamically create the event handler
// call save every 10 seconds after last change
this.debouncedSave = _.debounce(function() {
this.save();
}.bind(this), 10000);
},
mounted() {
/* Vue.nextTick(function() {
* var vm = this ;
* var el = document.getElementById('list');
* sortable = Sortable.create(el, {
* group: 'shared',
* multiDrag: true,
* multiDragKey : 'CTRL',
* selectedClass: "selected",
* animation: 150,
* onEnd: function(evt) {
* vm.onDragginEnd(evt);
* }
* });
* }.bind(this));
*/
this.editor = this.$el.querySelector('#diplomatic-lines');
this.saveNotif = this.$el.querySelector('.tools #save-notif');
},
methods: {
changed() {
this.saveNotif.classList.remove('hide');
this.debouncedSave();
},
appendLine(pos) {
let div = document.createElement('div');
div.appendChild(document.createElement('br'));
if (pos === undefined) {
this.editor.appendChild(div);
} else {
this.editor.insertBefore(div, pos.nextSibling);
}
return div;
},
constrainLineNumber() {
// add lines untill we have enough of them
while (this.editor.childElementCount < this.part.lines.length) {
this.appendLine();
}
// need to add/remove danger indicators
for (let i=0; i<this.editor.childElementCount; i++) {
let line = this.editor.querySelector('div:nth-child('+parseInt(i+1)+')');
if (line === null) {
this.editor.children[i].remove();
continue;
}
if (i<this.part.lines.length) {
line.classList.remove('alert-danger');
line.setAttribute('title', '');
} else if (i>=this.part.lines.length) {
if (line.textContent == '') { // just remove empty lines
line.remove();
} else {
line.classList.add('alert-danger');
line.setAttribute('title', 'More lines than there is in the segmentation!');
}
}
}
},
startEdit(ev) {
this.$parent.blockShortcuts = true;
},
stopEdit(ev) {
this.$parent.blockShortcuts = false;
this.constrainLineNumber();
this.save();
},
onDragginEnd(ev) {
/*
Finish dragging lines, save new positions
*/
Finish dragging lines, save new positions
*/
if(ev.newIndicies.length == 0 && ev.newIndex != ev.oldIndex){
let pk = ev.item.querySelector('.line-content').id;
let elt = {"pk":pk, "index":ev.newIndex};
this.movedLines.push(elt);
}
else {
for(let i=0; i< ev.newIndicies.length; i++){
......@@ -63,9 +114,10 @@ var DiploPanel = BasePanel.extend({
},
save() {
/*
if some lines are modified add them to updatedlines,
if some lines are modified add them to updatedlines,
new lines add them to createdLines then save
*/
this.saveNotif.classList.add('hide');
this.addToList();
this.bulkUpdate();
this.bulkCreate();
......@@ -90,6 +142,7 @@ var DiploPanel = BasePanel.extend({
sel.addRange(range);
}
},
onKeyPress(ev) {
// arrows needed to avoid skipping empty lines
if (ev.key == 'ArrowDown' && !ev.shiftKey) {
......@@ -102,64 +155,61 @@ var DiploPanel = BasePanel.extend({
let div = sel.anchorNode.nodeType==Node.TEXT_NODE?sel.anchorNode.parentElement:sel.anchorNode;
this.focusPreviousLine(sel, div);
ev.preventDefault();
} else if (ev.key == 'Enter') {
if (window.getSelection) {
const selection = window.getSelection();
let range = selection.getRangeAt(0);
// push text down
let lineNode = range.endContainer.nodeType==Node.TEXT_NODE?range.endContainer.parentNode:range.endContainer;
let lines = lineNode.parentNode.childNodes;
let curIndex = Array.prototype.indexOf.call(lines, lineNode);
let nextText = lineNode.textContent.slice(range.endOffset).trim();
this.$children[curIndex].$el.textContent = lineNode.textContent.slice(0, range.startOffset).trim();
for (let i=curIndex+1; i<lines.length-1; i++) {
let text = nextText;
nextText = lines[i].textContent;
this.$children[i].$el.textContent = text;
}
// focus next line
this.focusNextLine(selection, lineNode);
}
ev.preventDefault();
} else if (ev.key == 'Backspace') {
}
},
cleanSource(dirtyText) {
// cleanup html and possibly other tags (?)
var tmp = document.createElement("DIV");
tmp.innerHTML = dirtyText;
let clean = tmp.textContent || tmp.innerText || "";
tmp.remove();
return clean;
},
onPaste(e) {
let pastedData = e.clipboardData.getData('text/plain');
let pasted_data_split = pastedData.split('\n');
if (pasted_data_split.length == 1) {
let content = this.cleanSource(pastedData);
document.execCommand('insertText', false, content);
} else {
const selection = window.getSelection();
let range = selection.getRangeAt(0);
if (range.startContainer != range.endContainer) {
// override default behavior to avoid deleting entire lines
let startLine = range.startContainer.nodeType==Node.TEXT_NODE?range.startContainer.parentNode:range.startContainer;
let endLine = range.endContainer.nodeType==Node.TEXT_NODE?range.endContainer.parentNode:range.endContainer;
let inRange = false;
for (let i=0; i<this.$children.length; i++) {
let line = this.$children[i].$el;
if (line == startLine) {
line.textContent = line.textContent.slice(0, range.startOffset);
inRange = true;
} else if (line == endLine) {
line.textContent = line.textContent.slice(range.endOffset);
break;
} else if (inRange) {
line.textContent = '';
}
}
ev.preventDefault();
} else if (range.startOffset == 0 && range.endOffset == 0) {
// push text up
let lineNode = range.startContainer.nodeType==Node.TEXT_NODE?range.startContainer.parentNode:range.startContainer;
let lines = lineNode.parentNode.childNodes;
let curIndex = Array.prototype.indexOf.call(lines, lineNode);
if (curIndex > 0) {
// append content to previous line
this.$children[curIndex-1].$el.textContent += this.$children[curIndex].$el.textContent;
for (let i=curIndex; i<lines.length-1; i++) {
this.$children[i].$el.textContent = this.$children[i+1].$el.textContent;
}
this.$children[lines.length-1].$el.textContent = '';
let target = range.startContainer.nodeType==Node.TEXT_NODE?range.startContainer.parentNode:range.startContainer;
let start = Array.prototype.indexOf.call(target.parentNode.children, target);
for (let i = 0; i < pasted_data_split.length; i++) {
let content = pasted_data_split[i];
let child = target.parentNode.children[start+i];
let newDiv;
if (child) {
newDiv = this.appendLine(child);
} else {
newDiv = this.appendLine();
}
ev.preventDefault();
// trick to get at least 'some' ctrl+z functionality
range.setStart(newDiv, 0);
selection.removeAllRanges();
selection.addRange(range);
document.execCommand("insertText", false, this.cleanSource(content));
}
}
this.constrainLineNumber();
e.preventDefault();
},
showOverlay(ev) {
let target = ev.target.nodeType==Node.TEXT_NODE?ev.target.parentNode:ev.target;
let index = Array.prototype.indexOf.call(target.parentNode.children, target);
if (index > -1 && index < this.$children.length) {
this.$children[index].showOverlay();
} else {
this.hideOverlay();
}
},
hideOverlay() {
this.$children[0].hideOverlay();
},
bulkUpdate() {
if(this.updatedLines.length){
this.$parent.$emit(
......@@ -186,9 +236,8 @@ var DiploPanel = BasePanel.extend({
*/
for(let i=0; i<this.$children.length; i++) {
let currentLine = this.$children[i];
if(currentLine.line.currentTrans.content != currentLine.$el.textContent){
// TODO: sanitize text content?!
currentLine.line.currentTrans.content = currentLine.$el.textContent;
if(currentLine.line.currentTrans.content != currentLine.getEl().textContent){
currentLine.line.currentTrans.content = currentLine.getEl().textContent;
if(currentLine.line.currentTrans.pk) {
this.addToUpdatedLines(currentLine.line.currentTrans);
} else {
......@@ -199,7 +248,7 @@ var DiploPanel = BasePanel.extend({
},
addToUpdatedLines(lt) {
/*
if line already exists in updatedLines update its content on the list
if line already exists in updatedLines update its content on the list
*/
let elt = this.updatedLines.find(l => l.pk === lt.pk);
if(elt == undefined) {
......@@ -211,7 +260,7 @@ var DiploPanel = BasePanel.extend({
},
updateView() {
/*
update the size of the panel
update the size of the panel
*/
this.setHeight();
},
......
......@@ -206,6 +206,14 @@ form.inline-form {
opacity: .5;
}
.tools .notice {
color: var(--warning);
border: 1px solid;
padding: .25rem .5rem;
border-radius: .2rem;
float: right;
}
.help.open:hover {
opacity: 1;
}
......@@ -596,8 +604,9 @@ i.panel-icon {
}
#diplomatic-lines {
counter-reset: line;
line-clamp: 10;
}
#diplomatic-lines div.line-content {
#diplomatic-lines div {
display: block;
line-height: 1.7rem;
margin-bottom: 0px;
......@@ -605,7 +614,7 @@ i.panel-icon {
margin-left: 50px;
}
#diplomatic-lines .line-content:before {
#diplomatic-lines div:before {
user-select: none;
text-align: center;
counter-increment: line;
......
......@@ -548,29 +548,27 @@
inline-template>
<div class="col panel">
<div class="tools">
<i title="{% trans 'Transcription Panel' %}" class="panel-icon fas fa-language"></i>
<i title="{% trans 'Transcription Panel' %}" class="panel-icon fas fa-list-ol"></i>
<i id="save-notif" title="{% trans "There is content waiting to be saved (don't leave the page)" %}" class="notice fas fa-save hide"></i>
</div>
<div class="content-container {{ document.read_direction }}">
<diploline v-for="line in part.lines"
v-bind:line="line"
v-bind:ratio="ratio"
v-bind:key="'DL' + line.pk">
</diploline>
<div id="diplomatic-lines"
contenteditable="true"
@keydown="onKeyPress"
@keyup="constrainLineNumber"
@input="changed"
@focusin="startEdit"
@focusout="stopEdit"
@blur="save">
<diploline v-for="line in part.lines"
v-bind:line="line"
v-bind:ratio="ratio"
v-bind:key="'DL' + line.pk"
inline-template>
<div class="line-content"
v-if="line.currentTrans"
@mouseover="showOverlay"
@mouseleave="hideOverlay"
@paste="onPaste"
ref="content"
v-html="line.currentTrans.content">
</div>
</diploline>
@mousemove="showOverlay"
@mouseleave="hideOverlay"
@paste="onPaste">
</div>
</div>
</div>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment