From 4e64583a0b6175d2c9a6729ffde1472dd55d389c Mon Sep 17 00:00:00 2001
From: Wu Cheng-Han
Date: Fri, 15 May 2015 12:58:13 +0800
Subject: Marked as 0.2.8
---
public/js/common.js | 53 ++++++
public/js/cover.js | 245 ++++++++++++++++++++++++----
public/js/extra.js | 6 +-
public/js/fb.js | 8 +
public/js/ga.js | 14 --
public/js/history.js | 187 ++++++++++++++-------
public/js/index.js | 419 ++++++++++++++++++++----------------------------
public/js/pretty.js | 9 ++
public/js/syncscroll.js | 327 +++++++++++++++++++++++++++++++++++++
9 files changed, 913 insertions(+), 355 deletions(-)
create mode 100644 public/js/common.js
create mode 100644 public/js/fb.js
delete mode 100644 public/js/ga.js
create mode 100644 public/js/pretty.js
create mode 100644 public/js/syncscroll.js
(limited to 'public/js')
diff --git a/public/js/common.js b/public/js/common.js
new file mode 100644
index 00000000..37591d36
--- /dev/null
+++ b/public/js/common.js
@@ -0,0 +1,53 @@
+//common
+var domain = 'change this';
+var checkAuth = false;
+var profile = null;
+var lastLoginState = getLoginState();
+var loginStateChangeEvent = null;
+
+function resetCheckAuth() {
+ checkAuth = false;
+}
+
+function setLoginState(bool) {
+ Cookies.set('loginstate', bool, {
+ expires: 14
+ });
+ if (loginStateChangeEvent && bool != lastLoginState)
+ loginStateChangeEvent();
+ lastLoginState = bool;
+}
+
+function getLoginState() {
+ return Cookies.get('loginstate') === "true";
+}
+
+function clearLoginState() {
+ Cookies.remove('loginstate');
+}
+
+function checkIfAuth(yesCallback, noCallback) {
+ var cookieLoginState = getLoginState();
+ if (!checkAuth || typeof cookieLoginState == 'undefined') {
+ $.get('/me')
+ .done(function (data) {
+ if (data && data.status == 'ok') {
+ profile = data;
+ yesCallback(profile);
+ setLoginState(true);
+ } else {
+ noCallback();
+ setLoginState(false);
+ }
+ })
+ .fail(function () {
+ noCallback();
+ setLoginState(false);
+ });
+ checkAuth = true;
+ } else if (cookieLoginState) {
+ yesCallback(profile);
+ } else {
+ noCallback();
+ }
+}
\ No newline at end of file
diff --git a/public/js/cover.js b/public/js/cover.js
index fea51f6a..24ba605c 100644
--- a/public/js/cover.js
+++ b/public/js/cover.js
@@ -1,3 +1,47 @@
+var options = {
+ valueNames: ['id', 'text', 'timestamp', 'fromNow', 'time', 'tags'],
+ item: '
").insertAfter('.CodeMirror-cursors');
}
@@ -535,7 +581,10 @@ function buildCursor(id, color, pos) {
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.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';
@@ -566,6 +615,7 @@ editor.on('cursorActivity', function (cm) {
clearTimeout(cursorActivityTimer);
cursorActivityTimer = setTimeout(cursorActivity, cursorActivityDelay);
});
+
function cursorActivity() {
socket.emit('cursor activity', editor.getCursor());
}
@@ -578,8 +628,9 @@ function saveInfo() {
var top = $(document.body).scrollTop();
switch (currentMode) {
case modeType.edit:
- lastInfo.edit.scroll.left = left;
- lastInfo.edit.scroll.top = top;
+ //lastInfo.edit.scroll.left = left;
+ //lastInfo.edit.scroll.top = top;
+ lastInfo.edit.scroll = editor.getScrollInfo();
break;
case modeType.view:
lastInfo.view.scroll.left = left;
@@ -603,8 +654,12 @@ function restoreInfo() {
switch (currentMode) {
case modeType.edit:
- $(document.body).scrollLeft(lastInfo.edit.scroll.left);
- $(document.body).scrollTop(lastInfo.edit.scroll.top);
+ //$(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);
break;
case modeType.view:
$(document.body).scrollLeft(lastInfo.view.scroll.left);
@@ -652,9 +707,8 @@ function updateView() {
finishView(ui.area.view);
writeHistory(ui.area.markdown);
isDirty = false;
- // reset lines mapping cache on content update
- scrollMap = null;
emitUserStatus();
+ clearMap();
}
function partialUpdate(src, tar, des) {
@@ -702,7 +756,7 @@ function partialUpdate(src, tar, des) {
}
}
//tar end
- for (var i = 1; i <= tar.length; i++) {
+ 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');
@@ -715,7 +769,7 @@ function partialUpdate(src, tar, des) {
}
}
//src end
- for (var i = 1; i <= src.length; i++) {
+ 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');
@@ -730,56 +784,75 @@ function partialUpdate(src, tar, des) {
//check if tar end overlap tar start
var overlap = 0;
for (var i = start; i >= 0; i--) {
- var rawTarStart = cloneAndRemoveDataAttr(tar[i-1]);
- var rawTarEnd = cloneAndRemoveDataAttr(tar[tarEnd+1+start-i]);
- if(rawTarStart && rawTarEnd && rawTarStart.outerHTML == rawTarEnd.outerHTML)
+ var rawTarStart = cloneAndRemoveDataAttr(tar[i - 1]);
+ var rawTarEnd = cloneAndRemoveDataAttr(tar[tarEnd + 1 + start - i]);
+ if (rawTarStart && rawTarEnd && rawTarStart.outerHTML == rawTarEnd.outerHTML)
overlap++;
else
break;
}
- if(debug)
+ if (debug)
console.log('overlap:' + overlap);
//show diff content
- if(debug) {
+ if (debug) {
console.log('start:' + start);
console.log('tarEnd:' + tarEnd);
console.log('srcEnd:' + srcEnd);
- console.log('des[start]:' + des[start]);
}
tarEnd += overlap;
srcEnd += overlap;
- //add new element
- var newElements = "";
- for (var j = start; j <= srcEnd; j++) {
- if(debug)
- srcChanged += src[j].outerHTML;
- newElements += src[j].outerHTML;
+ var repeatAdd = (start - srcEnd) < (start - tarEnd);
+ var repeatDiff = Math.abs(srcEnd - tarEnd) - 1;
+ //push new elements
+ var newElements = [];
+ if(srcEnd >= start) {
+ for (var j = start; j <= srcEnd; j++) {
+ if (!src[j]) continue;
+ newElements.push(src[j].outerHTML);
+ }
+ } else if(repeatAdd) {
+ for (var j = srcEnd - repeatDiff; j <= srcEnd; j++) {
+ if (!des[j]) continue;
+ newElements.push(des[j].outerHTML);
+ }
}
- if(newElements && des[start]) {
- $(newElements).insertBefore(des[start]);
- } else {
- $(newElements).insertAfter(des[des.length-1]);
+ //push remove elements
+ var removeElements = [];
+ if(tarEnd >= start) {
+ for (var j = start; j <= tarEnd; j++) {
+ if (!des[j]) continue;
+ removeElements.push(des[j]);
+ }
+ } else if(!repeatAdd) {
+ for (var j = start; j <= start + repeatDiff; j++) {
+ if (!des[j]) continue;
+ removeElements.push(des[j]);
+ }
}
- if(debug)
- console.log(srcChanged);
- //remove old element
- if(debug)
- var tarChanged = "";
- for (var j = start; j <= tarEnd; j++) {
- if(debug)
- tarChanged += tar[j].outerHTML;
- if(des[j])
- des[j].remove();
+ //add elements
+ if (debug) {
+ console.log('ADD ELEMENTS');
+ console.log(newElements.join('\n'));
}
- if(debug) {
- console.log(tarChanged);
- var srcChanged = "";
+ if (des[start])
+ $(newElements.join('')).insertBefore(des[start]);
+ else
+ $(newElements.join('')).insertAfter(des[start - 1]);
+ //remove elements
+ if (debug)
+ console.log('REMOVE ELEMENTS');
+ for (var j = 0; j < removeElements.length; j++) {
+ if (debug) {
+ console.log(removeElements[j].outerHTML);
+ }
+ if (removeElements[j])
+ removeElements[j].remove();
}
}
}
function cloneAndRemoveDataAttr(el) {
- if(!el) return;
+ if (!el) return;
var rawEl = $(el).clone(true)[0];
rawEl.removeAttribute('data-startline');
rawEl.removeAttribute('data-endline');
@@ -789,152 +862,4 @@ function cloneAndRemoveDataAttr(el) {
function copyAttribute(src, des, attr) {
if (src && src.getAttribute(attr) && des)
des.setAttribute(attr, src.getAttribute(attr));
-}
-
-//
-// Inject line numbers for sync scroll. Notes:
-//
-// - We track only headings and paragraphs on first level. That's enougth.
-// - Footnotes content causes jumps. Level limit filter it automatically.
-//
-md.renderer.rules.paragraph_open = function (tokens, idx) {
- var line;
- if (tokens[idx].lines && tokens[idx].level === 0) {
- var startline = tokens[idx].lines[0] + 1;
- var endline = tokens[idx].lines[1];
- return '
';
- }
- return '';
-};
-
-md.renderer.rules.heading_open = function (tokens, idx) {
- var line;
- if (tokens[idx].lines && tokens[idx].level === 0) {
- var startline = tokens[idx].lines[0] + 1;
- var endline = tokens[idx].lines[1];
- return '';
- }
- return '';
-};
-
-editor.on('scroll', _.debounce(syncScrollToView, syncScrollDelay));
-//ui.area.view.on('scroll', _.debounce(syncScrollToEdit, 50));
-var scrollMap;
-// Build offsets for each line (lines can be wrapped)
-// That's a bit dirty to process each line everytime, but ok for demo.
-// Optimizations are required only for big texts.
-function buildScrollMap() {
- var i, offset, nonEmptyList, pos, a, b, lineHeightMap, linesCount,
- acc, sourceLikeDiv, textarea = ui.area.codemirror,
- _scrollMap;
-
- sourceLikeDiv = $('').css({
- position: 'absolute',
- visibility: 'hidden',
- height: 'auto',
- width: editor.getScrollInfo().clientWidth,
- 'font-size': textarea.css('font-size'),
- 'font-family': textarea.css('font-family'),
- 'line-height': textarea.css('line-height'),
- 'white-space': textarea.css('white-space')
- }).appendTo('body');
-
- offset = ui.area.view.scrollTop() - ui.area.view.offset().top;
- _scrollMap = [];
- nonEmptyList = [];
- lineHeightMap = [];
-
- acc = 0;
- editor.getValue().split('\n').forEach(function (str) {
- var h, lh;
-
- lineHeightMap.push(acc);
-
- if (str.length === 0) {
- acc++;
- return;
- }
-
- sourceLikeDiv.text(str);
- h = parseFloat(sourceLikeDiv.css('height'));
- lh = parseFloat(sourceLikeDiv.css('line-height'));
- acc += Math.round(h / lh);
- });
- sourceLikeDiv.remove();
- lineHeightMap.push(acc);
- linesCount = acc;
-
- for (i = 0; i < linesCount; i++) {
- _scrollMap.push(-1);
- }
-
- nonEmptyList.push(0);
- _scrollMap[0] = 0;
-
- ui.area.markdown.find('.part').each(function (n, el) {
- var $el = $(el),
- t = $el.data('startline');
- if (t === '') {
- return;
- }
- t = lineHeightMap[t];
- if (t !== 0) {
- nonEmptyList.push(t);
- }
- _scrollMap[t] = Math.round($el.offset().top + offset);
- });
-
- nonEmptyList.push(linesCount);
- _scrollMap[linesCount] = ui.area.view[0].scrollHeight;
-
- pos = 0;
- for (i = 1; i < linesCount; i++) {
- if (_scrollMap[i] !== -1) {
- pos++;
- continue;
- }
-
- a = nonEmptyList[pos];
- b = nonEmptyList[pos + 1];
- _scrollMap[i] = Math.round((_scrollMap[b] * (i - a) + _scrollMap[a] * (b - i)) / (b - a));
- }
-
- return _scrollMap;
-}
-
-function syncScrollToView() {
- var lineNo, posTo;
- var scrollInfo = editor.getScrollInfo();
- if (!scrollMap) {
- scrollMap = buildScrollMap();
- }
- lineNo = Math.floor(scrollInfo.top / editor.defaultTextHeight());
- posTo = scrollMap[lineNo];
- ui.area.view.stop(true).animate({scrollTop: posTo}, scrollAnimatePeriod);
-}
-
-function syncScrollToEdit() {
- var lineNo, posTo;
- if (!scrollMap) {
- scrollMap = buildScrollMap();
- }
- var top = ui.area.view.scrollTop();
- lineNo = closestIndex(top, scrollMap);
- posTo = lineNo * editor.defaultTextHeight();
- editor.scrollTo(0, posTo);
-}
-
-function closestIndex(num, arr) {
- var curr = arr[0];
- var index = 0;
- var diff = Math.abs(num - curr);
- for (var val = 0; val < arr.length; val++) {
- var newdiff = Math.abs(num - arr[val]);
- if (newdiff < diff) {
- diff = newdiff;
- curr = arr[val];
- index = val;
- }
- }
- return index;
}
\ No newline at end of file
diff --git a/public/js/pretty.js b/public/js/pretty.js
new file mode 100644
index 00000000..33b97803
--- /dev/null
+++ b/public/js/pretty.js
@@ -0,0 +1,9 @@
+var raw = $(".markdown-body").text();
+var markdown = LZString.decompressFromBase64(raw);
+var result = postProcess(md.render(markdown));
+var markdown = $(".markdown-body");
+markdown.html(result);
+markdown.show();
+finishView(markdown);
+autoLinkify(markdown);
+scrollToHash();
\ No newline at end of file
diff --git a/public/js/syncscroll.js b/public/js/syncscroll.js
new file mode 100644
index 00000000..3d97324c
--- /dev/null
+++ b/public/js/syncscroll.js
@@ -0,0 +1,327 @@
+//
+// Inject line numbers for sync scroll. Notes:
+//
+// - We track only headings and paragraphs on first level. That's enougth.
+// - Footnotes content causes jumps. Level limit filter it automatically.
+//
+md.renderer.rules.blockquote_open = function (tokens, idx /*, options, env */ ) {
+ if (tokens[idx].lines && tokens[idx].level === 0) {
+ var startline = tokens[idx].lines[0] + 1;
+ var endline = tokens[idx].lines[1];
+ return '\n';
+ }
+ return '\n';
+};
+
+md.renderer.rules.table_open = function (tokens, idx /*, options, env */ ) {
+ if (tokens[idx].lines && tokens[idx].level === 0) {
+ var startline = tokens[idx].lines[0] + 1;
+ var endline = tokens[idx].lines[1];
+ return '\n';
+ }
+ return '\n';
+};
+
+md.renderer.rules.bullet_list_open = function (tokens, idx /*, options, env */ ) {
+ if (tokens[idx].lines && tokens[idx].level === 0) {
+ var startline = tokens[idx].lines[0] + 1;
+ var endline = tokens[idx].lines[1];
+ return '\n';
+ }
+ return '\n';
+};
+
+md.renderer.rules.ordered_list_open = function (tokens, idx /*, options, env */ ) {
+ var token = tokens[idx];
+ if (tokens[idx].lines && tokens[idx].level === 0) {
+ var startline = tokens[idx].lines[0] + 1;
+ var endline = tokens[idx].lines[1];
+ return ' 1 ? ' start="' + token.order + '"' : '') + '>\n';
+ }
+ return ' 1 ? ' start="' + token.order + '"' : '') + '>\n';
+};
+
+md.renderer.rules.link_open = function (tokens, idx /*, options, env */ ) {
+ var title = tokens[idx].title ? (' title="' + Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(tokens[idx].title)) + '"') : '';
+ if (tokens[idx].lines && tokens[idx].level === 0) {
+ var startline = tokens[idx].lines[0] + 1;
+ var endline = tokens[idx].lines[1];
+ return '';
+ }
+ return '';
+};
+
+md.renderer.rules.paragraph_open = function (tokens, idx) {
+ if (tokens[idx].lines && tokens[idx].level === 0) {
+ var startline = tokens[idx].lines[0] + 1;
+ var endline = tokens[idx].lines[1];
+ return '';
+ }
+ return '';
+};
+
+md.renderer.rules.heading_open = function (tokens, idx) {
+ if (tokens[idx].lines && tokens[idx].level === 0) {
+ var startline = tokens[idx].lines[0] + 1;
+ var endline = tokens[idx].lines[1];
+ return '';
+ }
+ return '';
+};
+
+md.renderer.rules.image = function (tokens, idx, options /*, env */ ) {
+ var src = ' src="' + Remarkable.utils.escapeHtml(tokens[idx].src) + '"';
+ var title = tokens[idx].title ? (' title="' + Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(tokens[idx].title)) + '"') : '';
+ var alt = ' alt="' + (tokens[idx].alt ? Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(tokens[idx].alt)) : '') + '"';
+ var suffix = options.xhtmlOut ? ' /' : '';
+ var image = $('');
+ image[0].onload = function (e) {
+ if (viewAjaxCallback)
+ viewAjaxCallback();
+ };
+ return image[0].outerHTML;
+};
+
+md.renderer.rules.fence = function (tokens, idx, options, env, self) {
+ var token = tokens[idx];
+ var langClass = '';
+ var langPrefix = options.langPrefix;
+ var langName = '',
+ fenceName;
+ var highlighted;
+
+ if (token.params) {
+
+ //
+ // ```foo bar
+ //
+ // Try custom renderer "foo" first. That will simplify overwrite
+ // for diagrams, latex, and any other fenced block with custom look
+ //
+
+ fenceName = token.params.split(/\s+/g)[0];
+
+ if (Remarkable.utils.has(self.rules.fence_custom, fenceName)) {
+ return self.rules.fence_custom[fenceName](tokens, idx, options, env, self);
+ }
+
+ langName = Remarkable.utils.escapeHtml(Remarkable.utils.replaceEntities(Remarkable.utils.unescapeMd(fenceName)));
+ langClass = ' class="' + langPrefix + langName + '"';
+ }
+
+ if (options.highlight) {
+ highlighted = options.highlight(token.content, langName) || Remarkable.utils.escapeHtml(token.content);
+ } else {
+ highlighted = Remarkable.utils.escapeHtml(token.content);
+ }
+
+ if (tokens[idx].lines && tokens[idx].level === 0) {
+ var startline = tokens[idx].lines[0] + 1;
+ var endline = tokens[idx].lines[1];
+ return '' + highlighted + '
' + md.renderer.getBreak(tokens, idx);
+ }
+
+ return '' + highlighted + '
' + md.renderer.getBreak(tokens, idx);
+};
+
+md.renderer.rules.code = function (tokens, idx /*, options, env */ ) {
+ if (tokens[idx].block) {
+ if (tokens[idx].lines && tokens[idx].level === 0) {
+ var startline = tokens[idx].lines[0] + 1;
+ var endline = tokens[idx].lines[1];
+ return '' + Remarkable.utils.escapeHtml(tokens[idx].content) + '
' + md.renderer.getBreak(tokens, idx);
+ }
+
+ return '' + Remarkable.utils.escapeHtml(tokens[idx].content) + '
' + md.renderer.getBreak(tokens, idx);
+ }
+
+ if (tokens[idx].lines && tokens[idx].level === 0) {
+ var startline = tokens[idx].lines[0] + 1;
+ var endline = tokens[idx].lines[1];
+ return '' + Remarkable.utils.escapeHtml(tokens[idx].content) + '
';
+ }
+
+ return '' + Remarkable.utils.escapeHtml(tokens[idx].content) + '
';
+};
+
+var viewScrolling = false;
+var viewScrollingDelay = 200;
+var viewScrollingTimer = null;
+
+editor.on('scroll', syncScrollToView);
+ui.area.view.on('scroll', function () {
+ viewScrolling = true;
+ clearTimeout(viewScrollingTimer);
+ viewScrollingTimer = setTimeout(function () {
+ viewScrolling = false;
+ }, viewScrollingDelay);
+});
+//editor.on('scroll', _.debounce(syncScrollToView, syncScrollDelay));
+//ui.area.view.on('scroll', _.debounce(syncScrollToEdit, 50));
+
+var scrollMap, lineHeightMap;
+
+viewAjaxCallback = clearMap;
+
+function clearMap() {
+ scrollMap = null;
+ lineHeightMap = null;
+}
+
+// Build offsets for each line (lines can be wrapped)
+// That's a bit dirty to process each line everytime, but ok for demo.
+// Optimizations are required only for big texts.
+function buildMap() {
+ var i, offset, nonEmptyList, pos, a, b, _lineHeightMap, linesCount,
+ acc, sourceLikeDiv, textarea = ui.area.codemirror,
+ wrap = $('.CodeMirror-wrap pre'),
+ _scrollMap;
+
+ sourceLikeDiv = $('').css({
+ position: 'absolute',
+ visibility: 'hidden',
+ height: 'auto',
+ width: wrap.width(),
+ padding: wrap.css('padding'),
+ margin: wrap.css('margin'),
+ 'font-size': textarea.css('font-size'),
+ 'font-family': textarea.css('font-family'),
+ 'line-height': textarea.css('line-height'),
+ 'word-wrap': wrap.css('word-wrap'),
+ 'white-space': wrap.css('white-space'),
+ 'word-break': wrap.css('word-break')
+ }).appendTo('body');
+
+ offset = ui.area.view.scrollTop() - ui.area.view.offset().top;
+ _scrollMap = [];
+ nonEmptyList = [];
+ _lineHeightMap = [];
+
+ acc = 0;
+ editor.getValue().split('\n').forEach(function (str) {
+ var h, lh;
+
+ _lineHeightMap.push(acc);
+
+ if (str.length === 0) {
+ acc++;
+ return;
+ }
+
+ sourceLikeDiv.text(str);
+ h = parseFloat(sourceLikeDiv.css('height'));
+ lh = parseFloat(sourceLikeDiv.css('line-height'));
+ acc += Math.round(h / lh);
+ });
+ sourceLikeDiv.remove();
+ _lineHeightMap.push(acc);
+ linesCount = acc;
+
+ for (i = 0; i < linesCount; i++) {
+ _scrollMap.push(-1);
+ }
+
+ nonEmptyList.push(0);
+ _scrollMap[0] = 0;
+
+ ui.area.markdown.find('.part').each(function (n, el) {
+ var $el = $(el),
+ t = $el.data('startline') - 1;
+ if (t === '') {
+ return;
+ }
+ t = _lineHeightMap[t];
+ if (t !== 0) {
+ nonEmptyList.push(t);
+ }
+ _scrollMap[t] = Math.round($el.offset().top + offset);
+ });
+
+ nonEmptyList.push(linesCount);
+ _scrollMap[linesCount] = ui.area.view[0].scrollHeight;
+
+ pos = 0;
+ for (i = 1; i < linesCount; i++) {
+ if (_scrollMap[i] !== -1) {
+ pos++;
+ continue;
+ }
+
+ a = nonEmptyList[pos];
+ b = nonEmptyList[pos + 1];
+ _scrollMap[i] = Math.round((_scrollMap[b] * (i - a) + _scrollMap[a] * (b - i)) / (b - a));
+ }
+
+ _scrollMap[0] = 0;
+
+ scrollMap = _scrollMap;
+ lineHeightMap = _lineHeightMap;
+}
+
+function getPartByEditorLineNo(lineNo) {
+ var part = null;
+ ui.area.markdown.find('.part').each(function (n, el) {
+ if (part) return;
+ var $el = $(el),
+ t = $el.data('startline') - 1,
+ f = $el.data('endline') - 1;
+ if (t === '' || f === '') {
+ return;
+ }
+ if (lineNo >= t && lineNo <= f) {
+ part = $el;
+ }
+ });
+ if (part)
+ return {
+ startline: part.data('startline') - 1,
+ endline: part.data('endline') - 1,
+ linediff: Math.abs(part.data('endline') - part.data('startline')) + 1,
+ element: part
+ };
+ else
+ return null;
+}
+
+function getEditorLineNoByTop(top) {
+ for (var i = 0; i < lineHeightMap.length; i++)
+ if (lineHeightMap[i] * editor.defaultTextHeight() > top)
+ return i;
+ return null;
+}
+
+function syncScrollToView(_lineNo) {
+ var lineNo, posTo;
+ var scrollInfo = editor.getScrollInfo();
+ if (!scrollMap || !lineHeightMap) {
+ buildMap();
+ }
+ if (typeof _lineNo != "number") {
+ var topDiffPercent, posToNextDiff;
+ var textHeight = editor.defaultTextHeight();
+ lineNo = Math.floor(scrollInfo.top / textHeight);
+ var lineCount = editor.lineCount();
+ var lastLineHeight = editor.getLineHandle(lineCount - 1).height;
+ //if reach last line, then scroll to end
+ if (scrollInfo.top + scrollInfo.clientHeight >= scrollInfo.height - lastLineHeight) {
+ posTo = ui.area.view[0].scrollHeight - ui.area.view.height();
+ } else {
+ topDiffPercent = (scrollInfo.top % textHeight) / textHeight;
+ posTo = scrollMap[lineNo];
+ posToNextDiff = (scrollMap[lineNo + 1] - posTo) * topDiffPercent;
+ posTo += Math.floor(posToNextDiff);
+ }
+ } else {
+ if (viewScrolling) return;
+ posTo = scrollMap[lineHeightMap[_lineNo]];
+ }
+ var posDiff = Math.abs(ui.area.view.scrollTop() - posTo);
+ if (posDiff > scrollInfo.clientHeight / 5) {
+ var duration = posDiff / 50;
+ ui.area.view.stop(true).animate({
+ scrollTop: posTo
+ }, duration >= 50 ? duration : 100, "linear");
+ } else {
+ ui.area.view.stop(true).scrollTop(posTo);
+ }
+}
\ No newline at end of file
--
cgit v1.2.3