From f7f8c901f4bc39c3ed0a2bdfe1cbaa1ee6957999 Mon Sep 17 00:00:00 2001
From: Wu Cheng-Han
Date: Mon, 1 Jun 2015 18:04:25 +0800
Subject: Marked as 0.2.9
---
public/js/common.js | 36 +-
public/js/cover.js | 38 ++
public/js/extra.js | 29 +-
public/js/history.js | 18 +-
public/js/index.js | 985 +++++++++++++++++++++++++++++++++++++++++++-----
public/js/syncscroll.js | 56 ++-
6 files changed, 1036 insertions(+), 126 deletions(-)
(limited to 'public/js')
diff --git a/public/js/common.js b/public/js/common.js
index 37591d36..e6928e98 100644
--- a/public/js/common.js
+++ b/public/js/common.js
@@ -3,38 +3,62 @@ var domain = 'change this';
var checkAuth = false;
var profile = null;
var lastLoginState = getLoginState();
+var lastUserId = getUserId();
var loginStateChangeEvent = null;
function resetCheckAuth() {
checkAuth = false;
}
-function setLoginState(bool) {
+function setLoginState(bool, id) {
Cookies.set('loginstate', bool, {
expires: 14
});
- if (loginStateChangeEvent && bool != lastLoginState)
- loginStateChangeEvent();
+ if (id) {
+ Cookies.set('userid', id, {
+ expires: 14
+ });
+ } else {
+ Cookies.remove('userid');
+ }
lastLoginState = bool;
+ lastUserId = id;
+ checkLoginStateChanged();
+}
+
+function checkLoginStateChanged() {
+ if (getLoginState() != lastLoginState || getUserId() != lastUserId) {
+ if(loginStateChangeEvent)
+ loginStateChangeEvent();
+ return true;
+ } else {
+ return false;
+ }
}
function getLoginState() {
return Cookies.get('loginstate') === "true";
}
+function getUserId() {
+ return Cookies.get('userid');
+}
+
function clearLoginState() {
Cookies.remove('loginstate');
}
function checkIfAuth(yesCallback, noCallback) {
var cookieLoginState = getLoginState();
+ if (checkLoginStateChanged())
+ checkAuth = false;
if (!checkAuth || typeof cookieLoginState == 'undefined') {
$.get('/me')
.done(function (data) {
if (data && data.status == 'ok') {
profile = data;
yesCallback(profile);
- setLoginState(true);
+ setLoginState(true, data.id);
} else {
noCallback();
setLoginState(false);
@@ -43,8 +67,10 @@ function checkIfAuth(yesCallback, noCallback) {
.fail(function () {
noCallback();
setLoginState(false);
+ })
+ .always(function () {
+ checkAuth = true;
});
- checkAuth = true;
} else if (cookieLoginState) {
yesCallback(profile);
} else {
diff --git a/public/js/cover.js b/public/js/cover.js
index 24ba605c..322768bf 100644
--- a/public/js/cover.js
+++ b/public/js/cover.js
@@ -229,6 +229,44 @@ var source = $("#template").html();
var template = Handlebars.compile(source);
var context = {
release: [
+ {
+ version: "0.2.9",
+ tag: "wildfire",
+ date: moment("201505301400", 'YYYYMMDDhhmm').fromNow(),
+ detail: [
+ {
+ title: "Features",
+ item: [
+ "+ Support text auto complete",
+ "+ Support cursor tag and random last name",
+ "+ Support online user list",
+ "+ Support show user info in blockquote"
+ ]
+ },
+ {
+ title: "Enhancements",
+ item: [
+ "* Added more code highlighting support",
+ "* Added more continue list support",
+ "* Adjust menu and history filter UI for better UX",
+ "* Adjust sync scoll animte to gain performance",
+ "* Change compression method of dynamic data",
+ "* Optimized render script"
+ ]
+ },
+ {
+ title: "Fixes",
+ item: [
+ "* Access history fallback might get wrong",
+ "* Sync scroll not accurate",
+ "* Sync scroll reach bottom range too much",
+ "* Detect login state change not accurate",
+ "* Detect editor focus not accurate",
+ "* Server not handle some editor events"
+ ]
+ }
+ ]
+ },
{
version: "0.2.8",
tag: "flame",
diff --git a/public/js/extra.js b/public/js/extra.js
index 05fa4704..495c5677 100644
--- a/public/js/extra.js
+++ b/public/js/extra.js
@@ -65,6 +65,7 @@ function finishView(view) {
try {
for (var i = 0; i < mathjaxdivs.length; i++) {
MathJax.Hub.Queue(["Typeset", MathJax.Hub, mathjaxdivs[i].innerHTML]);
+ MathJax.Hub.Queue(viewAjaxCallback);
$(mathjaxdivs[i]).removeClass("mathjax");
}
} catch(err) {
@@ -101,6 +102,18 @@ function finishView(view) {
//render title
document.title = renderTitle(view);
}
+
+//regex for blockquote
+var spaceregex = /\s*/;
+var notinhtmltagregex = /(?![^<]*>|[^<>]*<\/)/;
+var coloregex = /\[color=([#|\(|\)|\s|\,|\w]*)\]/;
+coloregex = new RegExp(coloregex.source + notinhtmltagregex.source, "g");
+var nameregex = /\[name=([-|_|\s|\w]*)\]/;
+var timeregex = /\[time=([:|,|+|-|\(|\)|\s|\w]*)\]/;
+var nameandtimeregex = new RegExp(nameregex.source + spaceregex.source + timeregex.source + notinhtmltagregex.source, "g");
+nameregex = new RegExp(nameregex.source + notinhtmltagregex.source, "g");
+timeregex = new RegExp(timeregex.source + notinhtmltagregex.source, "g");
+
//only static transform should be here
function postProcess(code) {
var result = $('
").insertAfter('.CodeMirror-cursors');
}
- if ($('#' + id).length <= 0) {
- var cursor = $('
');
- //console.debug(pos);
- cursor.attr('data-line', pos.line);
- cursor.attr('data-ch', pos.ch);
- var coord = editor.charCoords(pos, 'windows');
+ if ($('#' + user.id).length <= 0) {
+ var cursor = $('
');
+ cursor.attr('data-line', user.cursor.line);
+ cursor.attr('data-ch', user.cursor.ch);
+ cursor.attr('data-offset-left', 0);
+ cursor.attr('data-offset-top', 0);
+
+ var cursorbar = $('
');
+ cursorbar[0].style.height = defaultTextHeight + 'px';
+ cursorbar[0].style.borderLeft = '2px solid ' + user.color;
+
+ var icon = '
';
+
+ var cursortag = $('
' + icon + ' ' + user.name + '
');
+ //cursortag[0].style.background = color;
+ cursortag[0].style.color = user.color;
+
+ cursor.attr('data-mode', 'state');
+ cursor.hover(
+ function () {
+ if (cursor.attr('data-mode') == 'hover')
+ cursortag.stop(true).fadeIn("fast");
+ },
+ function () {
+ if (cursor.attr('data-mode') == 'hover')
+ cursortag.stop(true).fadeOut("fast");
+ });
+
+ function switchMode(ele) {
+ if (ele.attr('data-mode') == 'state')
+ ele.attr('data-mode', 'hover');
+ else if (ele.attr('data-mode') == 'hover')
+ ele.attr('data-mode', 'state');
+ }
+
+ function switchTag(ele) {
+ if (ele.css('display') === 'none')
+ ele.stop(true).fadeIn("fast");
+ else
+ ele.stop(true).fadeOut("fast");
+ }
+ var hideCursorTagDelay = 2000;
+ var hideCursorTagTimer = null;
+
+ function hideCursorTag() {
+ if (cursor.attr('data-mode') == 'hover')
+ cursortag.fadeOut("fast");
+ }
+ cursor.on('touchstart', function (e) {
+ var display = cursortag.css('display');
+ cursortag.stop(true).fadeIn("fast");
+ clearTimeout(hideCursorTagTimer);
+ hideCursorTagTimer = setTimeout(hideCursorTag, hideCursorTagDelay);
+ if (display === 'none') {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ });
+ cursortag.on('mousedown touchstart', function (e) {
+ if (cursor.attr('data-mode') == 'state')
+ switchTag(cursortag);
+ switchMode(cursor);
+ e.preventDefault();
+ e.stopPropagation();
+ });
+
+ cursor.append(cursorbar);
+ cursor.append(cursortag);
+
cursor[0].style.left = coord.left + 'px';
cursor[0].style.top = coord.top + 'px';
- cursor[0].style.height = '18px';
- cursor[0].style.borderLeft = '2px solid ' + color;
$('.other-cursors').append(cursor);
- cursor.hide().fadeIn();
+
+ if (!user.idle)
+ cursor.stop(true).fadeIn();
+
+ checkCursorTag(coord, cursortag);
} else {
- var cursor = $('#' + id);
- cursor.attr('data-line', pos.line);
- cursor.attr('data-ch', pos.ch);
- var coord = editor.charCoords(pos, 'windows');
- cursor.stop(true).css('opacity', 1).animate({
- "left": coord.left,
- "top": coord.top
- }, cursorAnimatePeriod);
- //cursor[0].style.left = coord.left + 'px';
- //cursor[0].style.top = coord.top + 'px';
- cursor[0].style.height = '18px';
- cursor[0].style.borderLeft = '2px solid ' + color;
+ var cursor = $('#' + user.id);
+ cursor.attr('data-line', user.cursor.line);
+ cursor.attr('data-ch', user.cursor.ch);
+
+ var cursorbar = cursor.find('.cursorbar');
+ cursorbar[0].style.height = defaultTextHeight + 'px';
+ cursorbar[0].style.borderLeft = '2px solid ' + user.color;
+
+ var cursortag = cursor.find('.cursortag');
+ cursortag.find('i').removeClass().addClass('fa').addClass(iconClass);
+ cursortag.find(".name").text(user.name);
+
+ if (cursor.css('display') === 'none') {
+ cursor[0].style.left = coord.left + 'px';
+ cursor[0].style.top = coord.top + 'px';
+ } else {
+ cursor.animate({
+ "left": coord.left,
+ "top": coord.top
+ }, {
+ duration: cursorAnimatePeriod,
+ queue: false
+ });
+ }
+
+ if (user.idle && cursor.css('display') !== 'none')
+ cursor.stop(true).fadeOut();
+ else if (!user.idle && cursor.css('display') === 'none')
+ cursor.stop(true).fadeIn();
+
+ checkCursorTag(coord, cursortag);
}
}
@@ -601,13 +1129,19 @@ editor.on('change', function (i, op) {
if (debug)
console.debug(op);
if (op.origin != 'setValue' && op.origin != 'ignoreHistory') {
- socket.emit('change', LZString.compressToBase64(JSON.stringify(op)));
+ socket.emit('change', LZString.compressToUTF16(JSON.stringify(op)));
}
isDirty = true;
clearTimeout(doneTypingTimer);
doneTypingTimer = setTimeout(doneTyping, doneTypingDelay);
});
editor.on('focus', function (cm) {
+ for (var i = 0; i < onlineUsers.length; i++) {
+ if (onlineUsers[i].id == personalInfo.id) {
+ onlineUsers[i].cursor = editor.getCursor();
+ }
+ }
+ personalInfo['cursor'] = editor.getCursor();
socket.emit('cursor focus', editor.getCursor());
});
var cursorActivityTimer = null;
@@ -617,20 +1151,38 @@ editor.on('cursorActivity', function (cm) {
});
function cursorActivity() {
- socket.emit('cursor activity', editor.getCursor());
+ if (editorHasFocus() && !Visibility.hidden()) {
+ for (var i = 0; i < onlineUsers.length; i++) {
+ if (onlineUsers[i].id == personalInfo.id) {
+ onlineUsers[i].cursor = editor.getCursor();
+ }
+ }
+ personalInfo['cursor'] = editor.getCursor();
+ socket.emit('cursor activity', editor.getCursor());
+ }
}
editor.on('blur', function (cm) {
+ for (var i = 0; i < onlineUsers.length; i++) {
+ if (onlineUsers[i].id == personalInfo.id) {
+ onlineUsers[i].cursor = null;
+ }
+ }
+ personalInfo['cursor'] = null;
socket.emit('cursor blur');
});
function saveInfo() {
+ var scrollbarStyle = editor.getOption('scrollbarStyle');
var left = $(document.body).scrollLeft();
var top = $(document.body).scrollTop();
switch (currentMode) {
case modeType.edit:
- //lastInfo.edit.scroll.left = left;
- //lastInfo.edit.scroll.top = top;
- lastInfo.edit.scroll = editor.getScrollInfo();
+ if (scrollbarStyle == 'native') {
+ lastInfo.edit.scroll.left = left;
+ lastInfo.edit.scroll.top = top;
+ } else {
+ lastInfo.edit.scroll = editor.getScrollInfo();
+ }
break;
case modeType.view:
lastInfo.view.scroll.left = left;
@@ -647,6 +1199,7 @@ function saveInfo() {
}
function restoreInfo() {
+ var scrollbarStyle = editor.getOption('scrollbarStyle');
if (lastInfo.needRestore) {
var line = lastInfo.edit.cursor.line;
var ch = lastInfo.edit.cursor.ch;
@@ -654,12 +1207,15 @@ function restoreInfo() {
switch (currentMode) {
case modeType.edit:
- //$(document.body).scrollLeft(lastInfo.edit.scroll.left);
- //$(document.body).scrollTop(lastInfo.edit.scroll.top);
- var left = lastInfo.edit.scroll.left;
- var top = lastInfo.edit.scroll.top;
- editor.scrollIntoView();
- editor.scrollTo(left, top);
+ if (scrollbarStyle == 'native') {
+ $(document.body).scrollLeft(lastInfo.edit.scroll.left);
+ $(document.body).scrollTop(lastInfo.edit.scroll.top);
+ } else {
+ var left = lastInfo.edit.scroll.left;
+ var top = lastInfo.edit.scroll.top;
+ editor.scrollIntoView();
+ editor.scrollTo(left, top);
+ }
break;
case modeType.view:
$(document.body).scrollLeft(lastInfo.view.scroll.left);
@@ -685,15 +1241,19 @@ var finishChangeTimer = null;
var input = editor.getInputField();
//user is "finished typing," do something
function doneTyping() {
+ emitRefresh();
updateView();
- var value = editor.getValue();
- socket.emit('refresh', LZString.compressToBase64(value));
}
function finishChange() {
updateView();
}
+function emitRefresh() {
+ var value = editor.getValue();
+ socket.emit('refresh', LZString.compressToUTF16(value));
+}
+
var lastResult = null;
function updateView() {
@@ -703,12 +1263,22 @@ function updateView() {
//ui.area.markdown.html(result);
//finishView(ui.area.markdown);
partialUpdate(result, lastResult, ui.area.markdown.children().toArray());
- lastResult = $(result).clone(true);
+ if (result && lastResult && result.length != lastResult.length)
+ updateDataAttrs(result, ui.area.markdown.children().toArray());
+ lastResult = $(result).clone();
finishView(ui.area.view);
writeHistory(ui.area.markdown);
isDirty = false;
- emitUserStatus();
clearMap();
+ buildMap();
+}
+
+function updateDataAttrs(src, des) {
+ //sync data attr startline and endline
+ for (var i = 0; i < src.length; i++) {
+ copyAttribute(src[i], des[i], 'data-startline');
+ copyAttribute(src[i], des[i], 'data-endline');
+ }
}
function partialUpdate(src, tar, des) {
@@ -733,8 +1303,8 @@ function partialUpdate(src, tar, des) {
var end = 0;
//find diff start position
for (var i = 0; i < tar.length; i++) {
- copyAttribute(src[i], des[i], 'data-startline');
- copyAttribute(src[i], des[i], 'data-endline');
+ //copyAttribute(src[i], des[i], 'data-startline');
+ //copyAttribute(src[i], des[i], 'data-endline');
var rawSrc = cloneAndRemoveDataAttr(src[i]);
var rawTar = cloneAndRemoveDataAttr(tar[i]);
if (!rawSrc || !rawTar || rawSrc.outerHTML != rawTar.outerHTML) {
@@ -746,8 +1316,8 @@ function partialUpdate(src, tar, des) {
var srcEnd = 0;
var tarEnd = 0;
for (var i = 0; i < src.length; i++) {
- copyAttribute(src[i], des[i], 'data-startline');
- copyAttribute(src[i], des[i], 'data-endline');
+ //copyAttribute(src[i], des[i], 'data-startline');
+ //copyAttribute(src[i], des[i], 'data-endline');
var rawSrc = cloneAndRemoveDataAttr(src[i]);
var rawTar = cloneAndRemoveDataAttr(tar[i]);
if (!rawSrc || !rawTar || rawSrc.outerHTML != rawTar.outerHTML) {
@@ -759,8 +1329,8 @@ function partialUpdate(src, tar, des) {
for (var i = 1; i <= tar.length + 1; i++) {
var srcLength = src.length;
var tarLength = tar.length;
- copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
- copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
+ //copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
+ //copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
var rawSrc = cloneAndRemoveDataAttr(src[srcLength - i]);
var rawTar = cloneAndRemoveDataAttr(tar[tarLength - i]);
if (!rawSrc || !rawTar || rawSrc.outerHTML != rawTar.outerHTML) {
@@ -772,8 +1342,8 @@ function partialUpdate(src, tar, des) {
for (var i = 1; i <= src.length + 1; i++) {
var srcLength = src.length;
var tarLength = tar.length;
- copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
- copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
+ //copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
+ //copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
var rawSrc = cloneAndRemoveDataAttr(src[srcLength - i]);
var rawTar = cloneAndRemoveDataAttr(tar[tarLength - i]);
if (!rawSrc || !rawTar || rawSrc.outerHTML != rawTar.outerHTML) {
@@ -805,12 +1375,12 @@ function partialUpdate(src, tar, des) {
var repeatDiff = Math.abs(srcEnd - tarEnd) - 1;
//push new elements
var newElements = [];
- if(srcEnd >= start) {
+ if (srcEnd >= start) {
for (var j = start; j <= srcEnd; j++) {
if (!src[j]) continue;
newElements.push(src[j].outerHTML);
}
- } else if(repeatAdd) {
+ } else if (repeatAdd) {
for (var j = srcEnd - repeatDiff; j <= srcEnd; j++) {
if (!des[j]) continue;
newElements.push(des[j].outerHTML);
@@ -818,12 +1388,12 @@ function partialUpdate(src, tar, des) {
}
//push remove elements
var removeElements = [];
- if(tarEnd >= start) {
+ if (tarEnd >= start) {
for (var j = start; j <= tarEnd; j++) {
if (!des[j]) continue;
removeElements.push(des[j]);
}
- } else if(!repeatAdd) {
+ } else if (!repeatAdd) {
for (var j = start; j <= start + repeatDiff; j++) {
if (!des[j]) continue;
removeElements.push(des[j]);
@@ -853,7 +1423,7 @@ function partialUpdate(src, tar, des) {
function cloneAndRemoveDataAttr(el) {
if (!el) return;
- var rawEl = $(el).clone(true)[0];
+ var rawEl = $(el).clone()[0];
rawEl.removeAttribute('data-startline');
rawEl.removeAttribute('data-endline');
return rawEl;
@@ -862,4 +1432,229 @@ function cloneAndRemoveDataAttr(el) {
function copyAttribute(src, des, attr) {
if (src && src.getAttribute(attr) && des)
des.setAttribute(attr, src.getAttribute(attr));
-}
\ No newline at end of file
+}
+
+if ($('.cursor-menu').length <= 0) {
+ $("