Implement remember document position

This commit is contained in:
benweet 2013-06-03 23:19:52 +01:00
parent 693072218e
commit c99f927205
18 changed files with 394 additions and 197 deletions

View File

@ -598,7 +598,7 @@ dt, dd {
}
dd {
margin-left: 40px;
margin-left: 40px;
}
/* Table style */

View File

@ -736,6 +736,9 @@
<dd>
<a target="_blank" href="http://jquery.com/">jQuery</a>
</dd>
<dd>
<a target="_blank" href="https://github.com/brandonaaron/jquery-mousewheel">jQuery Mouse Wheel Plugin</a>
</dd>
<dd>
<a target="_blank" href="https://code.google.com/p/pagedown/">PageDown</a>
/ <a target="_blank"

View File

@ -200,15 +200,31 @@ define([
// Create the PageDown editor
var editor = undefined;
var fileDesc = undefined;
var documentContent = undefined;
core.createEditor = function(onTextChange) {
var undoManager = undefined;
core.createEditor = function(fileDescParam) {
fileDesc = fileDescParam;
documentContent = undefined;
$("#wmd-input, .preview-container").scrollTop(0);
var initDocumentContent = fileDesc.content;
$("#wmd-input").val(initDocumentContent);
if(editor !== undefined) {
// Only restart if the editor is already created
editor.restart();
// If the editor is already created
undoManager.reinit(initDocumentContent, fileDesc.editorStart, fileDesc.editorEnd, fileDesc.editorScrollTop);
editor.refreshPreview();
return;
}
// Store scrollTop on scroll event
$("#wmd-input").scroll(function() {
if(documentContent !== undefined) {
fileDesc.editorScrollTop = $(this).scrollTop();
}
});
$(".preview-container").scroll(function() {
if(documentContent !== undefined) {
fileDesc.previewScrollTop = $(this).scrollTop();
}
});
var converter = new Markdown.Converter();
editor = new Markdown.Editor(converter);
// Custom insert link dialog
@ -229,7 +245,7 @@ define([
function checkDocumentChanges() {
var newDocumentContent = $("#wmd-input").val();
if(documentContent !== undefined && documentContent != newDocumentContent) {
onTextChange();
fileDesc.content = newDocumentContent;
}
documentContent = newDocumentContent;
}
@ -240,6 +256,8 @@ define([
return function() {
if(documentContent === undefined) {
makePreview();
$("#wmd-input").scrollTop(fileDesc.editorScrollTop);
$(".preview-container").scrollTop(fileDesc.previewScrollTop);
}
else {
debouncedMakePreview();
@ -251,14 +269,22 @@ define([
else {
previewWrapper = function(makePreview) {
return function() {
checkDocumentChanges();
makePreview();
if(documentContent === undefined) {
$(".preview-container").scrollTop(fileDesc.previewScrollTop);
}
checkDocumentChanges();
};
};
}
extensionMgr.onEditorConfigure(editor);
editor.hooks.chain("onPreviewRefresh", extensionMgr.onAsyncPreview);
editor.run(previewWrapper);
undoManager = editor.run(previewWrapper);
undoManager.reinit(initDocumentContent, fileDesc.editorStart, fileDesc.editorEnd, fileDesc.editorScrollTop);
$("#wmd-input").bind("keydown click focus", function(event) {
fileDesc.editorStart = this.selectionStart;
fileDesc.editorEnd = this.selectionEnd;
});
// Hide default buttons
$(".wmd-button-row").addClass("btn-group").find("li:not(.wmd-spacer)").addClass("btn").css("left", 0).find("span").hide();
@ -482,11 +508,6 @@ define([
checkOnline();
}
}, 1000);
// Focus on the editor at startup
_.defer(function() {
$("#wmd-input").focus();
});
});
return core;

View File

@ -7,6 +7,11 @@ define([
var documentSelector = {
extensionId: "documentSelector",
extensionName: "Document selector",
/*
defaultConfig: {
keyShortcut: 223
},
*/
settingsBloc: '<p>Builds the "Open document" dropdown menu.</p>'
};
@ -56,7 +61,8 @@ define([
$("#file-selector li:not(.stick)").removeClass("disabled");
var li = liMap[fileDesc.fileIndex];
if(li === undefined) {
// It means that we are showing a temporary file (not in the selector)
// It means that we are showing a temporary file (not in the
// selector)
return;
}
liMap[fileDesc.fileIndex].addClass("disabled");
@ -104,6 +110,12 @@ define([
}).click(function(event) {
event.stopPropagation();
});
/*
$("#wmd-input").keydown(function(event) {
if(event.ctrlKey && event.keyCode == documentSelector.config.keyShortcut) {
console.log(event.keyCode);
}
});*/
};
return documentSelector;

View File

@ -1,7 +1,8 @@
define([
"jquery",
"underscore",
"libs/css_browser_selector"
"libs/css_browser_selector",
"libs/jquery.mousewheel"
], function($, _) {
var scrollLink = {
@ -95,13 +96,14 @@ define([
// apply Scroll Link
lastEditorScrollTop = -10;
isScrollPreview = false;
lastPreviewScrollTop = -10;
runScrollLink();
}, 500);
// -10 to be sure the gap is > 9
// -10 to be sure the gap is more than 9px
var lastEditorScrollTop = -10;
var lastPreviewScrollTop = -10;
var isScrollEditor = false;
var isScrollPreview = false;
var runScrollLink = _.debounce(function() {
if(mdSectionList.length === 0 || mdSectionList.length !== htmlSectionList.length) {
@ -120,7 +122,8 @@ define([
});
if(srcSection === undefined) {
// Something wrong in the algorithm...
return -10;
callback(-10);
return;
}
var posInSection = (srcScrollTop - srcSection.startOffset) / srcSection.height;
var destSection = destSectionList[sectionIndex];
@ -131,50 +134,58 @@ define([
]);
if(Math.abs(destScrollTop - lastDestScrollTop) < 9) {
// Skip the animation in case it's not necessary
callback(lastDestScrollTop);
return;
}
destElt.animate({
scrollTop: destScrollTop
}, 600, function() {
}, 500, function() {
callback(destScrollTop);
});
}
// Perform the animation if diff > 9px
if(isScrollPreview === false && Math.abs(editorScrollTop - lastEditorScrollTop) > 9) {
if(isScrollEditor === true && Math.abs(editorScrollTop - lastEditorScrollTop) > 9) {
isScrollEditor = false;
// Animate the preview
lastEditorScrollTop = editorScrollTop;
animate(editorScrollTop, mdSectionList, previewElt, htmlSectionList, lastPreviewScrollTop, function(destScrollTop) {
lastPreviewScrollTop = destScrollTop;
});
}
else if(Math.abs(previewScrollTop - lastPreviewScrollTop) > 9) {
else if(isScrollPreview === true && Math.abs(previewScrollTop - lastPreviewScrollTop) > 9) {
isScrollPreview = false;
// Animate the editor
lastPreviewScrollTop = previewScrollTop;
animate(previewScrollTop, htmlSectionList, editorElt, mdSectionList, lastEditorScrollTop, function(destScrollTop) {
lastEditorScrollTop = destScrollTop;
});
}
}, 600);
}, 500);
scrollLink.onLayoutConfigure = function(layoutConfig) {
layoutConfig.onresize = buildSections;
layoutConfig.onresize = function() {
isScrollEditor = true;
buildSections();
};
};
scrollLink.onLayoutCreated = function() {
$(".preview-container").scroll(function() {
$(".preview-container").bind("keydown click focus mousewheel", function() {
isScrollPreview = true;
isScrollEditor = false;
runScrollLink();
});
$("#wmd-input").scroll(function() {
$("#wmd-input").bind("keydown click focus mousewheel", function() {
isScrollEditor = true;
isScrollPreview = false;
runScrollLink();
});
};
scrollLink.onEditorConfigure = function(editor) {
lastPreviewScrollTop = 0;
editor.getConverter().hooks.chain("postConversion", function(text) {
// To avoid losing scrolling position before elements are fully loaded
// To avoid losing scrolling position before elements are fully
// loaded
$("#wmd-preview").height($("#wmd-preview").height());
return text;
});
@ -183,11 +194,8 @@ define([
scrollLink.onPreviewFinished = function() {
// Now set the correct height
$("#wmd-preview").height("auto");
_.defer(function() {
// Modify scroll position of the preview not the editor
lastEditorScrollTop = -10;
buildSections();
});
isScrollEditor = true;
buildSections();
};
return scrollLink;

View File

@ -11,10 +11,16 @@ define([
var fileMgr = {};
// Defines a file descriptor in the file system (fileDesc objects)
// Defines a file descriptor (fileDesc objects)
function FileDescriptor(fileIndex, title, syncLocations, publishLocations) {
this.fileIndex = fileIndex;
this._title = title;
this._editorScrollTop = parseInt(localStorage[fileIndex + ".editorScrollTop"]) || 0;
this._editorStart = parseInt(localStorage[fileIndex + ".editorStart"]) || 0;
this._editorEnd = parseInt(localStorage[fileIndex + ".editorEnd"]) || 0;
this._previewScrollTop = parseInt(localStorage[fileIndex + ".previewScrollTop"]) || 0;
this.syncLocations = syncLocations || {};
this.publishLocations = publishLocations || {};
this.__defineGetter__("title", function() {
return this._title;
});
@ -30,12 +36,38 @@ define([
localStorage[this.fileIndex + ".content"] = content;
extensionMgr.onContentChanged(this);
});
this.syncLocations = syncLocations || {};
this.publishLocations = publishLocations || {};
this.__defineGetter__("editorScrollTop", function() {
return this._editorScrollTop;
});
this.__defineSetter__("editorScrollTop", function(editorScrollTop) {
this._editorScrollTop = editorScrollTop;
localStorage[this.fileIndex + ".editorScrollTop"] = editorScrollTop;
});
this.__defineGetter__("editorStart", function() {
return this._editorStart;
});
this.__defineSetter__("editorStart", function(editorStart) {
this._editorStart = editorStart;
localStorage[this.fileIndex + ".editorStart"] = editorStart;
});
this.__defineGetter__("editorEnd", function() {
return this._editorEnd;
});
this.__defineSetter__("editorEnd", function(editorEnd) {
this._editorEnd = editorEnd;
localStorage[this.fileIndex + ".editorEnd"] = editorEnd;
});
this.__defineGetter__("previewScrollTop", function() {
return this._previewScrollTop;
});
this.__defineSetter__("previewScrollTop", function(previewScrollTop) {
this._previewScrollTop = previewScrollTop;
localStorage[this.fileIndex + ".previewScrollTop"] = previewScrollTop;
});
}
// Load file descriptors from localStorage
_.chain(localStorage["file.list"].split(";")).compact().each(function(fileIndex) {
// Retrieve file descriptors from localStorage and populate fileSystem
_.each(utils.retrieveIndexArray("file.list"), function(fileIndex) {
fileSystem[fileIndex] = new FileDescriptor(fileIndex, localStorage[fileIndex + ".title"]);
});
@ -57,7 +89,6 @@ define([
}
};
// Caution: this function recreates the editor (reset undo operations)
fileMgr.selectFile = function(fileDesc) {
fileDesc = fileDesc || fileMgr.getCurrentFile();
@ -92,12 +123,8 @@ define([
}
}
// Recreate the editor
$("#wmd-input").val(fileDesc.content);
core.createEditor(function() {
// Callback to save content when textarea changes
fileMgr.saveFile();
});
// Refresh the editor
core.createEditor(fileDesc);
};
fileMgr.createFile = function(title, content, syncLocations, isTemporary) {
@ -137,7 +164,7 @@ define([
// Add the index to the file list
if(!isTemporary) {
localStorage["file.list"] += fileIndex + ";";
utils.appendIndexToArray("file.list", fileIndex);
fileSystem[fileIndex] = fileDesc;
extensionMgr.onFileCreated(fileDesc);
}
@ -148,7 +175,7 @@ define([
fileDesc = fileDesc || fileMgr.getCurrentFile();
// Remove the index from the file list
localStorage["file.list"] = localStorage["file.list"].replace(";" + fileDesc.fileIndex + ";", ";");
utils.removeIndexFromArray("file.list", fileDesc.fileIndex);
delete fileSystem[fileDesc.fileIndex];
if(fileMgr.isCurrentFile(fileDesc) === true) {
@ -160,12 +187,12 @@ define([
// Remove synchronized locations
_.each(fileDesc.syncLocations, function(syncAttributes) {
fileMgr.removeSync(syncAttributes, true);
fileMgr.removeSync(syncAttributes);
});
// Remove publish locations
_.each(fileDesc.publishLocations, function(publishAttributes) {
fileMgr.removePublish(publishAttributes, true);
fileMgr.removePublish(publishAttributes);
});
localStorage.removeItem(fileDesc.fileIndex + ".title");
@ -176,32 +203,24 @@ define([
extensionMgr.onFileDeleted(fileDesc);
};
// Save current file in localStorage
fileMgr.saveFile = function() {
var fileDesc = fileMgr.getCurrentFile();
fileDesc.content = $("#wmd-input").val();
};
// Add a synchronized location to a file
fileMgr.addSync = function(fileDesc, syncAttributes) {
localStorage[fileDesc.fileIndex + ".sync"] += syncAttributes.syncIndex + ";";
utils.appendIndexToArray(fileDesc.fileIndex + ".sync", syncAttributes.syncIndex);
fileDesc.syncLocations[syncAttributes.syncIndex] = syncAttributes;
// addSync is only used for export, not for import
extensionMgr.onSyncExportSuccess(fileDesc, syncAttributes);
};
// Remove a synchronized location
fileMgr.removeSync = function(syncAttributes, skipExtensions) {
fileMgr.removeSync = function(syncAttributes) {
var fileDesc = fileMgr.getFileFromSyncIndex(syncAttributes.syncIndex);
if(fileDesc !== undefined) {
localStorage[fileDesc.fileIndex + ".sync"] = localStorage[fileDesc.fileIndex + ".sync"].replace(";" + syncAttributes.syncIndex + ";", ";");
}
// Remove sync attributes
localStorage.removeItem(syncAttributes.syncIndex);
delete fileDesc.syncLocations[syncAttributes.syncIndex];
if(!skipExtensions) {
utils.removeIndexFromArray(fileDesc.fileIndex + ".sync", syncAttributes.syncIndex);
delete fileDesc.syncLocations[syncAttributes.syncIndex];
extensionMgr.onSyncRemoved(fileDesc, syncAttributes);
}
// Remove sync attributes from localStorage
localStorage.removeItem(syncAttributes.syncIndex);
};
// Get the file descriptor associated to a syncIndex
@ -228,23 +247,21 @@ define([
// Add a publishIndex (publish location) to a file
fileMgr.addPublish = function(fileDesc, publishAttributes) {
localStorage[fileDesc.fileIndex + ".publish"] += publishAttributes.publishIndex + ";";
utils.appendIndexToArray(fileDesc.fileIndex + ".publish", publishAttributes.publishIndex);
fileDesc.publishLocations[publishAttributes.publishIndex] = publishAttributes;
extensionMgr.onNewPublishSuccess(fileDesc, publishAttributes);
};
// Remove a publishIndex (publish location)
fileMgr.removePublish = function(publishAttributes, skipExtensions) {
fileMgr.removePublish = function(publishAttributes) {
var fileDesc = fileMgr.getFileFromPublishIndex(publishAttributes.publishIndex);
if(fileDesc !== undefined) {
localStorage[fileDesc.fileIndex + ".publish"] = localStorage[fileDesc.fileIndex + ".publish"].replace(";" + publishAttributes.publishIndex + ";", ";");
}
// Remove publish attributes
localStorage.removeItem(publishAttributes.publishIndex);
delete fileDesc.publishLocations[publishAttributes.publishIndex];
if(!skipExtensions) {
utils.removeIndexFromArray(fileDesc.fileIndex + ".publish", publishAttributes.publishIndex);
delete fileDesc.publishLocations[publishAttributes.publishIndex];
extensionMgr.onPublishRemoved(fileDesc, publishAttributes);
}
// Remove publish attributes from localStorage
localStorage.removeItem(publishAttributes.publishIndex);
};
// Get the file descriptor associated to a publishIndex

View File

@ -362,7 +362,7 @@ define([
task.retry(new Error(errorMsg), 1);
return;
}
else if(error.code <= 0) {
else if(error.code === 0 || error.code === -1) {
connected = false;
authenticated = false;
core.setOffline();

View File

@ -111,14 +111,13 @@
* its own image insertion dialog, this hook should return true, and the callback should be called with the chosen
* image url (or null if the user cancelled). If this hook returns false, the default dialog will be used.
*/
hooks.addFalse("insertLinkDialog"); // benweet
hooks.addFalse("insertLinkDialog");
this.getConverter = function () { return markdownConverter; }
var that = this,
panels;
// benweet
var undoManager;
this.run = function (previewWrapper) {
if (panels)
@ -126,7 +125,7 @@
panels = new PanelCollection(idPostfix);
var commandManager = new CommandManager(hooks, getString);
var previewManager = new PreviewManager(markdownConverter, panels, function () { hooks.onPreviewRefresh(); }, previewWrapper); // benweet
var previewManager = new PreviewManager(markdownConverter, panels, function () { hooks.onPreviewRefresh(); }, previewWrapper);
var uiManager;
if (!/\?noundo/.test(doc.location.href)) {
@ -147,13 +146,9 @@
var forceRefresh = that.refreshPreview = function () { previewManager.refresh(true); };
forceRefresh();
};
// benweet
this.restart = function() {
undoManager.reinit();
that.refreshPreview();
//Not necessary
//forceRefresh();
return undoManager;
};
}
@ -681,18 +676,21 @@
var init = function () {
setEventHandlers();
refreshState(true);
saveState();
//Not necessary
//saveState();
};
// benweet
this.reinit = function() {
this.reinit = function(content, start, end, scrollTop) {
undoStack = [];
stackPtr = 0;
mode = "none";
lastState = undefined;
timer = undefined;
inputStateObj = undefined;
refreshState();
inputStateObj.text = content;
inputStateObj.start = start;
inputStateObj.end = end;
inputStateObj.scrollTop = scrollTop;
inputStateObj.setInputAreaSelection();
saveState();
};
@ -842,7 +840,7 @@
this.init();
};
function PreviewManager(converter, panels, previewRefreshCallback, previewWrapper) { // benweet
function PreviewManager(converter, panels, previewRefreshCallback, previewWrapper) {
var managerObj = this;
var timeout;
@ -908,7 +906,7 @@
pushPreviewHtml(text);
};
if(previewWrapper !== undefined) { // benweet
if(previewWrapper !== undefined) {
makePreviewHtml = previewWrapper(makePreviewHtml);
}
@ -1030,7 +1028,8 @@
var init = function () {
setupEvents(panels.input, applyTimeout);
makePreviewHtml();
//Not necessary
//makePreviewHtml();
if (panels.preview) {
panels.preview.scrollTop = 0;
@ -1437,12 +1436,12 @@
return false;
}
}
button.className = button.className.replace(/ disabled/g, ""); // benweet
button.className = button.className.replace(/ disabled/g, "");
}
else {
image.style.backgroundPosition = button.XShift + " " + disabledYShift;
button.onmouseover = button.onmouseout = button.onclick = function () { };
button.className += " disabled"; // benweet
button.className += " disabled";
}
}
@ -1807,7 +1806,7 @@
ui.prompt(this.getString("imagedialog"), imageDefaultText, linkEnteredCallback);
}
else {
if (!this.hooks.insertLinkDialog(linkEnteredCallback)) // benweet
if (!this.hooks.insertLinkDialog(linkEnteredCallback))
ui.prompt(this.getString("linkdialog"), linkDefaultText, linkEnteredCallback);
}
return true;

View File

@ -24,7 +24,7 @@
}
}
return -1;
}
};
}
function trim(str) {
@ -113,21 +113,17 @@
// Duplicated from PageDown converter
function unescapeSpecialChars(text) {
//
// Swap back in all the special characters we've hidden.
//
text = text.replace(/~E(\d+)E/g,
function (wholeMatch, m1) {
var charCodeToReplace = parseInt(m1);
return String.fromCharCode(charCodeToReplace);
}
);
text = text.replace(/~E(\d+)E/g, function(wholeMatch, m1) {
var charCodeToReplace = parseInt(m1);
return String.fromCharCode(charCodeToReplace);
});
return text;
}
/******************************************************************
* Markdown.Extra *
*****************************************************************/
/*****************************************************************************
* Markdown.Extra *
****************************************************************************/
Markdown.Extra = function() {
// For converting internal markdown (in tables for instance).
@ -159,36 +155,47 @@
var extra = new Markdown.Extra();
var postNormalizationTransformations = [];
var preBlockGamutTransformations = [];
var postConversionTransformations = ["unHashExtraBlocks"];
options = options || {};
options.extensions = options.extensions || ["all"];
if (contains(options.extensions, "all"))
if (contains(options.extensions, "all")) {
options.extensions = ["tables", "fenced_code_gfm", "def_list", "attr_list"];
if (contains(options.extensions, "tables"))
preBlockGamutTransformations.push("tables");
if (contains(options.extensions, "fenced_code_gfm"))
}
if (contains(options.extensions, "attr_list")) {
postNormalizationTransformations.push("hashFcbAttributeBlocks");
preBlockGamutTransformations.push("hashHeaderAttributeBlocks");
postConversionTransformations.push("applyAttributeBlocks");
extra.attributeBlocks = true;
}
if (contains(options.extensions, "tables")) {
preBlockGamutTransformations.push("tables");
}
if (contains(options.extensions, "fenced_code_gfm")) {
postNormalizationTransformations.push("fencedCodeBlocks");
if (contains(options.extensions, "def_list"))
preBlockGamutTransformations.push("definitionLists");
if (contains(options.extensions, "attr_list"))
extra.attributeBlocks = true;
}
if (contains(options.extensions, "def_list")) {
preBlockGamutTransformations.push("definitionLists");
}
converter.hooks.chain("postNormalization", function(text) {
return extra.doTransform(postNormalizationTransformations, text);
return extra.doTransform(postNormalizationTransformations, text) + '\n';
});
// preBlockGamut also gives us access to a hook so we can run the
// block gamut recursively, however we don't need it at this point
converter.hooks.chain("preBlockGamut", function(text, blockGamutHookCallback) {
// Keep a reference to the block gamut callback to run recursively
extra.blockGamutHookCallback = blockGamutHookCallback;
return extra.doConversion(preBlockGamutTransformations, text);
text = processEscapes(text);
return extra.doTransform(preBlockGamutTransformations, text) + '\n';
});
// Keep a reference to the hook chain running before finishConversion to apply on hashed extra blocks
// Keep a reference to the hook chain running before doPostConversion to apply on hashed extra blocks
extra.previousPostConversion = converter.hooks.postConversion;
converter.hooks.chain("postConversion", function(text) {
return extra.finishConversion(text);
text = extra.doTransform(postConversionTransformations, text);
// Clear state vars that may use unnecessary memory
this.hashBlocks = [];
return text;
});
if ("highlighter" in options) {
@ -208,35 +215,9 @@
// Do transformations
Markdown.Extra.prototype.doTransform = function(transformations, text) {
if (this.attributeBlocks)
text = this.hashFcbAttributeBlocks(text);
for(var i = 0; i < transformations.length; i++)
text = this[transformations[i]](text);
return text + '\n';
};
// Setup state vars, do conversion
Markdown.Extra.prototype.doConversion = function(transformations, text) {
text = processEscapes(text);
if (this.attributeBlocks)
text = this.hashHeaderAttributeBlocks(text);
return this.doTransform(transformations, text);
};
// Clear state vars that may use unnecessary memory. Unhash blocks we
// stored, apply attribute blocks if necessary, and return converted text.
Markdown.Extra.prototype.finishConversion = function(text) {
text = this.unHashExtraBlocks(text);
if (this.attributeBlocks)
text = this.applyAttributeBlocks(text);
this.hashBlocks = [];
return text;
return text;
};
// Return a placeholder containing a key, which is the block's index in the
@ -466,6 +447,9 @@
code = code.replace(/&/g, "&amp;");
code = code.replace(/</g, "&lt;");
code = code.replace(/>/g, "&gt;");
// These were escaped by PageDown before postNormalization
code = code.replace(/~D/g, "$$");
code = code.replace(/~T/g, "~");
return code;
}

View File

@ -0,0 +1,117 @@
/*! Copyright (c) 2013 Brandon Aaron (http://brandonaaron.net)
* Licensed under the MIT License (LICENSE.txt).
*
* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
* Thanks to: Seamus Leahy for adding deltaX and deltaY
*
* Version: 3.1.3
*
* Requires: 1.2.2+
*/
(function (factory) {
if ( typeof define === 'function' && define.amd ) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS style for Browserify
module.exports = factory;
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
var lowestDelta, lowestDeltaXY;
if ( $.event.fixHooks ) {
for ( var i = toFix.length; i; ) {
$.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
}
}
$.event.special.mousewheel = {
setup: function() {
if ( this.addEventListener ) {
for ( var i = toBind.length; i; ) {
this.addEventListener( toBind[--i], handler, false );
}
} else {
this.onmousewheel = handler;
}
},
teardown: function() {
if ( this.removeEventListener ) {
for ( var i = toBind.length; i; ) {
this.removeEventListener( toBind[--i], handler, false );
}
} else {
this.onmousewheel = null;
}
}
};
$.fn.extend({
mousewheel: function(fn) {
return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
},
unmousewheel: function(fn) {
return this.unbind("mousewheel", fn);
}
});
function handler(event) {
var orgEvent = event || window.event,
args = [].slice.call(arguments, 1),
delta = 0,
deltaX = 0,
deltaY = 0,
absDelta = 0,
absDeltaXY = 0,
fn;
event = $.event.fix(orgEvent);
event.type = "mousewheel";
// Old school scrollwheel delta
if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
if ( orgEvent.detail ) { delta = orgEvent.detail * -1; }
// New school wheel delta (wheel event)
if ( orgEvent.deltaY ) {
deltaY = orgEvent.deltaY * -1;
delta = deltaY;
}
if ( orgEvent.deltaX ) {
deltaX = orgEvent.deltaX;
delta = deltaX * -1;
}
// Webkit
if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX * -1; }
// Look for lowest delta to normalize the delta values
absDelta = Math.abs(delta);
if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
// Get a whole value for the deltas
fn = delta > 0 ? 'floor' : 'ceil';
delta = Math[fn](delta / lowestDelta);
deltaX = Math[fn](deltaX / lowestDeltaXY);
deltaY = Math[fn](deltaY / lowestDeltaXY);
// Add event and delta to the front of the arguments
args.unshift(event, delta, deltaX, deltaY);
return ($.event.dispatch || $.event.handle).apply(this, args);
}
}));

View File

@ -26,6 +26,9 @@ requirejs.config({
'libs/jquery.waitforimages': [
'jquery'
],
'libs/jquery.mousewheel': [
'jquery'
],
'libs/layout': [
'libs/jquery-ui'
],

View File

@ -244,12 +244,11 @@ define([
};
core.onReady(function() {
var state = localStorage[PROVIDER_GDRIVE + ".state"];
var state = utils.retrieveIgnoreError(PROVIDER_GDRIVE + ".state");
if(state === undefined) {
return;
}
localStorage.removeItem(PROVIDER_GDRIVE + ".state");
state = JSON.parse(state);
if(state.action == "create") {
googleHelper.upload(undefined, state.folderId, GDRIVE_DEFAULT_FILE_TITLE, settings.defaultContent, undefined, function(error, file) {
if(error) {

View File

@ -28,6 +28,7 @@ define([
var importImageCallback = undefined;
var imageDoc = undefined;
var importImagePreferences = utils.retrieveIgnoreError(PROVIDER_GPLUS + ".importImagePreferences");
gplusProvider.importImage = function(callback) {
importImageCallback = callback;
googleHelper.picker(function(error, docs) {
@ -46,9 +47,7 @@ define([
utils.setInputValue("#input-import-image-title", imageDoc.name);
// Load preferences
var serializedPreferences = localStorage[PROVIDER_GPLUS + ".importImagePreferences"];
if(serializedPreferences) {
var importImagePreferences = JSON.parse(serializedPreferences);
if(importImagePreferences) {
utils.setInputValue("#input-import-image-size", importImagePreferences.size);
}
@ -67,7 +66,7 @@ define([
importImageCallback(undefined, image);
// Store import preferences for next time
var importImagePreferences = {};
importImagePreferences = {};
if(size) {
importImagePreferences.size = size;
}

View File

@ -30,13 +30,22 @@ define([
// Retrieve publish locations from localStorage
_.each(fileSystem, function(fileDesc) {
_.chain(localStorage[fileDesc.fileIndex + ".publish"].split(";")).compact().each(function(publishIndex) {
var publishAttributes = JSON.parse(localStorage[publishIndex]);
// Store publishIndex
publishAttributes.publishIndex = publishIndex;
// Replace provider ID by provider module in attributes
publishAttributes.provider = providerMap[publishAttributes.provider];
fileDesc.publishLocations[publishIndex] = publishAttributes;
_.each(utils.retrieveIndexArray(fileDesc.fileIndex + ".publish"), function(publishIndex) {
try {
var publishAttributes = JSON.parse(localStorage[publishIndex]);
// Store publishIndex
publishAttributes.publishIndex = publishIndex;
// Replace provider ID by provider module in attributes
publishAttributes.provider = providerMap[publishAttributes.provider];
fileDesc.publishLocations[publishIndex] = publishAttributes;
}
catch(e) {
// localStorage can be corrupted
extensionMgr.onError(e);
// Remove publish location
utils.removeIndexFromArray(fileDesc.fileIndex + ".publish", publishIndex);
localStorage.removeItem(publishIndex);
}
});
});
@ -151,9 +160,8 @@ define([
$("input:radio[name=radio-publish-format][value=" + defaultPublishFormat + "]").prop("checked", true);
// Load preferences
var serializedPreferences = localStorage[provider.providerId + ".publishPreferences"];
if(serializedPreferences) {
var publishPreferences = JSON.parse(serializedPreferences);
var publishPreferences = utils.retrieveIgnoreError(provider.providerId + ".publishPreferences");
if(publishPreferences) {
_.each(provider.publishPreferencesInputIds, function(inputId) {
utils.setInputValue("#input-publish-" + inputId, publishPreferences[inputId]);
});
@ -195,18 +203,6 @@ define([
localStorage[provider.providerId + ".publishPreferences"] = JSON.stringify(publishPreferences);
}
// Retrieve file's publish locations from localStorage
publisher.populatePublishLocations = function(fileDesc) {
_.chain(localStorage[fileDesc.fileIndex + ".publish"].split(";")).compact().each(function(publishIndex) {
var publishAttributes = JSON.parse(localStorage[publishIndex]);
// Store publishIndex
publishAttributes.publishIndex = publishIndex;
// Replace provider ID by provider module in attributes
publishAttributes.provider = providerMap[publishAttributes.provider];
fileDesc.publishLocations[publishIndex] = publishAttributes;
});
};
core.onReady(function() {
// Add every provider
var publishMenu = $("#publish-menu");

View File

@ -26,9 +26,12 @@ define([
extensionSettings: {}
};
if(_.has(localStorage, "settings")) {
try {
_.extend(settings, JSON.parse(localStorage.settings));
}
catch(e) {
// Ignore parsing error
}
return settings;
});

View File

@ -1,13 +1,10 @@
// Setup an empty localStorage or upgrade an existing one
define([
"underscore"
], function(_) {
"underscore",
"utils"
], function(_, utils) {
// Create the file system if not exist
if(localStorage["file.list"] === undefined) {
localStorage["file.list"] = ";";
}
var fileIndexList = _.compact(localStorage["file.list"].split(";"));
var fileIndexList = utils.retrieveIndexArray("file.list");
// localStorage versioning
var version = localStorage["version"];
@ -22,7 +19,7 @@ define([
_.each(fileIndexList, function(fileIndex) {
localStorage[fileIndex + ".publish"] = ";";
var syncIndexList = _.compact(localStorage[fileIndex + ".sync"].split(";"));
var syncIndexList = utils.retrieveIndexArray(fileIndex + ".sync");
_.each(syncIndexList, function(syncIndex) {
localStorage[syncIndex + ".contentCRC"] = "0";
// We store title CRC only for Google Drive synchronization
@ -52,7 +49,7 @@ define([
var SYNC_PROVIDER_GDRIVE = "sync." + PROVIDER_GDRIVE + ".";
var SYNC_PROVIDER_DROPBOX = "sync." + PROVIDER_DROPBOX + ".";
_.each(fileIndexList, function(fileIndex) {
var syncIndexList = _.compact(localStorage[fileIndex + ".sync"].split(";"));
var syncIndexList = utils.retrieveIndexArray(fileIndex + ".sync");
_.each(syncIndexList, function(syncIndex) {
var syncAttributes = {};
if(syncIndex.indexOf(SYNC_PROVIDER_GDRIVE) === 0) {
@ -85,7 +82,7 @@ define([
localStorage.removeItem(fileIndex + ".title");
localStorage.removeItem(fileIndex + ".publish");
localStorage.removeItem(fileIndex + ".content");
localStorage["file.list"] = localStorage["file.list"].replace(";" + fileIndex + ";", ";");
utils.removeIndexFromArray("file.list", fileIndex);
}
});
version = "v3";
@ -110,7 +107,7 @@ define([
// Upgrade from v5 to v6
if(version == "v5") {
_.each(fileIndexList, function(fileIndex) {
var publishIndexList = _.compact(localStorage[fileIndex + ".publish"].split(";"));
var publishIndexList = utils.retrieveIndexArray(fileIndex + ".publish");
_.each(publishIndexList, function(publishIndex) {
var publishAttributes = JSON.parse(localStorage[publishIndex]);
if(publishAttributes.provider == "gdrive") {

View File

@ -22,13 +22,22 @@ define([
// Retrieve sync locations from localStorage
_.each(fileSystem, function(fileDesc) {
_.chain(localStorage[fileDesc.fileIndex + ".sync"].split(";")).compact().each(function(syncIndex) {
var syncAttributes = JSON.parse(localStorage[syncIndex]);
// Store syncIndex
syncAttributes.syncIndex = syncIndex;
// Replace provider ID by provider module in attributes
syncAttributes.provider = providerMap[syncAttributes.provider];
fileDesc.syncLocations[syncIndex] = syncAttributes;
_.each(utils.retrieveIndexArray(fileDesc.fileIndex + ".sync"), function(syncIndex) {
try {
var syncAttributes = JSON.parse(localStorage[syncIndex]);
// Store syncIndex
syncAttributes.syncIndex = syncIndex;
// Replace provider ID by provider module in attributes
syncAttributes.provider = providerMap[syncAttributes.provider];
fileDesc.syncLocations[syncIndex] = syncAttributes;
}
catch(e) {
// localStorage can be corrupted
extensionMgr.onError(e);
// Remove sync location
utils.removeIndexFromArray(fileDesc.fileIndex + ".sync", syncIndex);
localStorage.removeItem(syncIndex);
}
});
});
@ -191,9 +200,8 @@ define([
utils.resetModalInputs();
// Load preferences
var serializedPreferences = localStorage[provider.providerId + ".exportPreferences"];
if(serializedPreferences) {
var exportPreferences = JSON.parse(serializedPreferences);
var exportPreferences = utils.retrieveIgnoreError(provider.providerId + ".exportPreferences");
if(exportPreferences) {
_.each(provider.exportPreferencesInputIds, function(inputId) {
utils.setInputValue("#input-sync-export-" + inputId, exportPreferences[inputId]);
});

View File

@ -196,7 +196,7 @@ define([
};
utils.updateCurrentTime();
// Serialize sync/publish attributes and store it in the fileStorage
// Serialize sync/publish attributes and store it in the localStorage
utils.storeAttributes = function(attributes) {
var storeIndex = attributes.syncIndex || attributes.publishIndex;
// Don't store sync/publish index
@ -206,6 +206,37 @@ define([
localStorage[storeIndex] = JSON.stringify(attributes);
};
// Retrieve/parse an index array from localStorage
utils.retrieveIndexArray = function(storeIndex) {
try {
return _.compact(localStorage[storeIndex].split(";"));
}
catch(e) {
localStorage[storeIndex] = ";";
return [];
}
};
// Append an index to an array in localStorage
utils.appendIndexToArray = function(storeIndex, index) {
localStorage[storeIndex] += index + ";";
};
// Remove an index from an array in localStorage
utils.removeIndexFromArray = function(storeIndex, index) {
localStorage[storeIndex] = localStorage[storeIndex].replace(";" + index + ";", ";");
};
// Retrieve/parse an object from localStorage. Returns undefined if error.
utils.retrieveIgnoreError = function(storeIndex) {
try {
return JSON.parse(localStorage[storeIndex]);
}
catch(e) {
return undefined;
}
};
// Base64 conversion
utils.encodeBase64 = function(str) {
if(str.length === 0) {