diff --git a/css/default.css b/css/default.css
index 60e0afbf..7fbdbb2e 100644
--- a/css/default.css
+++ b/css/default.css
@@ -598,7 +598,7 @@ dt, dd {
}
dd {
- margin-left: 40px;
+ margin-left: 40px;
}
/* Table style */
diff --git a/index.html b/index.html
index bb7e0b03..067786e3 100644
--- a/index.html
+++ b/index.html
@@ -736,6 +736,9 @@
jQuery
+
+ jQuery Mouse Wheel Plugin
+
PageDown
/ Builds the "Open document" dropdown menu.'
};
@@ -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");
@@ -69,7 +75,7 @@ define([
documentSelector.onSyncRemoved = buildSelector;
documentSelector.onNewPublishSuccess = buildSelector;
documentSelector.onPublishRemoved = buildSelector;
-
+
// Filter for search input in file selector
function filterFileSelector(filter) {
var liList = $("#file-selector li:not(.stick)");
@@ -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;
diff --git a/js/extensions/scroll-link.js b/js/extensions/scroll-link.js
index 6bee7008..3157cfb5 100644
--- a/js/extensions/scroll-link.js
+++ b/js/extensions/scroll-link.js
@@ -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;
diff --git a/js/file-manager.js b/js/file-manager.js
index e4d6fcf1..4eb4361d 100644
--- a/js/file-manager.js
+++ b/js/file-manager.js
@@ -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
diff --git a/js/helpers/google-helper.js b/js/helpers/google-helper.js
index 403b9cea..3cf3a684 100644
--- a/js/helpers/google-helper.js
+++ b/js/helpers/google-helper.js
@@ -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();
diff --git a/js/libs/Markdown.Editor.js b/js/libs/Markdown.Editor.js
index debd0630..660e1df6 100644
--- a/js/libs/Markdown.Editor.js
+++ b/js/libs/Markdown.Editor.js
@@ -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;
diff --git a/js/libs/Markdown.Extra.js b/js/libs/Markdown.Extra.js
index 8204799d..b9c7f56b 100644
--- a/js/libs/Markdown.Extra.js
+++ b/js/libs/Markdown.Extra.js
@@ -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, "&");
code = code.replace(//g, ">");
+ // These were escaped by PageDown before postNormalization
+ code = code.replace(/~D/g, "$$");
+ code = code.replace(/~T/g, "~");
return code;
}
diff --git a/js/libs/jquery.mousewheel.js b/js/libs/jquery.mousewheel.js
new file mode 100644
index 00000000..9d65c716
--- /dev/null
+++ b/js/libs/jquery.mousewheel.js
@@ -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);
+ }
+
+}));
diff --git a/js/main.js b/js/main.js
index e1df25f5..f016b838 100644
--- a/js/main.js
+++ b/js/main.js
@@ -26,6 +26,9 @@ requirejs.config({
'libs/jquery.waitforimages': [
'jquery'
],
+ 'libs/jquery.mousewheel': [
+ 'jquery'
+ ],
'libs/layout': [
'libs/jquery-ui'
],
diff --git a/js/providers/gdrive-provider.js b/js/providers/gdrive-provider.js
index 0f5db6a1..2747d561 100644
--- a/js/providers/gdrive-provider.js
+++ b/js/providers/gdrive-provider.js
@@ -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) {
diff --git a/js/providers/gplus-provider.js b/js/providers/gplus-provider.js
index 26bd3bea..fa1593fc 100644
--- a/js/providers/gplus-provider.js
+++ b/js/providers/gplus-provider.js
@@ -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;
}
diff --git a/js/publisher.js b/js/publisher.js
index dc78a962..75517d52 100644
--- a/js/publisher.js
+++ b/js/publisher.js
@@ -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");
diff --git a/js/settings.js b/js/settings.js
index 03d99b58..8c7ee974 100644
--- a/js/settings.js
+++ b/js/settings.js
@@ -26,9 +26,12 @@ define([
extensionSettings: {}
};
- if(_.has(localStorage, "settings")) {
+ try {
_.extend(settings, JSON.parse(localStorage.settings));
}
+ catch(e) {
+ // Ignore parsing error
+ }
return settings;
});
\ No newline at end of file
diff --git a/js/storage.js b/js/storage.js
index cb8072eb..0e5da2ed 100644
--- a/js/storage.js
+++ b/js/storage.js
@@ -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") {
diff --git a/js/synchronizer.js b/js/synchronizer.js
index d6915a22..20c814a6 100644
--- a/js/synchronizer.js
+++ b/js/synchronizer.js
@@ -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]);
});
diff --git a/js/utils.js b/js/utils.js
index 6d9b3658..5d7483f4 100644
--- a/js/utils.js
+++ b/js/utils.js
@@ -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
@@ -205,7 +205,38 @@ define([
attributes.provider = attributes.provider.providerId;
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) {