Add support of showing authorship in editor and adjust related styles
This commit is contained in:
		
							parent
							
								
									d5549c6a84
								
							
						
					
					
						commit
						a14e7953b5
					
				| @ -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 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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)} | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user