BUGFIX: blank preview when loading draft.

FEATURE: worlds dumbest preview sync.
This commit is contained in:
Sam 2014-06-04 17:04:15 +10:00
parent c7209c0a65
commit fc8eef6d98
2 changed files with 30 additions and 151 deletions

View File

@ -330,7 +330,6 @@
function PanelCollection(postfix) { function PanelCollection(postfix) {
this.buttonBar = doc.getElementById("wmd-button-bar" + postfix); this.buttonBar = doc.getElementById("wmd-button-bar" + postfix);
this.preview = doc.getElementById("wmd-preview" + postfix); this.preview = doc.getElementById("wmd-preview" + postfix);
this.previewScroller = doc.getElementById("wmd-preview-scroller" + postfix);
this.input = doc.getElementById("wmd-input" + postfix); this.input = doc.getElementById("wmd-input" + postfix);
}; };
@ -861,7 +860,6 @@
var oldInputText; var oldInputText;
var maxDelay = 3000; var maxDelay = 3000;
var startType = "delayed"; // The other legal value is "manual" var startType = "delayed"; // The other legal value is "manual"
var scrollSyncOn = false && !!panels.previewScroller;
var paneContentHeight = function(pane) { var paneContentHeight = function(pane) {
var $pane = $(pane); var $pane = $(pane);
@ -870,100 +868,26 @@
return pane.scrollHeight - paneVerticalPadding; return pane.scrollHeight - paneVerticalPadding;
}; };
if (scrollSyncOn) {
var prevScrollPosition = $(panels.input).scrollTop();
var caretMarkerPosition = 0;
var markerPositions = {
scroller: [0, paneContentHeight(panels.previewScroller)],
preview: [0, paneContentHeight(panels.preview)]
};
}
var getCaretPosition = function() {
return Discourse.Utilities.caretPosition(panels.input);
};
var cacheCaretMarkerPosition = function() {
caretMarkerPosition = $(panels.previewScroller).find(".caret").position().top;
};
var cachePaneMarkerPositions = function(cacheName, pane) {
var $pane = $(pane);
var paneScrollPosition = $pane.scrollTop();
var panePaddingTop = parseInt($pane.css("padding-top"));
markerPositions[cacheName] = [0];
$(pane).find(".marker").each(function () {
var markerPosition = $(this).position().top + paneScrollPosition - panePaddingTop;
markerPositions[cacheName].push(markerPosition);
});
markerPositions[cacheName].push(paneContentHeight(pane));
};
var cacheMarkerPositions = function() {
cachePaneMarkerPositions("scroller", panels.previewScroller);
cachePaneMarkerPositions("preview", panels.preview);
};
var getMarkerPositions = function(syncPosition) {
var startMarkerIndex = 0;
var endMarkerIndex = markerPositions.scroller.length - 1;
for (var index = startMarkerIndex + 1; index < endMarkerIndex; index += 1) {
if (markerPositions.scroller[index] > syncPosition) {
endMarkerIndex = index;
break;
}
startMarkerIndex = index;
}
return {
scrollerStart: markerPositions.scroller[startMarkerIndex],
scrollerEnd: markerPositions.scroller[endMarkerIndex],
previewStart: markerPositions.preview[startMarkerIndex] || markerPositions.preview[markerPositions.preview.length-1],
previewEnd: markerPositions.preview[endMarkerIndex] || markerPositions.preview[markerPositions.preview.length-1]
};
};
var detectScrollDown = function(currentPosition, previousPosition) {
return (currentPosition - previousPosition >= 0);
};
var getRatio = function(positions) {
return (positions.previewEnd - positions.previewStart) / (positions.scrollerEnd - positions.scrollerStart);
};
var syncScroll = function(isEdit) { var syncScroll = function(isEdit) {
var $preview = $(panels.preview);
var $input = $(panels.input);
if($input.scrollTop() === 0){
$preview.scrollTop(0);
return;
}
if(($input.height() + $input.scrollTop() + 100) > panels.input.scrollHeight){
// cheat, special case for bottom
$preview.scrollTop(panels.preview.scrollHeight);
return;
}
var scrollPosition = $(panels.input).scrollTop(); var scrollPosition = $(panels.input).scrollTop();
var isScrollDown = (scrollPosition - prevScrollPosition >= 0); var factor = panels.preview.scrollHeight / panels.input.scrollHeight;
prevScrollPosition = scrollPosition;
var inputBaseline; var desired = scrollPosition * factor;
var previewBaseline; $preview.scrollTop(desired + 50);
var threshold;
if (isEdit) {
inputBaseline = caretMarkerPosition;
previewBaseline = ($(panels.preview).height() * (caretMarkerPosition - scrollPosition) / $(panels.input).height());
threshold = 20;
} else if (isScrollDown) {
inputBaseline = scrollPosition + $(panels.input).height();
previewBaseline = $(panels.preview).height();
threshold = 0;
} else {
inputBaseline = scrollPosition;
previewBaseline = 0;
threshold = 0;
}
var positions = getMarkerPositions(inputBaseline);
var ratio = getRatio(positions);
var newPreviewScrollPosition = positions.previewStart - previewBaseline + (inputBaseline - positions.scrollerStart) * ratio;
if (threshold == 0 || Math.abs(newPreviewScrollPosition - $(panels.preview).scrollTop()) >= threshold) {
$(panels.preview).scrollTop(newPreviewScrollPosition);
}
}; };
var setupScrollSync = function() { var setupScrollSync = function() {
@ -1020,39 +944,7 @@
var prevTime = new Date().getTime(); var prevTime = new Date().getTime();
var previewText; var previewText;
var previewScrollerText; previewText = converter.makeHtml(text);
if (scrollSyncOn) {
var caretPosition = getCaretPosition();
var caret = "465c94fb53b6304c4f57";
var marker = "468c94fb53b6304c4f58";
// add last marker
text = text + marker;
var addMarkers = function(text) {
return text.replace(/(\s*)(\n|\n|\r|\r\n)/g, function(m, spaces, newline) {
return marker + spaces + "\n";
});
}
previewText = converter.makeHtml(addMarkers(text))
.replace(new RegExp(marker, 'g'), '<span class="marker"></span>');
var withCaret = text.slice(0, caretPosition) + caret + text.slice(caretPosition);
previewScrollerText = addMarkers(withCaret)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/(\n|\n\r|\r\n)/g, '<br>')
.replace(caret, '<span class="caret"></span>')
.replace(new RegExp(marker, 'g'), '<span class="marker"></span>');
} else {
previewText = converter.makeHtml(text);
}
// Calculate the processing time of the HTML creation. // Calculate the processing time of the HTML creation.
// It's used as the delay time in the event listener. // It's used as the delay time in the event listener.
@ -1060,12 +952,8 @@
elapsedTime = currTime - prevTime; elapsedTime = currTime - prevTime;
Ember.run(function() { Ember.run(function() {
pushPreviewHtml(previewText, previewScrollerText); pushPreviewHtml(previewText);
if (scrollSyncOn) { syncScroll(true);
cacheMarkerPositions();
cacheCaretMarkerPosition();
syncScroll(true);
}
}); });
}; };
@ -1159,7 +1047,7 @@
// IE doesn't let you use innerHTML if the element is contained somewhere in a table // IE doesn't let you use innerHTML if the element is contained somewhere in a table
// (which is the case for inline editing) -- in that case, detach the element, set the // (which is the case for inline editing) -- in that case, detach the element, set the
// value, and reattach. Yes, that *is* ridiculous. // value, and reattach. Yes, that *is* ridiculous.
var ieSafePreviewSet = function (previewText, previewScrollerText) { var ieSafePreviewSet = function (previewText) {
var ieSafeSet = function(panel, text) { var ieSafeSet = function(panel, text) {
var parent = panel.parentNode; var parent = panel.parentNode;
var sibling = panel.nextSibling; var sibling = panel.nextSibling;
@ -1172,40 +1060,34 @@
}; };
ieSafeSet(panels.preview, previewText); ieSafeSet(panels.preview, previewText);
if (scrollSyncOn) {
ieSafeSet(panels.previewScroller, previewScrollerText);
}
} }
var nonSuckyBrowserPreviewSet = function (previewText, previewScrollerText) { var nonSuckyBrowserPreviewSet = function (previewText) {
panels.preview.innerHTML = previewText; panels.preview.innerHTML = previewText;
if (scrollSyncOn) {
panels.previewScroller.innerHTML = previewScrollerText;
}
} }
var previewSetter; var previewSetter;
var previewSet = function (previewText, previewScrollerText) { var previewSet = function (previewText) {
if (previewSetter) if (previewSetter)
return previewSetter(previewText, previewScrollerText); return previewSetter(previewText);
try { try {
nonSuckyBrowserPreviewSet(previewText, previewScrollerText); nonSuckyBrowserPreviewSet(previewText);
previewSetter = nonSuckyBrowserPreviewSet; previewSetter = nonSuckyBrowserPreviewSet;
} catch (e) { } catch (e) {
previewSetter = ieSafePreviewSet; previewSetter = ieSafePreviewSet;
previewSetter(previewText, previewScrollerText); previewSetter(previewText);
} }
}; };
var pushPreviewHtml = function (previewText, previewScrollerText) { var pushPreviewHtml = function (previewText) {
var emptyTop = position.getTop(panels.input) - getDocScrollTop(); var emptyTop = position.getTop(panels.input) - getDocScrollTop();
if (panels.preview) { if (panels.preview) {
previewSet(previewText, previewScrollerText); previewSet(previewText);
previewRefreshCallback(); previewRefreshCallback();
} }
@ -1231,12 +1113,8 @@
// TODO: make option to disable. We don't need this in discourse // TODO: make option to disable. We don't need this in discourse
// setupEvents(panels.input, applyTimeout); // setupEvents(panels.input, applyTimeout);
if (scrollSyncOn) { setupScrollSync();
setupScrollSync();
}
makePreviewHtml(); makePreviewHtml();
}; };
init(); init();

View File

@ -397,6 +397,7 @@ Discourse.ComposerView = Discourse.View.extend(Ember.Evented, {
return Em.run.later(jQuery, (function() { return Em.run.later(jQuery, (function() {
var replyTitle = $('#reply-title'); var replyTitle = $('#reply-title');
self.resize(); self.resize();
self.refreshPreview();
return replyTitle.length ? replyTitle.putCursorAtEnd() : $wmdInput.putCursorAtEnd(); return replyTitle.length ? replyTitle.putCursorAtEnd() : $wmdInput.putCursorAtEnd();
}), 300); }), 300);
}, },