Stability fixes
This commit is contained in:
parent
da2351d837
commit
f0e60a2637
@ -27,12 +27,9 @@ define([
|
|||||||
) {
|
) {
|
||||||
throw 'invalid';
|
throw 'invalid';
|
||||||
}
|
}
|
||||||
if(discussion.type == 'conflict') {
|
discussion.commentList && discussion.commentList.forEach(function(comment) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
discussion.commentList.forEach(function(comment) {
|
|
||||||
if(
|
if(
|
||||||
(!_.isString(comment.author)) ||
|
(!(!comment.author || _.isString(comment.author))) ||
|
||||||
(!_.isString(comment.content))
|
(!_.isString(comment.content))
|
||||||
) {
|
) {
|
||||||
throw 'invalid';
|
throw 'invalid';
|
||||||
@ -46,7 +43,7 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
Provider.prototype.serializeContent = function(content, discussionList) {
|
Provider.prototype.serializeContent = function(content, discussionList) {
|
||||||
if(discussionList.length > 2) { // It's a serialized JSON
|
if(discussionList.length > 2) { // Serialized JSON
|
||||||
return content + '<!--se_discussion_list:' + discussionList + '-->';
|
return content + '<!--se_discussion_list:' + discussionList + '-->';
|
||||||
}
|
}
|
||||||
return content;
|
return content;
|
||||||
@ -86,24 +83,29 @@ define([
|
|||||||
var addDiff = [1, ''];
|
var addDiff = [1, ''];
|
||||||
var distance = 20;
|
var distance = 20;
|
||||||
function pushDiff() {
|
function pushDiff() {
|
||||||
var separator = '///';
|
if(!removeDiff[1] && !addDiff[1]) {
|
||||||
if(removeDiff[1]) {
|
return;
|
||||||
removeDiff[1] = '///' + removeDiff[1] + separator;
|
|
||||||
separator = '';
|
|
||||||
result.push(removeDiff);
|
|
||||||
}
|
}
|
||||||
if(addDiff[1]) {
|
if(!removeDiff[1] || !addDiff[1]) {
|
||||||
addDiff[1] = separator + addDiff[1] + '///';
|
result.push([0, removeDiff[1] + addDiff[1]]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
removeDiff[1] = '///' + removeDiff[1] + '///';
|
||||||
|
addDiff[1] += '///';
|
||||||
|
result.push(removeDiff);
|
||||||
result.push(addDiff);
|
result.push(addDiff);
|
||||||
}
|
}
|
||||||
removeDiff = [-1, ''];
|
removeDiff = [-1, ''];
|
||||||
addDiff = [1, ''];
|
addDiff = [1, ''];
|
||||||
}
|
}
|
||||||
diffs.forEach(function(diff) {
|
diffs.forEach(function(diff, index) {
|
||||||
|
function firstOrLast() {
|
||||||
|
return index === 0 || index === diffs.length - 1;
|
||||||
|
}
|
||||||
var diffType = diff[0];
|
var diffType = diff[0];
|
||||||
var diffText = diff[1];
|
var diffText = diff[1];
|
||||||
if(diffType === 0) {
|
if(diffType === 0) {
|
||||||
if(diffText.length > distance) {
|
if(firstOrLast() || diffText.length > distance) {
|
||||||
if(removeDiff[1] || addDiff[1]) {
|
if(removeDiff[1] || addDiff[1]) {
|
||||||
var match = /\s/.exec(diffText);
|
var match = /\s/.exec(diffText);
|
||||||
if(match) {
|
if(match) {
|
||||||
@ -121,7 +123,7 @@ define([
|
|||||||
}
|
}
|
||||||
var suffix = diffText.substring(suffixOffset);
|
var suffix = diffText.substring(suffixOffset);
|
||||||
diffText = diffText.substring(0, suffixOffset);
|
diffText = diffText.substring(0, suffixOffset);
|
||||||
if(diffText.length > distance) {
|
if(firstOrLast() || diffText.length > distance) {
|
||||||
pushDiff();
|
pushDiff();
|
||||||
result.push([0, diffText]);
|
result.push([0, diffText]);
|
||||||
}
|
}
|
||||||
@ -154,51 +156,6 @@ define([
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveComments(oldTextContent, newTextContent, discussionList) {
|
|
||||||
if(!discussionList.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var changes = diffMatchPatch.diff_main(oldTextContent, newTextContent);
|
|
||||||
var changed = false;
|
|
||||||
var startOffset = 0;
|
|
||||||
changes.forEach(function(change) {
|
|
||||||
var changeType = change[0];
|
|
||||||
var changeText = change[1];
|
|
||||||
if(changeType === 0) {
|
|
||||||
startOffset += changeText.length;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var endOffset = startOffset;
|
|
||||||
var diffOffset = changeText.length;
|
|
||||||
if(changeType === -1) {
|
|
||||||
endOffset += diffOffset;
|
|
||||||
diffOffset = -diffOffset;
|
|
||||||
}
|
|
||||||
discussionList.forEach(function(discussion) {
|
|
||||||
// selectionEnd
|
|
||||||
if(discussion.selectionEnd >= endOffset) {
|
|
||||||
discussion.selectionEnd += diffOffset;
|
|
||||||
discussion.discussionIndex && (changed = true);
|
|
||||||
}
|
|
||||||
else if(discussion.selectionEnd > startOffset) {
|
|
||||||
discussion.selectionEnd = startOffset;
|
|
||||||
discussion.discussionIndex && (changed = true);
|
|
||||||
}
|
|
||||||
// selectionStart
|
|
||||||
if(discussion.selectionStart >= endOffset) {
|
|
||||||
discussion.selectionStart += diffOffset;
|
|
||||||
discussion.discussionIndex && (changed = true);
|
|
||||||
}
|
|
||||||
else if(discussion.selectionStart > startOffset) {
|
|
||||||
discussion.selectionStart = startOffset;
|
|
||||||
discussion.discussionIndex && (changed = true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
startOffset = endOffset;
|
|
||||||
});
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
var localContent = fileDesc.content;
|
var localContent = fileDesc.content;
|
||||||
var localTitle = fileDesc.title;
|
var localTitle = fileDesc.title;
|
||||||
var localDiscussionListJSON = fileDesc.discussionListJSON;
|
var localDiscussionListJSON = fileDesc.discussionListJSON;
|
||||||
@ -314,7 +271,7 @@ define([
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust local discussions offset
|
// Adjust local discussions offsets
|
||||||
var editorSelection;
|
var editorSelection;
|
||||||
if(contentChanged) {
|
if(contentChanged) {
|
||||||
var localDiscussionArray = [];
|
var localDiscussionArray = [];
|
||||||
@ -330,13 +287,13 @@ define([
|
|||||||
if(adjustLocalDiscussionList) {
|
if(adjustLocalDiscussionList) {
|
||||||
localDiscussionArray = localDiscussionArray.concat(_.values(localDiscussionList));
|
localDiscussionArray = localDiscussionArray.concat(_.values(localDiscussionList));
|
||||||
}
|
}
|
||||||
discussionListChanged |= moveComments(localContent, newContent, localDiscussionArray);
|
discussionListChanged |= editor.adjustCommentOffsets(localContent, newContent, localDiscussionArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust remote discussions offset
|
// Adjust remote discussions offsets
|
||||||
if(adjustRemoteDiscussionList) {
|
if(adjustRemoteDiscussionList) {
|
||||||
var remoteDiscussionArray = _.values(remoteDiscussionList);
|
var remoteDiscussionArray = _.values(remoteDiscussionList);
|
||||||
moveComments(remoteContent, newContent, remoteDiscussionArray);
|
editor.adjustCommentOffsets(remoteContent, newContent, remoteDiscussionArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch remote discussionList with local modifications
|
// Patch remote discussionList with local modifications
|
||||||
|
@ -359,7 +359,7 @@ define([
|
|||||||
var $titleContainer;
|
var $titleContainer;
|
||||||
var marginWidth = 18 * 2 + 25 + 25;
|
var marginWidth = 18 * 2 + 25 + 25;
|
||||||
var titleWidth = 18 + 348;
|
var titleWidth = 18 + 348;
|
||||||
var leftButtonsWidth = 18 * 4 + 80 + 160 + 160 + 80;
|
var leftButtonsWidth = 18 * 4 + 80 + 160 + 200 + 80;
|
||||||
var rightButtonsWidth = 18 + 80;
|
var rightButtonsWidth = 18 + 80;
|
||||||
var buttonsDropdownWidth = 40;
|
var buttonsDropdownWidth = 40;
|
||||||
function adjustWindow() {
|
function adjustWindow() {
|
||||||
@ -394,7 +394,8 @@ define([
|
|||||||
|
|
||||||
if(pagedownEditor !== undefined) {
|
if(pagedownEditor !== undefined) {
|
||||||
// If the editor is already created
|
// If the editor is already created
|
||||||
return editor.undoMgr.init();
|
editor.undoMgr.init();
|
||||||
|
return pagedownEditor.uiManager.setUndoRedoButtonStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the converter and the editor
|
// Create the converter and the editor
|
||||||
@ -450,10 +451,12 @@ define([
|
|||||||
$("#wmd-code-button").append($('<i class="icon-code">')).appendTo($btnGroupElt);
|
$("#wmd-code-button").append($('<i class="icon-code">')).appendTo($btnGroupElt);
|
||||||
$("#wmd-image-button").append($('<i class="icon-picture">')).appendTo($btnGroupElt);
|
$("#wmd-image-button").append($('<i class="icon-picture">')).appendTo($btnGroupElt);
|
||||||
$btnGroupElt = $('.wmd-button-group3');
|
$btnGroupElt = $('.wmd-button-group3');
|
||||||
|
var $openDiscussionElt = $btnGroupElt.find('.button-open-discussion');
|
||||||
$("#wmd-olist-button").append($('<i class="icon-list-numbered">')).appendTo($btnGroupElt);
|
$("#wmd-olist-button").append($('<i class="icon-list-numbered">')).appendTo($btnGroupElt);
|
||||||
$("#wmd-ulist-button").append($('<i class="icon-list-bullet">')).appendTo($btnGroupElt);
|
$("#wmd-ulist-button").append($('<i class="icon-list-bullet">')).appendTo($btnGroupElt);
|
||||||
$("#wmd-heading-button").append($('<i class="icon-text-height">')).appendTo($btnGroupElt);
|
$("#wmd-heading-button").append($('<i class="icon-text-height">')).appendTo($btnGroupElt);
|
||||||
$("#wmd-hr-button").append($('<i class="icon-ellipsis">')).appendTo($btnGroupElt);
|
$("#wmd-hr-button").append($('<i class="icon-ellipsis">')).appendTo($btnGroupElt);
|
||||||
|
$openDiscussionElt.appendTo($btnGroupElt);
|
||||||
$btnGroupElt = $('.wmd-button-group4');
|
$btnGroupElt = $('.wmd-button-group4');
|
||||||
$("#wmd-undo-button").append($('<i class="icon-reply">')).appendTo($btnGroupElt);
|
$("#wmd-undo-button").append($('<i class="icon-reply">')).appendTo($btnGroupElt);
|
||||||
$("#wmd-redo-button").append($('<i class="icon-forward">')).appendTo($btnGroupElt);
|
$("#wmd-redo-button").append($('<i class="icon-forward">')).appendTo($btnGroupElt);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/* jshint -W084, -W099 */
|
/* jshint -W084, -W099 */
|
||||||
|
// Credit to http://dabblet.com/
|
||||||
define([
|
define([
|
||||||
'jquery',
|
'jquery',
|
||||||
'underscore',
|
'underscore',
|
||||||
@ -8,15 +9,10 @@ define([
|
|||||||
'diff_match_patch_uncompressed',
|
'diff_match_patch_uncompressed',
|
||||||
'jsondiffpatch',
|
'jsondiffpatch',
|
||||||
'crel',
|
'crel',
|
||||||
|
'rangy',
|
||||||
'MutationObservers',
|
'MutationObservers',
|
||||||
'libs/prism-markdown'
|
'libs/prism-markdown'
|
||||||
], function ($, _, settings, eventMgr, Prism, diff_match_patch, jsondiffpatch, crel) {
|
], function ($, _, settings, eventMgr, Prism, diff_match_patch, jsondiffpatch, crel, rangy) {
|
||||||
|
|
||||||
function strSplice(str, i, remove, add) {
|
|
||||||
remove = +remove || 0;
|
|
||||||
add = add || '';
|
|
||||||
return str.slice(0, i) + add + str.slice(i + remove);
|
|
||||||
}
|
|
||||||
|
|
||||||
var editor = {};
|
var editor = {};
|
||||||
var scrollTop = 0;
|
var scrollTop = 0;
|
||||||
@ -110,6 +106,7 @@ define([
|
|||||||
});
|
});
|
||||||
|
|
||||||
function SelectionMgr() {
|
function SelectionMgr() {
|
||||||
|
var self = this;
|
||||||
this.selectionStart = 0;
|
this.selectionStart = 0;
|
||||||
this.selectionEnd = 0;
|
this.selectionEnd = 0;
|
||||||
this.cursorY = 0;
|
this.cursorY = 0;
|
||||||
@ -147,21 +144,26 @@ define([
|
|||||||
if(end === undefined) {
|
if(end === undefined) {
|
||||||
end = this.selectionEnd;
|
end = this.selectionEnd;
|
||||||
}
|
}
|
||||||
|
var maxOffset = inputElt.textContent.length - 1;
|
||||||
|
if(start > maxOffset) {
|
||||||
|
start = maxOffset;
|
||||||
|
range = undefined;
|
||||||
|
skipSelectionUpdate = false;
|
||||||
|
}
|
||||||
|
if(end > maxOffset) {
|
||||||
|
end = maxOffset;
|
||||||
|
range = undefined;
|
||||||
|
skipSelectionUpdate = false;
|
||||||
|
}
|
||||||
|
this.selectionStart = start;
|
||||||
|
this.selectionEnd = end;
|
||||||
var min = Math.min(start, end);
|
var min = Math.min(start, end);
|
||||||
var max = Math.max(start, end);
|
var max = Math.max(start, end);
|
||||||
range = range || this.createRange(min, max);
|
range = range || this.createRange(min, max);
|
||||||
if(start < end || !skipSelectionUpdate) {
|
|
||||||
this.selectionStart = min;
|
|
||||||
this.selectionEnd = max;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.selectionStart = max;
|
|
||||||
this.selectionEnd = min;
|
|
||||||
}
|
|
||||||
if(!skipSelectionUpdate) {
|
if(!skipSelectionUpdate) {
|
||||||
var selection = window.getSelection();
|
var selection = rangy.getSelection();
|
||||||
selection.removeAllRanges();
|
selection.removeAllRanges();
|
||||||
selection.addRange(range);
|
selection.addRange(range, start > end);
|
||||||
}
|
}
|
||||||
fileDesc.editorStart = this.selectionStart;
|
fileDesc.editorStart = this.selectionStart;
|
||||||
fileDesc.editorEnd = this.selectionEnd;
|
fileDesc.editorEnd = this.selectionEnd;
|
||||||
@ -174,47 +176,42 @@ define([
|
|||||||
}
|
}
|
||||||
return range;
|
return range;
|
||||||
};
|
};
|
||||||
this.saveSelectionState = function(skipSelectionUpdate) {
|
this.saveSelectionState = (function() {
|
||||||
if(fileChanged === false) {
|
function save() {
|
||||||
var selection = window.getSelection();
|
if(fileChanged === false) {
|
||||||
if(!skipSelectionUpdate && selection.rangeCount > 0) {
|
var selection = rangy.getSelection();
|
||||||
var range = selection.getRangeAt(0);
|
if(selection.rangeCount > 0) {
|
||||||
var element = range.startContainer;
|
var range = selection.getRangeAt(0);
|
||||||
|
var element = range.startContainer;
|
||||||
|
|
||||||
if ((inputElt.compareDocumentPosition(element) & 0x10)) {
|
if ((contentElt.compareDocumentPosition(element) & 0x10)) {
|
||||||
var container = element;
|
var container = element;
|
||||||
var offset = range.startOffset;
|
var offset = range.startOffset;
|
||||||
do {
|
do {
|
||||||
while (element = element.previousSibling) {
|
while (element = element.previousSibling) {
|
||||||
if (element.textContent) {
|
if (element.textContent) {
|
||||||
offset += element.textContent.length;
|
offset += element.textContent.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
element = container = container.parentNode;
|
||||||
|
} while (element && element != inputElt);
|
||||||
|
|
||||||
|
if(selection.isBackwards()) {
|
||||||
|
self.setSelectionStartEnd(offset + (range + '').length, offset, range, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.setSelectionStartEnd(offset, offset + (range + '').length, range, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
element = container = container.parentNode;
|
|
||||||
} while (element && element != inputElt);
|
|
||||||
|
|
||||||
// Determine if it's a backward selection
|
|
||||||
var isBackwardSelection = false;
|
|
||||||
if (!selection.isCollapsed) {
|
|
||||||
var tmpRange = document.createRange();
|
|
||||||
tmpRange.setStart(selection.anchorNode, selection.anchorOffset);
|
|
||||||
tmpRange.setEnd(selection.focusNode, selection.focusOffset);
|
|
||||||
isBackwardSelection = tmpRange.collapsed;
|
|
||||||
tmpRange.detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isBackwardSelection) {
|
|
||||||
this.setSelectionStartEnd(offset + (range + '').length, offset, range, true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.setSelectionStartEnd(offset, offset + (range + '').length, range, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
undoMgr.saveSelectionState();
|
||||||
}
|
}
|
||||||
undoMgr.saveSelectionState();
|
var debouncedSave = _.debounce(save, 0);
|
||||||
};
|
return function(debounced) {
|
||||||
|
debounced ? debouncedSave() : save();
|
||||||
|
};
|
||||||
|
})();
|
||||||
this.getCoordinates = function(inputOffset, container, offset) {
|
this.getCoordinates = function(inputOffset, container, offset) {
|
||||||
if(!container) {
|
if(!container) {
|
||||||
offset = this.findOffset(inputOffset);
|
offset = this.findOffset(inputOffset);
|
||||||
@ -236,7 +233,7 @@ define([
|
|||||||
container: container,
|
container: container,
|
||||||
offset: offset
|
offset: offset
|
||||||
};
|
};
|
||||||
if(selectedChar === undefined || selectedChar == '\n') {
|
if(inputOffset > 0 && (selectedChar === undefined || selectedChar == '\n')) {
|
||||||
if(startOffset.offset === 0) {
|
if(startOffset.offset === 0) {
|
||||||
startOffset = inputOffset - 1;
|
startOffset = inputOffset - 1;
|
||||||
}
|
}
|
||||||
@ -265,31 +262,41 @@ define([
|
|||||||
}
|
}
|
||||||
var selectionMgr = new SelectionMgr();
|
var selectionMgr = new SelectionMgr();
|
||||||
editor.selectionMgr = selectionMgr;
|
editor.selectionMgr = selectionMgr;
|
||||||
|
$(document).on('selectionchange', function() {
|
||||||
|
selectionMgr.saveSelectionState(true);
|
||||||
|
});
|
||||||
|
|
||||||
var adjustCursorPosition = _.debounce(function() {
|
var adjustCursorPosition = (function() {
|
||||||
if(inputElt === undefined) {
|
var adjust = _.debounce(function() {
|
||||||
return;
|
var adjust = inputElt.offsetHeight / 2;
|
||||||
}
|
if(adjust > 130) {
|
||||||
selectionMgr.saveSelectionState();
|
adjust = 130;
|
||||||
|
}
|
||||||
var adjust = inputElt.offsetHeight / 2;
|
var cursorMinY = inputElt.scrollTop + adjust;
|
||||||
if(adjust > 130) {
|
var cursorMaxY = inputElt.scrollTop + inputElt.offsetHeight - adjust;
|
||||||
adjust = 130;
|
if(selectionMgr.cursorY < cursorMinY) {
|
||||||
}
|
inputElt.scrollTop += selectionMgr.cursorY - cursorMinY;
|
||||||
var cursorMinY = inputElt.scrollTop + adjust;
|
}
|
||||||
var cursorMaxY = inputElt.scrollTop + inputElt.offsetHeight - adjust;
|
else if(selectionMgr.cursorY > cursorMaxY) {
|
||||||
if(selectionMgr.cursorY < cursorMinY) {
|
inputElt.scrollTop += selectionMgr.cursorY - cursorMaxY;
|
||||||
inputElt.scrollTop += selectionMgr.cursorY - cursorMinY;
|
}
|
||||||
}
|
}, 0);
|
||||||
else if(selectionMgr.cursorY > cursorMaxY) {
|
return function() {
|
||||||
inputElt.scrollTop += selectionMgr.cursorY - cursorMaxY;
|
if(inputElt === undefined) {
|
||||||
}
|
return;
|
||||||
}, 0);
|
}
|
||||||
|
selectionMgr.saveSelectionState(true);
|
||||||
|
adjust();
|
||||||
|
};
|
||||||
|
})();
|
||||||
eventMgr.addListener('onLayoutResize', adjustCursorPosition);
|
eventMgr.addListener('onLayoutResize', adjustCursorPosition);
|
||||||
|
|
||||||
var textContent;
|
var textContent;
|
||||||
function setValue(value) {
|
function setValue(value) {
|
||||||
var startOffset = diffMatchPatch.diff_commonPrefix(textContent, value);
|
var startOffset = diffMatchPatch.diff_commonPrefix(textContent, value);
|
||||||
|
if(startOffset === textContent.length) {
|
||||||
|
startOffset--;
|
||||||
|
}
|
||||||
var endOffset = Math.min(
|
var endOffset = Math.min(
|
||||||
diffMatchPatch.diff_commonSuffix(textContent, value),
|
diffMatchPatch.diff_commonSuffix(textContent, value),
|
||||||
textContent.length - startOffset,
|
textContent.length - startOffset,
|
||||||
@ -310,7 +317,7 @@ define([
|
|||||||
function getValue() {
|
function getValue() {
|
||||||
return textContent;
|
return textContent;
|
||||||
}
|
}
|
||||||
editor.setValueNoWatch = getValue;
|
editor.getValue = getValue;
|
||||||
|
|
||||||
function UndoMgr() {
|
function UndoMgr() {
|
||||||
var undoStack = [];
|
var undoStack = [];
|
||||||
@ -459,48 +466,10 @@ define([
|
|||||||
currentTextContent += '\n';
|
currentTextContent += '\n';
|
||||||
}
|
}
|
||||||
undoMgr.currentMode = undoMgr.currentMode || 'typing';
|
undoMgr.currentMode = undoMgr.currentMode || 'typing';
|
||||||
var changes = diffMatchPatch.diff_main(textContent, currentTextContent);
|
|
||||||
textContent = currentTextContent;
|
|
||||||
// Move comments according to changes
|
|
||||||
var updateDiscussionList = false;
|
|
||||||
var startOffset = 0;
|
|
||||||
var discussionList = _.values(fileDesc.discussionList);
|
var discussionList = _.values(fileDesc.discussionList);
|
||||||
fileDesc.newDiscussion && discussionList.push(fileDesc.newDiscussion);
|
fileDesc.newDiscussion && discussionList.push(fileDesc.newDiscussion);
|
||||||
changes.forEach(function(change) {
|
var updateDiscussionList = adjustCommentOffsets(textContent, currentTextContent, discussionList);
|
||||||
var changeType = change[0];
|
textContent = currentTextContent;
|
||||||
var changeText = change[1];
|
|
||||||
if(changeType === 0) {
|
|
||||||
startOffset += changeText.length;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var endOffset = startOffset;
|
|
||||||
var diffOffset = changeText.length;
|
|
||||||
if(changeType === -1) {
|
|
||||||
endOffset += diffOffset;
|
|
||||||
diffOffset = -diffOffset;
|
|
||||||
}
|
|
||||||
discussionList.forEach(function(discussion) {
|
|
||||||
// selectionEnd
|
|
||||||
if(discussion.selectionEnd >= endOffset) {
|
|
||||||
discussion.selectionEnd += diffOffset;
|
|
||||||
updateDiscussionList = true;
|
|
||||||
}
|
|
||||||
else if(discussion.selectionEnd > startOffset) {
|
|
||||||
discussion.selectionEnd = startOffset;
|
|
||||||
updateDiscussionList = true;
|
|
||||||
}
|
|
||||||
// selectionStart
|
|
||||||
if(discussion.selectionStart >= endOffset) {
|
|
||||||
discussion.selectionStart += diffOffset;
|
|
||||||
updateDiscussionList = true;
|
|
||||||
}
|
|
||||||
else if(discussion.selectionStart > startOffset) {
|
|
||||||
discussion.selectionStart = startOffset;
|
|
||||||
updateDiscussionList = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
startOffset = endOffset;
|
|
||||||
});
|
|
||||||
if(updateDiscussionList === true) {
|
if(updateDiscussionList === true) {
|
||||||
fileDesc.discussionList = fileDesc.discussionList; // Write discussionList in localStorage
|
fileDesc.discussionList = fileDesc.discussionList; // Write discussionList in localStorage
|
||||||
}
|
}
|
||||||
@ -525,12 +494,57 @@ define([
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function adjustCommentOffsets(oldTextContent, newTextContent, discussionList) {
|
||||||
|
if(!discussionList.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var changes = diffMatchPatch.diff_main(oldTextContent, newTextContent);
|
||||||
|
var changed = false;
|
||||||
|
var startOffset = 0;
|
||||||
|
changes.forEach(function(change) {
|
||||||
|
var changeType = change[0];
|
||||||
|
var changeText = change[1];
|
||||||
|
if(changeType === 0) {
|
||||||
|
startOffset += changeText.length;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var endOffset = startOffset;
|
||||||
|
var diffOffset = changeText.length;
|
||||||
|
if(changeType === -1) {
|
||||||
|
endOffset += diffOffset;
|
||||||
|
diffOffset = -diffOffset;
|
||||||
|
}
|
||||||
|
discussionList.forEach(function(discussion) {
|
||||||
|
// selectionEnd
|
||||||
|
if(discussion.selectionEnd > endOffset) {
|
||||||
|
discussion.selectionEnd += diffOffset;
|
||||||
|
discussion.discussionIndex && (changed = true);
|
||||||
|
}
|
||||||
|
else if(discussion.selectionEnd > startOffset) {
|
||||||
|
discussion.selectionEnd = startOffset;
|
||||||
|
discussion.discussionIndex && (changed = true);
|
||||||
|
}
|
||||||
|
// selectionStart
|
||||||
|
if(discussion.selectionStart >= endOffset) {
|
||||||
|
discussion.selectionStart += diffOffset;
|
||||||
|
discussion.discussionIndex && (changed = true);
|
||||||
|
}
|
||||||
|
else if(discussion.selectionStart > startOffset) {
|
||||||
|
discussion.selectionStart = startOffset;
|
||||||
|
discussion.discussionIndex && (changed = true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(changeType === 1) {
|
||||||
|
startOffset += changeText.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
editor.adjustCommentOffsets = adjustCommentOffsets;
|
||||||
|
|
||||||
editor.init = function(elt1, elt2) {
|
editor.init = function(elt1, elt2) {
|
||||||
inputElt = elt1;
|
inputElt = elt1;
|
||||||
$inputElt = $(inputElt);
|
$inputElt = $(inputElt);
|
||||||
editor.inputElt = inputElt;
|
|
||||||
editor.$inputElt = $inputElt;
|
|
||||||
|
|
||||||
previewElt = elt2;
|
previewElt = elt2;
|
||||||
|
|
||||||
contentElt = crel('div', {
|
contentElt = crel('div', {
|
||||||
@ -538,10 +552,8 @@ define([
|
|||||||
contenteditable: true
|
contenteditable: true
|
||||||
});
|
});
|
||||||
inputElt.appendChild(contentElt);
|
inputElt.appendChild(contentElt);
|
||||||
editor.contentElt = contentElt;
|
|
||||||
$contentElt = $(contentElt);
|
$contentElt = $(contentElt);
|
||||||
editor.$contentElt = $contentElt;
|
editor.$contentElt = $contentElt;
|
||||||
|
|
||||||
marginElt = crel('div', {
|
marginElt = crel('div', {
|
||||||
class: 'editor-margin'
|
class: 'editor-margin'
|
||||||
});
|
});
|
||||||
@ -568,12 +580,6 @@ define([
|
|||||||
selectionMgr.setSelectionStartEnd();
|
selectionMgr.setSelectionStartEnd();
|
||||||
inputElt.scrollTop = scrollTop;
|
inputElt.scrollTop = scrollTop;
|
||||||
};
|
};
|
||||||
$contentElt.focus(function() {
|
|
||||||
inputElt.focused = true;
|
|
||||||
});
|
|
||||||
$contentElt.blur(function() {
|
|
||||||
inputElt.focused = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.defineProperty(inputElt, 'value', {
|
Object.defineProperty(inputElt, 'value', {
|
||||||
get: function () {
|
get: function () {
|
||||||
@ -584,7 +590,7 @@ define([
|
|||||||
|
|
||||||
Object.defineProperty(inputElt, 'selectionStart', {
|
Object.defineProperty(inputElt, 'selectionStart', {
|
||||||
get: function () {
|
get: function () {
|
||||||
return selectionMgr.selectionStart;
|
return Math.min(selectionMgr.selectionStart, selectionMgr.selectionEnd);
|
||||||
},
|
},
|
||||||
set: function (value) {
|
set: function (value) {
|
||||||
selectionMgr.setSelectionStartEnd(value);
|
selectionMgr.setSelectionStartEnd(value);
|
||||||
@ -596,7 +602,7 @@ define([
|
|||||||
|
|
||||||
Object.defineProperty(inputElt, 'selectionEnd', {
|
Object.defineProperty(inputElt, 'selectionEnd', {
|
||||||
get: function () {
|
get: function () {
|
||||||
return selectionMgr.selectionEnd;
|
return Math.max(selectionMgr.selectionStart, selectionMgr.selectionEnd);
|
||||||
},
|
},
|
||||||
set: function (value) {
|
set: function (value) {
|
||||||
selectionMgr.setSelectionStartEnd(undefined, value);
|
selectionMgr.setSelectionStartEnd(undefined, value);
|
||||||
@ -642,9 +648,7 @@ define([
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on('mouseup', function() {
|
.on('mouseup', function() {
|
||||||
setTimeout(function() {
|
selectionMgr.saveSelectionState(true);
|
||||||
selectionMgr.saveSelectionState();
|
|
||||||
}, 0);
|
|
||||||
})
|
})
|
||||||
.on('paste', function () {
|
.on('paste', function () {
|
||||||
undoMgr.currentMode = 'paste';
|
undoMgr.currentMode = 'paste';
|
||||||
@ -658,52 +662,52 @@ define([
|
|||||||
var action = function (action, options) {
|
var action = function (action, options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
var text = inputElt.value,
|
var textContent = getValue();
|
||||||
ss = options.start || selectionMgr.selectionStart,
|
var selectionStart = options.start || selectionMgr.selectionStart;
|
||||||
se = options.end || selectionMgr.selectionEnd,
|
var selectionEnd = options.end || selectionMgr.selectionEnd;
|
||||||
state = {
|
var state = {
|
||||||
ss: ss,
|
selectionStart: selectionStart,
|
||||||
se: se,
|
selectionEnd: selectionEnd,
|
||||||
before: text.slice(0, ss),
|
before: textContent.slice(0, selectionStart),
|
||||||
after: text.slice(se),
|
after: textContent.slice(selectionEnd),
|
||||||
selection: text.slice(ss, se)
|
selection: textContent.slice(selectionStart, selectionEnd)
|
||||||
};
|
};
|
||||||
|
|
||||||
actions[action](state, options);
|
actions[action](state, options);
|
||||||
inputElt.value = state.before + state.selection + state.after;
|
setValue(state.before + state.selection + state.after);
|
||||||
selectionMgr.setSelectionStartEnd(state.ss, state.se);
|
selectionMgr.setSelectionStartEnd(state.selectionStart, state.selectionEnd);
|
||||||
$inputElt.trigger('input');
|
$inputElt.trigger('input');
|
||||||
};
|
};
|
||||||
|
|
||||||
var actions = {
|
var actions = {
|
||||||
indent: function (state, options) {
|
indent: function (state, options) {
|
||||||
|
function strSplice(str, i, remove, add) {
|
||||||
|
remove = +remove || 0;
|
||||||
|
add = add || '';
|
||||||
|
return str.slice(0, i) + add + str.slice(i + remove);
|
||||||
|
}
|
||||||
var lf = state.before.lastIndexOf('\n') + 1;
|
var lf = state.before.lastIndexOf('\n') + 1;
|
||||||
|
|
||||||
if (options.inverse) {
|
if (options.inverse) {
|
||||||
if (/\s/.test(state.before.charAt(lf))) {
|
if (/\s/.test(state.before.charAt(lf))) {
|
||||||
state.before = strSplice(state.before, lf, 1);
|
state.before = strSplice(state.before, lf, 1);
|
||||||
|
|
||||||
state.ss--;
|
state.selectionStart--;
|
||||||
state.se--;
|
state.selectionEnd--;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.selection = state.selection.replace(/^[ \t]/gm, '');
|
state.selection = state.selection.replace(/^[ \t]/gm, '');
|
||||||
} else if (state.selection) {
|
} else if (state.selection) {
|
||||||
state.before = strSplice(state.before, lf, 0, '\t');
|
state.before = strSplice(state.before, lf, 0, '\t');
|
||||||
state.selection = state.selection.replace(/\r?\n(?=[\s\S])/g, '\n\t');
|
state.selection = state.selection.replace(/\r?\n(?=[\s\S])/g, '\n\t');
|
||||||
|
state.selectionStart++;
|
||||||
state.ss++;
|
state.selectionEnd++;
|
||||||
state.se++;
|
|
||||||
} else {
|
} else {
|
||||||
state.before += '\t';
|
state.before += '\t';
|
||||||
|
state.selectionStart++;
|
||||||
state.ss++;
|
state.selectionEnd++;
|
||||||
state.se++;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.se = state.ss + state.selection.length;
|
state.selectionEnd = state.selectionStart + state.selection.length;
|
||||||
},
|
},
|
||||||
|
|
||||||
newline: function (state) {
|
newline: function (state) {
|
||||||
@ -711,8 +715,8 @@ define([
|
|||||||
if(clearNewline) {
|
if(clearNewline) {
|
||||||
state.before = state.before.substring(0, lf);
|
state.before = state.before.substring(0, lf);
|
||||||
state.selection = '';
|
state.selection = '';
|
||||||
state.ss = lf;
|
state.selectionStart = lf;
|
||||||
state.se = lf;
|
state.selectionEnd = lf;
|
||||||
clearNewline = false;
|
clearNewline = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -732,8 +736,8 @@ define([
|
|||||||
|
|
||||||
state.before += '\n' + indent;
|
state.before += '\n' + indent;
|
||||||
state.selection = '';
|
state.selection = '';
|
||||||
state.ss += indent.length + 1;
|
state.selectionStart += indent.length + 1;
|
||||||
state.se = state.ss;
|
state.selectionEnd = state.selectionStart;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -843,17 +847,18 @@ define([
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var entityMap = {
|
var escape = (function() {
|
||||||
"&": "&",
|
var entityMap = {
|
||||||
"<": "<",
|
"&": "&",
|
||||||
"\u00a0": ' ',
|
"<": "<",
|
||||||
};
|
"\u00a0": ' ',
|
||||||
|
};
|
||||||
function escape(str) {
|
return function(str) {
|
||||||
return str.replace(/[&<\u00a0]/g, function(s) {
|
return str.replace(/[&<\u00a0]/g, function(s) {
|
||||||
return entityMap[s];
|
return entityMap[s];
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
function highlight(section) {
|
function highlight(section) {
|
||||||
var text = escape(section.text);
|
var text = escape(section.text);
|
||||||
|
@ -10,7 +10,7 @@ define([
|
|||||||
"bootstrap"
|
"bootstrap"
|
||||||
], function($, _, utils, storage, crel, rangy, Extension, commentsPopoverContentHTML) {
|
], function($, _, utils, storage, crel, rangy, Extension, commentsPopoverContentHTML) {
|
||||||
|
|
||||||
var comments = new Extension("comments", 'Comments');
|
var comments = new Extension("comments", 'Comments', false, true);
|
||||||
|
|
||||||
var commentTmpl = [
|
var commentTmpl = [
|
||||||
'<div class="comment-block<%= reply ? \' reply\' : \'\' %>">',
|
'<div class="comment-block<%= reply ? \' reply\' : \'\' %>">',
|
||||||
@ -40,14 +40,15 @@ define([
|
|||||||
var offsetMap = {};
|
var offsetMap = {};
|
||||||
function setCommentEltCoordinates(commentElt, y) {
|
function setCommentEltCoordinates(commentElt, y) {
|
||||||
var lineIndex = Math.round(y / 10);
|
var lineIndex = Math.round(y / 10);
|
||||||
var yOffset = -10;
|
var yOffset = -9;
|
||||||
if(commentElt.className.indexOf(' icon-split') !== -1) {
|
if(commentElt.className.indexOf(' icon-split') !== -1) {
|
||||||
yOffset = -12;
|
yOffset = -12;
|
||||||
}
|
}
|
||||||
var top = (y + yOffset) + 'px';
|
var top = y + yOffset;
|
||||||
var right = ((offsetMap[lineIndex] || 0) * 25 + 10) + 'px';
|
var right = (offsetMap[lineIndex] || 0) * 25 + 10;
|
||||||
commentElt.style.top = top;
|
commentElt.orderedIndex = lineIndex * 10000 + right;
|
||||||
commentElt.style.right = right;
|
commentElt.style.top = top + 'px';
|
||||||
|
commentElt.style.right = right + 'px';
|
||||||
return lineIndex;
|
return lineIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,17 +88,27 @@ define([
|
|||||||
}
|
}
|
||||||
popoverElt.style.left = left + 'px';
|
popoverElt.style.left = left + 'px';
|
||||||
popoverElt.querySelector('.arrow').style.left = (marginElt.offsetWidth - parseInt(commentElt.style.right) - commentElt.offsetWidth / 2 - left) + 'px';
|
popoverElt.querySelector('.arrow').style.left = (marginElt.offsetWidth - parseInt(commentElt.style.right) - commentElt.offsetWidth / 2 - left) + 'px';
|
||||||
|
var $contentInputElt = currentContext.$contentInputElt;
|
||||||
|
var popoverTopOffset = document.body.offsetHeight - $contentInputElt.offset().top - $contentInputElt.outerHeight();
|
||||||
|
if(popoverTopOffset < 0) {
|
||||||
|
popoverElt.style.top = (parseInt(popoverElt.style.top) + popoverTopOffset) + 'px';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cssApplier;
|
var cssApplier;
|
||||||
var currentFileDesc;
|
var currentFileDesc;
|
||||||
var refreshTimeoutId;
|
var refreshTimeoutId;
|
||||||
var commentEltMap = {};
|
var commentEltMap = {};
|
||||||
|
var sortedCommentEltList = [];
|
||||||
|
var someReplies = false;
|
||||||
|
var $openDiscussionElt;
|
||||||
|
var $openDiscussionIconElt;
|
||||||
var refreshDiscussions = _.debounce(function() {
|
var refreshDiscussions = _.debounce(function() {
|
||||||
if(currentFileDesc === undefined) {
|
if(currentFileDesc === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
someReplies = false;
|
||||||
|
sortedCommentEltList = [];
|
||||||
var author = storage['author.name'];
|
var author = storage['author.name'];
|
||||||
offsetMap = {};
|
offsetMap = {};
|
||||||
var discussionList = _.values(currentFileDesc.discussionList);
|
var discussionList = _.values(currentFileDesc.discussionList);
|
||||||
@ -116,24 +127,32 @@ define([
|
|||||||
inputElt.scrollTop += parseInt(newCommentElt.style.top) - inputElt.scrollTop - inputElt.offsetHeight * 3 / 4;
|
inputElt.scrollTop += parseInt(newCommentElt.style.top) - inputElt.scrollTop - inputElt.offsetHeight * 3 / 4;
|
||||||
movePopover(newCommentElt);
|
movePopover(newCommentElt);
|
||||||
}
|
}
|
||||||
|
sortedCommentEltList = _.sortBy(commentEltMap, function(commentElt) {
|
||||||
|
return commentElt.orderedIndex;
|
||||||
|
});
|
||||||
|
$openDiscussionElt.toggleClass('some', sortedCommentEltList.length !== 0);
|
||||||
|
$openDiscussionElt.toggleClass('replied', someReplies);
|
||||||
|
$openDiscussionIconElt.toggleClass('icon-chat', sortedCommentEltList.length !== 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var discussion = discussionList.pop();
|
var discussion = discussionList.pop();
|
||||||
var commentElt = crel('a', {
|
var commentElt = commentEltMap[discussion.discussionIndex];
|
||||||
class: 'discussion'
|
if(!commentElt) {
|
||||||
});
|
commentElt = crel('a');
|
||||||
var isReplied = !discussion.commentList || _.last(discussion.commentList).author != author;
|
|
||||||
commentElt.className += ' icon-quote-left' + (isReplied ? ' replied' : ' added');
|
|
||||||
if(discussion.type == 'conflict') {
|
|
||||||
commentElt.className += ' icon-split';
|
|
||||||
}
|
}
|
||||||
|
var className = 'discussion';
|
||||||
|
var isReplied = !discussion.commentList || _.last(discussion.commentList).author != author;
|
||||||
|
isReplied && (someReplies = true);
|
||||||
|
className += ' icon-quote-left' + (isReplied ? ' replied' : ' added');
|
||||||
|
if(discussion.type == 'conflict') {
|
||||||
|
className += ' icon-split';
|
||||||
|
}
|
||||||
|
commentElt.className = className;
|
||||||
commentElt.discussionIndex = discussion.discussionIndex;
|
commentElt.discussionIndex = discussion.discussionIndex;
|
||||||
var coordinates = editor.selectionMgr.getCoordinates(discussion.selectionEnd);
|
var coordinates = editor.selectionMgr.getCoordinates(discussion.selectionEnd);
|
||||||
var lineIndex = setCommentEltCoordinates(commentElt, coordinates.y);
|
var lineIndex = setCommentEltCoordinates(commentElt, coordinates.y);
|
||||||
offsetMap[lineIndex] = (offsetMap[lineIndex] || 0) + 1;
|
offsetMap[lineIndex] = (offsetMap[lineIndex] || 0) + 1;
|
||||||
|
|
||||||
var oldCommentElt = commentEltMap[discussion.discussionIndex];
|
|
||||||
oldCommentElt && marginElt.removeChild(oldCommentElt);
|
|
||||||
marginElt.appendChild(commentElt);
|
marginElt.appendChild(commentElt);
|
||||||
commentEltMap[discussion.discussionIndex] = commentElt;
|
commentEltMap[discussion.discussionIndex] = commentElt;
|
||||||
|
|
||||||
@ -225,7 +244,7 @@ define([
|
|||||||
if(discussion.type == 'conflict') {
|
if(discussion.type == 'conflict') {
|
||||||
result.unshift(_.template(commentTmpl, {
|
result.unshift(_.template(commentTmpl, {
|
||||||
author: 'StackEdit',
|
author: 'StackEdit',
|
||||||
content: 'Multiple users have made conflicting modifications that you have to review.',
|
content: 'Multiple users have made conflicting modifications.',
|
||||||
reply: true
|
reply: true
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -276,6 +295,9 @@ define([
|
|||||||
}).on('show.bs.popover', '#wmd-input > .editor-margin', function(evt) {
|
}).on('show.bs.popover', '#wmd-input > .editor-margin', function(evt) {
|
||||||
closeCurrentPopover();
|
closeCurrentPopover();
|
||||||
var context = new Context(evt.target, currentFileDesc);
|
var context = new Context(evt.target, currentFileDesc);
|
||||||
|
if(evt.target !== newCommentElt) {
|
||||||
|
$newCommentElt.addClass('hide');
|
||||||
|
}
|
||||||
currentContext = context;
|
currentContext = context;
|
||||||
inputElt.scrollTop += parseInt(evt.target.style.top) - inputElt.scrollTop - inputElt.offsetHeight * 3 / 4;
|
inputElt.scrollTop += parseInt(evt.target.style.top) - inputElt.scrollTop - inputElt.offsetHeight * 3 / 4;
|
||||||
|
|
||||||
@ -295,15 +317,15 @@ define([
|
|||||||
var match = /\S+/.exec(after);
|
var match = /\S+/.exec(after);
|
||||||
if(match) {
|
if(match) {
|
||||||
selectionStart += match.index;
|
selectionStart += match.index;
|
||||||
if(match.index === 0) {
|
selectionEnd = selectionStart + match[0].length;
|
||||||
while(selectionStart && /\S/.test(textContent[selectionStart - 1])) {
|
}
|
||||||
selectionStart--;
|
if(!match || match.index === 0) {
|
||||||
}
|
while(selectionStart && /\S/.test(textContent[selectionStart - 1])) {
|
||||||
|
selectionStart--;
|
||||||
}
|
}
|
||||||
selectionEnd += match.index + match[0].length;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.selectionRange = editor.selectionMgr.createRange(selectionStart, selectionEnd);
|
context.selectionRange = editor.selectionMgr.setSelectionStartEnd(selectionStart, selectionEnd, undefined, true);
|
||||||
currentFileDesc.newDiscussion = {
|
currentFileDesc.newDiscussion = {
|
||||||
selectionStart: selectionStart,
|
selectionStart: selectionStart,
|
||||||
selectionEnd: selectionEnd,
|
selectionEnd: selectionEnd,
|
||||||
@ -311,14 +333,14 @@ define([
|
|||||||
};
|
};
|
||||||
}).on('shown.bs.popover', '#wmd-input > .editor-margin', function(evt) {
|
}).on('shown.bs.popover', '#wmd-input > .editor-margin', function(evt) {
|
||||||
var context = currentContext;
|
var context = currentContext;
|
||||||
movePopover(context.commentElt);
|
|
||||||
var popoverElt = context.getPopoverElt();
|
var popoverElt = context.getPopoverElt();
|
||||||
|
|
||||||
// Scroll to the bottom of the discussion
|
|
||||||
popoverElt.querySelector('.popover-content').scrollTop = 9999999;
|
|
||||||
|
|
||||||
context.$authorInputElt = $(popoverElt.querySelector('.input-comment-author')).val(storage['author.name']);
|
context.$authorInputElt = $(popoverElt.querySelector('.input-comment-author')).val(storage['author.name']);
|
||||||
context.$contentInputElt = $(popoverElt.querySelector('.input-comment-content'));
|
context.$contentInputElt = $(popoverElt.querySelector('.input-comment-content'));
|
||||||
|
movePopover(context.commentElt);
|
||||||
|
|
||||||
|
// Scroll to the bottom of the discussion
|
||||||
|
popoverElt.querySelector('.scrollport').scrollTop = 9999999;
|
||||||
|
|
||||||
var $addButton = $(popoverElt.querySelector('.action-add-comment'));
|
var $addButton = $(popoverElt.querySelector('.action-add-comment'));
|
||||||
$().add(context.$contentInputElt).add(context.$authorInputElt).keydown(function(evt) {
|
$().add(context.$contentInputElt).add(context.$authorInputElt).keydown(function(evt) {
|
||||||
// Enter key
|
// Enter key
|
||||||
@ -377,12 +399,12 @@ define([
|
|||||||
$removeButton.click(function() {
|
$removeButton.click(function() {
|
||||||
$(popoverElt.querySelector('.new-comment-block')).addClass('hide');
|
$(popoverElt.querySelector('.new-comment-block')).addClass('hide');
|
||||||
$(popoverElt.querySelector('.remove-discussion-confirm')).removeClass('hide');
|
$(popoverElt.querySelector('.remove-discussion-confirm')).removeClass('hide');
|
||||||
popoverElt.querySelector('.popover-content').scrollTop = 9999999;
|
popoverElt.querySelector('.scrollport').scrollTop = 9999999;
|
||||||
});
|
});
|
||||||
$removeCancelButton.click(function() {
|
$removeCancelButton.click(function() {
|
||||||
$(popoverElt.querySelector('.new-comment-block')).removeClass('hide');
|
$(popoverElt.querySelector('.new-comment-block')).removeClass('hide');
|
||||||
$(popoverElt.querySelector('.remove-discussion-confirm')).addClass('hide');
|
$(popoverElt.querySelector('.remove-discussion-confirm')).addClass('hide');
|
||||||
popoverElt.querySelector('.popover-content').scrollTop = 9999999;
|
popoverElt.querySelector('.scrollport').scrollTop = 9999999;
|
||||||
context.$contentInputElt.focus();
|
context.$contentInputElt.focus();
|
||||||
});
|
});
|
||||||
$removeConfirmButton.click(function() {
|
$removeConfirmButton.click(function() {
|
||||||
@ -421,6 +443,7 @@ define([
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentContext.$commentElt.removeClass('active');
|
currentContext.$commentElt.removeClass('active');
|
||||||
|
$newCommentElt.removeClass('hide');
|
||||||
|
|
||||||
// Save content and author for later
|
// Save content and author for later
|
||||||
previousContent = currentContext.$contentInputElt.val();
|
previousContent = currentContext.$contentInputElt.val();
|
||||||
@ -431,6 +454,29 @@ define([
|
|||||||
currentContext = undefined;
|
currentContext = undefined;
|
||||||
delete currentFileDesc.newDiscussion;
|
delete currentFileDesc.newDiscussion;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var $newCommentElt = $(newCommentElt);
|
||||||
|
$openDiscussionElt = $('.button-open-discussion').click(function(evt) {
|
||||||
|
var $commentElt = $newCommentElt;
|
||||||
|
if(sortedCommentEltList.length) {
|
||||||
|
if(!currentContext) {
|
||||||
|
$commentElt = $(_.first(sortedCommentEltList));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var curentIndex = -1;
|
||||||
|
sortedCommentEltList.some(function(elt, index) {
|
||||||
|
if(elt === currentContext.commentElt) {
|
||||||
|
curentIndex = index;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$commentElt = $(sortedCommentEltList[(curentIndex + 1) % sortedCommentEltList.length]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$commentElt.click();
|
||||||
|
evt.stopPropagation();
|
||||||
|
});
|
||||||
|
$openDiscussionIconElt = $openDiscussionElt.find('i');
|
||||||
};
|
};
|
||||||
|
|
||||||
return comments;
|
return comments;
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
<li class="wmd-button-group2 btn-group"></li>
|
<li class="wmd-button-group2 btn-group"></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="nav left-buttons">
|
<ul class="nav left-buttons">
|
||||||
<li class="wmd-button-group3 btn-group"></li>
|
<li class="wmd-button-group3 btn-group">
|
||||||
|
<a class="btn btn-success button-open-discussion"><i class="icon-comment-alt"></i></a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="nav left-buttons">
|
<ul class="nav left-buttons">
|
||||||
<li class="wmd-button-group4 btn-group"></li>
|
<li class="wmd-button-group4 btn-group"></li>
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
<div class="discussion-comment-list"><%= commentList %></div>
|
<div class="scrollport">
|
||||||
<div class="new-comment-block">
|
<div class="discussion-comment-list"><%= commentList %></div>
|
||||||
<div class="form-group">
|
<div class="new-comment-block">
|
||||||
<i class="icon-comment"></i> <input class="form-control input-comment-author" placeholder="Your name"></input>
|
<div class="form-group">
|
||||||
<textarea class="form-control input-comment-content"></textarea>
|
<i class="icon-comment"></i> <input class="form-control input-comment-author" placeholder="Your name"></input>
|
||||||
|
<textarea class="form-control input-comment-content"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group text-right">
|
||||||
|
<button class="btn btn-primary action-add-comment">Add</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group text-right">
|
<div class="remove-discussion-confirm hide">
|
||||||
<button class="btn btn-primary action-add-comment">Add</button>
|
<blockquote>Remove this discussion, really?</blockquote>
|
||||||
</div>
|
<div class="form-group text-right">
|
||||||
</div>
|
<button class="btn btn-default action-remove-discussion-cancel">No</button>
|
||||||
<div class="remove-discussion-confirm hide">
|
<button class="btn btn-primary action-remove-discussion-confirm">Yes</button>
|
||||||
<br/>
|
</div>
|
||||||
<blockquote>Remove this discussion, really?</blockquote>
|
|
||||||
<div class="form-group text-right">
|
|
||||||
<button class="btn btn-default action-remove-discussion-cancel">No</button>
|
|
||||||
<button class="btn btn-primary action-remove-discussion-confirm">Yes</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<hr/>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
@primary-border-color: fade(@primary, 10%);
|
@primary-border-color: fade(@primary, 10%);
|
||||||
|
|
||||||
// Preview and menus
|
// Preview and menus
|
||||||
@secondary-bg: lighten(@secondary-desaturated, 45%);
|
@secondary-bg: lighten(@secondary-desaturated, 48%);
|
||||||
@secondary-bg-light: lighten(@secondary-desaturated, 47%);
|
@secondary-bg-light: lighten(@secondary-desaturated, 47%);
|
||||||
@secondary-bg-lighter: #fff;
|
@secondary-bg-lighter: #fff;
|
||||||
@secondary-color: lighten(@primary-desaturated, 10%);
|
@secondary-color: lighten(@primary-desaturated, 10%);
|
||||||
@ -111,7 +111,7 @@
|
|||||||
@btn-info-color: fade(@secondary-desaturated, 35%);
|
@btn-info-color: fade(@secondary-desaturated, 35%);
|
||||||
@btn-info-bg: @transparent;
|
@btn-info-bg: @transparent;
|
||||||
@btn-info-border: @transparent;
|
@btn-info-border: @transparent;
|
||||||
@btn-info-hover-bg: @secondary-bg;
|
@btn-info-hover-bg: lighten(@secondary-desaturated, 45%);
|
||||||
@gray-lighter: @body-bg;
|
@gray-lighter: @body-bg;
|
||||||
@modal-header-border-color: @secondary-border-color-light;
|
@modal-header-border-color: @secondary-border-color-light;
|
||||||
@modal-content-bg: @secondary-bg-lighter;
|
@modal-content-bg: @secondary-bg-lighter;
|
||||||
@ -127,8 +127,14 @@
|
|||||||
@popover-arrow-outer-color: @secondary-border-color;
|
@popover-arrow-outer-color: @secondary-border-color;
|
||||||
@popover-title-bg: @transparent;
|
@popover-title-bg: @transparent;
|
||||||
@alert-border-radius: 0;
|
@alert-border-radius: 0;
|
||||||
@label-warning-bg: spin(darken(@logo-yellow, 4%), -4);
|
@label-warning-bg: spin(darken(@logo-yellow, 4%), -6);
|
||||||
@label-danger-bg: spin(darken(@logo-orange, 4%), -4);
|
@label-danger-bg: spin(darken(@logo-orange, 4%), -4);
|
||||||
|
@state-warning-text: spin(darken(@logo-yellow, 18%), -6);
|
||||||
|
@state-warning-bg: fade(spin(@logo-yellow, -6), 12%);
|
||||||
|
@state-warning-border: fade(spin(@logo-yellow, -6), 24%);
|
||||||
|
@state-danger-text: spin(darken(@logo-orange, 20%), -4);
|
||||||
|
@state-danger-bg: fade(spin(@logo-orange, -4), 10%);
|
||||||
|
@state-danger-border: fade(spin(@logo-orange, -4), 20%);
|
||||||
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@ -443,6 +449,25 @@ a {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-open-discussion {
|
||||||
|
&.some {
|
||||||
|
color: lighten(@alert-warning-text, 10%);
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
.alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);
|
||||||
|
background-color: @alert-warning-bg !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.replied {
|
||||||
|
color: lighten(@alert-danger-text, 10%);
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
.alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);
|
||||||
|
background-color: @alert-danger-bg !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.file-title-navbar {
|
.file-title-navbar {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
@ -1058,12 +1083,13 @@ a {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
.discussion {
|
.discussion {
|
||||||
font-size: 18px;
|
font-size: 17px;
|
||||||
&:before {
|
&:before {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
&.new {
|
&.new {
|
||||||
color: fade(@tertiary-color, 10%);
|
display: none;
|
||||||
|
color: fade(@tertiary-color, 20%);
|
||||||
&:hover, &.active, &.active:hover {
|
&:hover, &.active, &.active:hover {
|
||||||
color: fade(@tertiary-color, 35%) !important;
|
color: fade(@tertiary-color, 35%) !important;
|
||||||
}
|
}
|
||||||
@ -1091,12 +1117,11 @@ a {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.has-selection > .editor-margin .discussion.new {
|
&.has-selection > .editor-margin .discussion.new {
|
||||||
color: fade(@tertiary-color, 25%);
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-highlight {
|
.comment-highlight {
|
||||||
background-color: fade(@label-warning-bg, 30%);
|
background-color: fade(@label-warning-bg, 30%);
|
||||||
//border-radius: @border-radius-base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.conflict {
|
.conflict {
|
||||||
@ -1150,13 +1175,6 @@ a {
|
|||||||
padding: 0.2em;
|
padding: 0.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
.pre {
|
|
||||||
line-height: 1.8;
|
|
||||||
margin-left: 1.8em
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
.link, .linkref {
|
.link, .linkref {
|
||||||
.md-underlined-text {
|
.md-underlined-text {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
@ -1438,16 +1456,23 @@ input[type="file"] {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.popover-content {
|
.popover-content {
|
||||||
padding: 10px 20px 0;
|
margin: 0;
|
||||||
overflow: auto;
|
padding: 0;
|
||||||
max-height: 230px;
|
.scrollport {
|
||||||
margin: 0 -20px;
|
overflow: auto;
|
||||||
|
max-height: 230px;
|
||||||
|
padding: 10px 20px 0;
|
||||||
|
margin: 0 -20px;
|
||||||
|
}
|
||||||
.btn {
|
.btn {
|
||||||
padding: 6px 11px;
|
padding: 6px 11px;
|
||||||
}
|
}
|
||||||
.comment-block {
|
.comment-block {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
.form-group, blockquote {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
.comment-author {
|
.comment-author {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: @input-color;
|
color: @input-color;
|
||||||
@ -1466,9 +1491,12 @@ input[type="file"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
padding: 0 0 5px;
|
padding: 0 0 5px;
|
||||||
width: 150px;
|
width: 140px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
hr {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.comments-popover & {
|
.comments-popover & {
|
||||||
|
Loading…
Reference in New Issue
Block a user