Skip to content

Commit a14e795

Browse files
committed
Add support of showing authorship in editor and adjust related styles
1 parent d5549c6 commit a14e795

4 files changed

Lines changed: 218 additions & 3 deletions

File tree

lib/realtime.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ function emitCheck(note) {
6565
var out = {
6666
updatetime: note.updatetime,
6767
lastchangeuser: note.lastchangeuser,
68-
lastchangeuserprofile: note.lastchangeuserprofile
68+
lastchangeuserprofile: note.lastchangeuserprofile,
69+
authors: note.authors,
70+
authorship: note.authorship
6971
};
7072
realtime.io.to(note.id).emit('check', out);
7173
}
@@ -314,6 +316,8 @@ function emitRefresh(socket) {
314316
ownerprofile: note.ownerprofile,
315317
lastchangeuser: note.lastchangeuser,
316318
lastchangeuserprofile: note.lastchangeuserprofile,
319+
authors: note.authors,
320+
authorship: note.authorship,
317321
permission: note.permission,
318322
createtime: note.createtime,
319323
updatetime: note.updatetime

public/css/index.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ body {
4949
min-width: 1.5em;
5050
text-align: right;
5151
}
52+
.CodeMirror-gutter.authorship-gutters {
53+
width: 8px;
54+
}
5255
.CodeMirror-matchingtag {
5356
background: rgba(255, 255, 255, .1);
5457
line-height: 1em;

public/js/index.js

Lines changed: 209 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ var editor = CodeMirror.fromTextArea(textit, {
287287
},
288288
autoCloseTags: true,
289289
foldGutter: true,
290-
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
290+
gutters: ["CodeMirror-linenumbers", "authorship-gutters", "CodeMirror-foldgutter"],
291291
extraKeys: defaultExtraKeys,
292292
flattenSpans: true,
293293
addModeClass: true,
@@ -2127,6 +2127,9 @@ socket.on('version', function (data) {
21272127
}
21282128
}
21292129
});
2130+
var authors = [];
2131+
var authorship = [];
2132+
var authorshipMarks = {};
21302133
function updateLastInfo(data) {
21312134
//console.log(data);
21322135
if (data.hasOwnProperty('createtime') && createtime !== data.createtime) {
@@ -2142,7 +2145,212 @@ function updateLastInfo(data) {
21422145
lastchangeuserprofile = data.lastchangeuserprofile;
21432146
updateLastChangeUser();
21442147
}
2148+
if (data.hasOwnProperty('authors') && authors !== data.authors) {
2149+
authors = data.authors;
2150+
}
2151+
if (data.hasOwnProperty('authorship') && authorship !== data.authorship) {
2152+
authorship = data.authorship;
2153+
updateAuthorship();
2154+
}
2155+
}
2156+
var updateAuthorship = _.throttle(updateAuthorshipInner, 50);
2157+
function initMark() {
2158+
return {
2159+
gutter: {
2160+
userid: null,
2161+
timestamp: null
2162+
},
2163+
textmarkers: []
2164+
};
21452165
}
2166+
function initMarkAndCheckGutter(mark, author, timestamp) {
2167+
if (!mark) mark = initMark();
2168+
if (!mark.gutter.userid || mark.gutter.timestamp > timestamp) {
2169+
mark.gutter.userid = author.userid;
2170+
mark.gutter.timestamp = timestamp;
2171+
}
2172+
return mark;
2173+
}
2174+
var gutterStylePrefix = "border-left: 3px solid ";
2175+
var gutterStylePostfix = "; height: " + defaultTextHeight + "px; margin-left: 3px;";
2176+
var textMarkderStylePrefix = "background-image: linear-gradient(to top, ";
2177+
var textMarkderStylePostfix = " 1px, transparent 1px);";
2178+
var addStyleRule = (function () {
2179+
var added = {};
2180+
var styleElement = document.createElement('style');
2181+
document.documentElement.getElementsByTagName('head')[0].appendChild(styleElement);
2182+
var styleSheet = styleElement.sheet;
2183+
2184+
return function (css) {
2185+
if (added[css]) {
2186+
return;
2187+
}
2188+
added[css] = true;
2189+
styleSheet.insertRule(css, (styleSheet.cssRules || styleSheet.rules).length);
2190+
};
2191+
}());
2192+
function updateAuthorshipInner() {
2193+
// ignore when ot not synced yet
2194+
if (Object.keys(cmClient.state).length > 0) return;
2195+
var authorMarks = {};
2196+
for (var i = 0; i < authorship.length; i++) {
2197+
var atom = authorship[i];
2198+
var author = authors[atom[0]];
2199+
if (author) {
2200+
var prePos = editor.posFromIndex(atom[1]);
2201+
var preLine = editor.getLine(prePos.line);
2202+
var postPos = editor.posFromIndex(atom[2]);
2203+
var postLine = editor.getLine(postPos.line);
2204+
if (prePos.ch == 0 && postPos.ch == postLine.length) {
2205+
for (var j = prePos.line; j <= postPos.line; j++) {
2206+
if (editor.getLine(j)) {
2207+
authorMarks[j] = initMarkAndCheckGutter(authorMarks[j], author, atom[3]);
2208+
}
2209+
}
2210+
} else if (postPos.line - prePos.line >= 1) {
2211+
var startLine = prePos.line;
2212+
var endLine = postPos.line;
2213+
if (prePos.ch == preLine.length) {
2214+
startLine++;
2215+
} else if (prePos.ch != 0) {
2216+
var mark = initMarkAndCheckGutter(authorMarks[prePos.line], author, atom[3]);
2217+
var _postPos = {
2218+
line: prePos.line,
2219+
ch: preLine.length
2220+
};
2221+
if (JSON.stringify(prePos) != JSON.stringify(_postPos)) {
2222+
mark.textmarkers.push({
2223+
userid: author.userid,
2224+
pos: [prePos, _postPos]
2225+
});
2226+
startLine++;
2227+
}
2228+
authorMarks[prePos.line] = mark;
2229+
}
2230+
if (postPos.ch == 0) {
2231+
endLine--;
2232+
} else if (postPos.ch != postLine.length) {
2233+
var mark = initMarkAndCheckGutter(authorMarks[postPos.line], author, atom[3]);
2234+
var _prePos = {
2235+
line: postPos.line,
2236+
ch: 0
2237+
};
2238+
if (JSON.stringify(_prePos) != JSON.stringify(postPos)) {
2239+
mark.textmarkers.push({
2240+
userid: author.userid,
2241+
pos: [_prePos, postPos]
2242+
});
2243+
endLine--;
2244+
}
2245+
authorMarks[postPos.line] = mark;
2246+
}
2247+
for (var j = startLine; j <= endLine; j++) {
2248+
if (editor.getLine(j)) {
2249+
authorMarks[j] = initMarkAndCheckGutter(authorMarks[j], author, atom[3]);
2250+
}
2251+
}
2252+
} else {
2253+
var mark = initMarkAndCheckGutter(authorMarks[prePos.line], author, atom[3]);
2254+
if (JSON.stringify(prePos) != JSON.stringify(postPos)) {
2255+
mark.textmarkers.push({
2256+
userid: author.userid,
2257+
pos: [prePos, postPos]
2258+
});
2259+
}
2260+
authorMarks[prePos.line] = mark;
2261+
}
2262+
}
2263+
}
2264+
var addTextMarkers = [];
2265+
editor.eachLine(function (line) {
2266+
var lineNumber = editor.getLineNumber(line);
2267+
var currMark = authorMarks[lineNumber];
2268+
var author = currMark ? authors[currMark.gutter.userid] : null;
2269+
if (currMark && author) {
2270+
var className = 'authorship-gutter-' + author.color.substr(1);
2271+
var gutters = editor.getLineHandle(lineNumber).gutterMarkers;
2272+
if (!gutters || !gutters['authorship-gutters'] ||
2273+
!gutters['authorship-gutters'].className ||
2274+
!gutters['authorship-gutters'].className.indexOf(className) < 0) {
2275+
var styleString = gutterStylePrefix + author.color + gutterStylePostfix;
2276+
var rule = "." + className + "{" + styleString + "}";
2277+
addStyleRule(rule);
2278+
var gutter = $('<div>', {
2279+
class: 'authorship-gutter ' + className,
2280+
title: author.name
2281+
});
2282+
editor.setGutterMarker(lineNumber, "authorship-gutters", gutter[0]);
2283+
}
2284+
} else {
2285+
editor.setGutterMarker(lineNumber, "authorship-gutters", null);
2286+
}
2287+
if (currMark && currMark.textmarkers.length > 0) {
2288+
for (var i = 0; i < currMark.textmarkers.length; i++) {
2289+
var textMarker = currMark.textmarkers[i];
2290+
if (textMarker.userid != currMark.gutter.userid) {
2291+
addTextMarkers.push(textMarker);
2292+
}
2293+
}
2294+
}
2295+
});
2296+
var allTextMarks = editor.getAllMarks();
2297+
for (var i = 0; i < allTextMarks.length; i++) {
2298+
var _textMarker = allTextMarks[i];
2299+
var pos = _textMarker.find();
2300+
var found = false;
2301+
for (var j = 0; j < addTextMarkers.length; j++) {
2302+
var textMarker = addTextMarkers[j];
2303+
var author = authors[textMarker.userid];
2304+
var className = 'authorship-inline-' + author.color.substr(1);
2305+
var obj = {
2306+
from: textMarker.pos[0],
2307+
to: textMarker.pos[1]
2308+
};
2309+
if (JSON.stringify(pos) == JSON.stringify(obj) && _textMarker.className &&
2310+
_textMarker.className.indexOf(className) > -1) {
2311+
addTextMarkers.splice(j, 1);
2312+
j--;
2313+
found = true;
2314+
break;
2315+
}
2316+
}
2317+
if (!found && _textMarker.className && _textMarker.className.indexOf('authorship-inline') > -1) {
2318+
_textMarker.clear();
2319+
}
2320+
}
2321+
for (var i = 0; i < addTextMarkers.length; i++) {
2322+
var textMarker = addTextMarkers[i];
2323+
var author = authors[textMarker.userid];
2324+
var rgbcolor = hex2rgb(author.color);
2325+
var colorString = "rgba(" + rgbcolor.red + "," + rgbcolor.green + "," + rgbcolor.blue + ",0.7)";
2326+
var styleString = textMarkderStylePrefix + colorString + textMarkderStylePostfix;
2327+
var className = 'authorship-inline-' + author.color.substr(1);
2328+
var rule = "." + className + "{" + styleString + "}";
2329+
addStyleRule(rule);
2330+
var _textMarker = editor.markText(textMarker.pos[0], textMarker.pos[1], {
2331+
className: 'authorship-inline ' + className,
2332+
title: author.name
2333+
});
2334+
}
2335+
authorshipMarks = authorMarks;
2336+
}
2337+
editor.on('update', function () {
2338+
$('.authorship-gutter:not([data-original-title])').tooltip({
2339+
container: '.CodeMirror-lines',
2340+
placement: 'right',
2341+
delay: { "show": 500, "hide": 100 }
2342+
});
2343+
$('.authorship-inline:not([data-original-title])').tooltip({
2344+
container: '.CodeMirror-lines',
2345+
placement: 'bottom',
2346+
delay: { "show": 500, "hide": 100 }
2347+
});
2348+
// clear tooltip which described element has been removed
2349+
$('[id^="tooltip"]').each(function (index, element) {
2350+
$ele = $(element);
2351+
if ($('[aria-describedby="' + $ele.attr('id') + '"]').length <= 0) $ele.remove();
2352+
});
2353+
});
21462354
socket.on('check', function (data) {
21472355
//console.log(data);
21482356
updateLastInfo(data);

public/vendor/codemirror-spell-checker/spell-checker.min.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
* @link https://github.com/NextStepWebs/codemirror-spell-checker
55
* @license MIT
66
*/
7-
.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)}
7+
.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)}

0 commit comments

Comments
 (0)