Add support of showing authorship in editor and adjust related styles

This commit is contained in:
Wu Cheng-Han 2016-07-30 11:28:24 +08:00
parent d5549c6a84
commit a14e7953b5
4 changed files with 218 additions and 3 deletions

View file

@ -65,7 +65,9 @@ function emitCheck(note) {
var out = {
updatetime: note.updatetime,
lastchangeuser: note.lastchangeuser,
lastchangeuserprofile: note.lastchangeuserprofile
lastchangeuserprofile: note.lastchangeuserprofile,
authors: note.authors,
authorship: note.authorship
};
realtime.io.to(note.id).emit('check', out);
}
@ -314,6 +316,8 @@ function emitRefresh(socket) {
ownerprofile: note.ownerprofile,
lastchangeuser: note.lastchangeuser,
lastchangeuserprofile: note.lastchangeuserprofile,
authors: note.authors,
authorship: note.authorship,
permission: note.permission,
createtime: note.createtime,
updatetime: note.updatetime

View file

@ -49,6 +49,9 @@ body {
min-width: 1.5em;
text-align: right;
}
.CodeMirror-gutter.authorship-gutters {
width: 8px;
}
.CodeMirror-matchingtag {
background: rgba(255, 255, 255, .1);
line-height: 1em;

View file

@ -287,7 +287,7 @@ var editor = CodeMirror.fromTextArea(textit, {
},
autoCloseTags: true,
foldGutter: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
gutters: ["CodeMirror-linenumbers", "authorship-gutters", "CodeMirror-foldgutter"],
extraKeys: defaultExtraKeys,
flattenSpans: true,
addModeClass: true,
@ -2127,6 +2127,9 @@ socket.on('version', function (data) {
}
}
});
var authors = [];
var authorship = [];
var authorshipMarks = {};
function updateLastInfo(data) {
//console.log(data);
if (data.hasOwnProperty('createtime') && createtime !== data.createtime) {
@ -2142,7 +2145,212 @@ function updateLastInfo(data) {
lastchangeuserprofile = data.lastchangeuserprofile;
updateLastChangeUser();
}
if (data.hasOwnProperty('authors') && authors !== data.authors) {
authors = data.authors;
}
if (data.hasOwnProperty('authorship') && authorship !== data.authorship) {
authorship = data.authorship;
updateAuthorship();
}
}
var updateAuthorship = _.throttle(updateAuthorshipInner, 50);
function initMark() {
return {
gutter: {
userid: null,
timestamp: null
},
textmarkers: []
};
}
function initMarkAndCheckGutter(mark, author, timestamp) {
if (!mark) mark = initMark();
if (!mark.gutter.userid || mark.gutter.timestamp > timestamp) {
mark.gutter.userid = author.userid;
mark.gutter.timestamp = timestamp;
}
return mark;
}
var gutterStylePrefix = "border-left: 3px solid ";
var gutterStylePostfix = "; height: " + defaultTextHeight + "px; margin-left: 3px;";
var textMarkderStylePrefix = "background-image: linear-gradient(to top, ";
var textMarkderStylePostfix = " 1px, transparent 1px);";
var addStyleRule = (function () {
var added = {};
var styleElement = document.createElement('style');
document.documentElement.getElementsByTagName('head')[0].appendChild(styleElement);
var styleSheet = styleElement.sheet;
return function (css) {
if (added[css]) {
return;
}
added[css] = true;
styleSheet.insertRule(css, (styleSheet.cssRules || styleSheet.rules).length);
};
}());
function updateAuthorshipInner() {
// ignore when ot not synced yet
if (Object.keys(cmClient.state).length > 0) return;
var authorMarks = {};
for (var i = 0; i < authorship.length; i++) {
var atom = authorship[i];
var author = authors[atom[0]];
if (author) {
var prePos = editor.posFromIndex(atom[1]);
var preLine = editor.getLine(prePos.line);
var postPos = editor.posFromIndex(atom[2]);
var postLine = editor.getLine(postPos.line);
if (prePos.ch == 0 && postPos.ch == postLine.length) {
for (var j = prePos.line; j <= postPos.line; j++) {
if (editor.getLine(j)) {
authorMarks[j] = initMarkAndCheckGutter(authorMarks[j], author, atom[3]);
}
}
} else if (postPos.line - prePos.line >= 1) {
var startLine = prePos.line;
var endLine = postPos.line;
if (prePos.ch == preLine.length) {
startLine++;
} else if (prePos.ch != 0) {
var mark = initMarkAndCheckGutter(authorMarks[prePos.line], author, atom[3]);
var _postPos = {
line: prePos.line,
ch: preLine.length
};
if (JSON.stringify(prePos) != JSON.stringify(_postPos)) {
mark.textmarkers.push({
userid: author.userid,
pos: [prePos, _postPos]
});
startLine++;
}
authorMarks[prePos.line] = mark;
}
if (postPos.ch == 0) {
endLine--;
} else if (postPos.ch != postLine.length) {
var mark = initMarkAndCheckGutter(authorMarks[postPos.line], author, atom[3]);
var _prePos = {
line: postPos.line,
ch: 0
};
if (JSON.stringify(_prePos) != JSON.stringify(postPos)) {
mark.textmarkers.push({
userid: author.userid,
pos: [_prePos, postPos]
});
endLine--;
}
authorMarks[postPos.line] = mark;
}
for (var j = startLine; j <= endLine; j++) {
if (editor.getLine(j)) {
authorMarks[j] = initMarkAndCheckGutter(authorMarks[j], author, atom[3]);
}
}
} else {
var mark = initMarkAndCheckGutter(authorMarks[prePos.line], author, atom[3]);
if (JSON.stringify(prePos) != JSON.stringify(postPos)) {
mark.textmarkers.push({
userid: author.userid,
pos: [prePos, postPos]
});
}
authorMarks[prePos.line] = mark;
}
}
}
var addTextMarkers = [];
editor.eachLine(function (line) {
var lineNumber = editor.getLineNumber(line);
var currMark = authorMarks[lineNumber];
var author = currMark ? authors[currMark.gutter.userid] : null;
if (currMark && author) {
var className = 'authorship-gutter-' + author.color.substr(1);
var gutters = editor.getLineHandle(lineNumber).gutterMarkers;
if (!gutters || !gutters['authorship-gutters'] ||
!gutters['authorship-gutters'].className ||
!gutters['authorship-gutters'].className.indexOf(className) < 0) {
var styleString = gutterStylePrefix + author.color + gutterStylePostfix;
var rule = "." + className + "{" + styleString + "}";
addStyleRule(rule);
var gutter = $('<div>', {
class: 'authorship-gutter ' + className,
title: author.name
});
editor.setGutterMarker(lineNumber, "authorship-gutters", gutter[0]);
}
} else {
editor.setGutterMarker(lineNumber, "authorship-gutters", null);
}
if (currMark && currMark.textmarkers.length > 0) {
for (var i = 0; i < currMark.textmarkers.length; i++) {
var textMarker = currMark.textmarkers[i];
if (textMarker.userid != currMark.gutter.userid) {
addTextMarkers.push(textMarker);
}
}
}
});
var allTextMarks = editor.getAllMarks();
for (var i = 0; i < allTextMarks.length; i++) {
var _textMarker = allTextMarks[i];
var pos = _textMarker.find();
var found = false;
for (var j = 0; j < addTextMarkers.length; j++) {
var textMarker = addTextMarkers[j];
var author = authors[textMarker.userid];
var className = 'authorship-inline-' + author.color.substr(1);
var obj = {
from: textMarker.pos[0],
to: textMarker.pos[1]
};
if (JSON.stringify(pos) == JSON.stringify(obj) && _textMarker.className &&
_textMarker.className.indexOf(className) > -1) {
addTextMarkers.splice(j, 1);
j--;
found = true;
break;
}
}
if (!found && _textMarker.className && _textMarker.className.indexOf('authorship-inline') > -1) {
_textMarker.clear();
}
}
for (var i = 0; i < addTextMarkers.length; i++) {
var textMarker = addTextMarkers[i];
var author = authors[textMarker.userid];
var rgbcolor = hex2rgb(author.color);
var colorString = "rgba(" + rgbcolor.red + "," + rgbcolor.green + "," + rgbcolor.blue + ",0.7)";
var styleString = textMarkderStylePrefix + colorString + textMarkderStylePostfix;
var className = 'authorship-inline-' + author.color.substr(1);
var rule = "." + className + "{" + styleString + "}";
addStyleRule(rule);
var _textMarker = editor.markText(textMarker.pos[0], textMarker.pos[1], {
className: 'authorship-inline ' + className,
title: author.name
});
}
authorshipMarks = authorMarks;
}
editor.on('update', function () {
$('.authorship-gutter:not([data-original-title])').tooltip({
container: '.CodeMirror-lines',
placement: 'right',
delay: { "show": 500, "hide": 100 }
});
$('.authorship-inline:not([data-original-title])').tooltip({
container: '.CodeMirror-lines',
placement: 'bottom',
delay: { "show": 500, "hide": 100 }
});
// clear tooltip which described element has been removed
$('[id^="tooltip"]').each(function (index, element) {
$ele = $(element);
if ($('[aria-describedby="' + $ele.attr('id') + '"]').length <= 0) $ele.remove();
});
});
socket.on('check', function (data) {
//console.log(data);
updateLastInfo(data);

View file

@ -4,4 +4,4 @@
* @link https://github.com/NextStepWebs/codemirror-spell-checker
* @license MIT
*/
.CodeMirror .cm-spell-error:not(.cm-url):not(.cm-comment):not(.cm-tag):not(.cm-word){border-bottom:1px dashed rgba(255,0,0,.8)}
.CodeMirror .cm-spell-error:not(.cm-url):not(.cm-comment):not(.cm-tag):not(.cm-word){border-bottom:2px dotted rgba(255,0,0,.8)}