New extension pattern

This commit is contained in:
benweet 2013-05-29 00:41:09 +01:00
parent 569a52ca21
commit a7a5defbc7
25 changed files with 244 additions and 176 deletions

View File

@ -174,6 +174,31 @@ input[readonly], select[readonly], textarea[readonly] {
margin-right: 10px;
}
#extension-buttons {
margin-right: 15px;
}
#extension-buttons > .btn-group {
margin: 5px 0 0;
}
#extension-buttons > .btn-group > .btn {
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
#extension-buttons > .btn-group:first-child > .btn {
-webkit-border-radius: 4px 0 0 4px;
-moz-border-radius: 4px 0 0 4px;
border-radius: 4px 0 0 4px;
}
#extension-buttons > .btn-group:last-child > .btn {
-webkit-border-radius: 0 4px 4px 0;
-moz-border-radius: 0 4px 4px 0;
border-radius: 0 4px 4px 0;
}
.btn-group > .btn + .dropdown-toggle {
padding-right: 12px;
padding-left: 12px;
@ -405,7 +430,7 @@ div.dropdown-menu i {
width: 43px;
height: 11px;
background-position: 0 0;
margin: 14px 15px 0;
margin: 16px 16px 0;
}
.working-indicator.show {

View File

@ -34,31 +34,7 @@
<li><div id="wmd-button-bar"></div></li>
</ul>
<ul class="nav pull-right hide" id="menu-bar">
<li class="btn-group">
<button class="btn action-force-sync"
title="Synchronize all documents">
<i class="icon-refresh"></i>
</button>
<button class="btn action-force-publish"
title="Publish this document">
<i class="icon-share"></i>
</button>
<button class="btn dropdown-toggle" data-toggle="dropdown"
title="Share this document">
<i class="icon-link"></i>
</button>
<div id="link-container" class="dropdown-menu">
<div class="link-list"></div>
<p class="no-link">To share this document you need first to <a
href="#" class="action-publish-gist">publish it as a Gist</a> in
Markdown format.
</p>
<blockquote class="muted">
<b>NOTE:</b> You can open any URL within StackEdit using <a
href="viewer.html?url=https://raw.github.com/benweet/stackedit/master/README.md"
title="Sharing example">viewer.html?url=...</a>
</blockquote>
</div>
<li id="extension-buttons">
</li>
<li class="btn-group"><button class="btn action-create-file"
title="New local document">

View File

@ -12,6 +12,7 @@ define([
var asyncRunner = {};
var taskQueue = [];
var asyncRunning = false;
var currentTask = undefined;
var currentTaskRunning = false;
var currentTaskStartTime = 0;
@ -137,7 +138,10 @@ define([
// Dequeue an enqueued task
currentTask = taskQueue.shift();
currentTaskStartTime = utils.currentTime;
extensionMgr.onAsyncRunning(true);
if(asyncRunning === false) {
asyncRunning = true;
extensionMgr.onAsyncRunning(true);
}
}
// Run the task
@ -155,13 +159,15 @@ define([
_.each(callbacks, function(callback) {
callback(param);
});
} finally {
}
finally {
task.finished = true;
if (currentTask === task) {
currentTask = undefined;
currentTaskRunning = false;
}
if (taskQueue.length === 0) {
asyncRunning = false;
extensionMgr.onAsyncRunning(false);
} else {
asyncRunner.runTask();

View File

@ -261,8 +261,8 @@ define([
};
};
}
extensionMgr.onEditorConfigure(editor);
editor.hooks.chain("onPreviewRefresh", extensionMgr.onAsyncPreview);
extensionMgr.onEditorConfigure(editor);
$("#wmd-input, #wmd-preview").scrollTop(0);
$("#wmd-button-bar").empty();

View File

@ -230,7 +230,7 @@ define([
function handleError(error, task) {
var errorMsg = true;
if (error) {
console.error(error);
logger.error(error);
// Try to analyze the error
if (typeof error === "string") {
errorMsg = error;

View File

@ -39,6 +39,7 @@ define([
syncAttributes.version = versionTag;
syncAttributes.contentCRC = utils.crc32(content);
syncAttributes.syncIndex = createSyncIndex(path);
utils.storeAttributes(syncAttributes);
return syncAttributes;
}
@ -54,7 +55,6 @@ define([
var fileDescList = [];
_.each(result, function(file) {
var syncAttributes = createSyncAttributes(file.path, file.versionTag, file.content);
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
var syncLocations = {};
syncLocations[syncAttributes.syncIndex] = syncAttributes;
var fileDesc = fileMgr.createFile(file.name, file.content, syncLocations);
@ -106,7 +106,6 @@ define([
return;
}
var syncAttributes = createSyncAttributes(result.path, result.versionTag, content);
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
callback(undefined, syncAttributes);
});
}
@ -185,7 +184,7 @@ define([
fileMgr.removeSync(syncAttributes);
return;
}
var localContent = localStorage[fileDesc.fileIndex + ".content"];
var localContent = fileDesc.getContent();
var localContentChanged = syncAttributes.contentCRC != utils.crc32(localContent);
var file = change.stat;
var remoteContentCRC = utils.crc32(file.content);
@ -193,13 +192,12 @@ define([
var fileContentChanged = localContent != file.content;
// Conflict detection
if (fileContentChanged === true && localContentChanged === true && remoteContentChanged === true) {
var backupFileDesc = fileMgr.createFile(localTitle + " (backup)", localContent);
extensionMgr.onTitleChanged(backupFileDesc);
fileMgr.createFile(localTitle + " (backup)", localContent);
extensionMgr.onMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.');
}
// If file content changed
if(fileContentChanged && remoteContentChanged === true) {
localStorage[fileDesc.fileIndex + ".content"] = file.content;
fileDesc.setContent(file.content);
extensionMgr.onMessage('"' + localTitle + '" has been updated from Dropbox.');
if(fileMgr.isCurrentFile(fileDesc)) {
fileMgr.selectFile(); // Refresh editor
@ -208,7 +206,7 @@ define([
// Update syncAttributes
syncAttributes.version = file.versionTag;
syncAttributes.contentCRC = remoteContentCRC;
localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
utils.storeAttributes(syncAttributes);
});
localStorage[PROVIDER_DROPBOX + ".lastChangeId"] = newChangeId;
callback();

View File

@ -3,9 +3,9 @@ define( [
"underscore",
"utils",
"settings",
"extensions/button-sync",
"extensions/button-publish",
"extensions/button-share",
"extensions/button-sync",
"extensions/document-selector",
"extensions/document-title",
"extensions/manage-publication",
@ -42,7 +42,7 @@ define( [
function createHook(hookName) {
var callbackList = getExtensionCallbackList(hookName);
return function() {
console.debug(hookName);
logger.debug(hookName, arguments);
var callbackArguments = arguments;
_.each(callbackList, function(callback) {
callback.apply(null, callbackArguments);
@ -64,7 +64,7 @@ define( [
// Load/Save extension config from/to settings
extensionMgr["onLoadSettings"] = function() {
console.debug("onLoadSettings");
logger.debug("onLoadSettings");
_.each(extensionList, function(extension) {
utils.setInputChecked("#input-enable-extension-" + extension.extensionId, extension.config.enabled);
var onLoadSettingsCallback = extension.onLoadSettings;
@ -72,7 +72,7 @@ define( [
});
};
extensionMgr["onSaveSettings"] = function(newExtensionSettings, event) {
console.debug("onSaveSettings");
logger.debug("onSaveSettings");
_.each(extensionList, function(extension) {
var newExtensionConfig = extension.defaultConfig || {};
newExtensionConfig.enabled = utils.getInputChecked("#input-enable-extension-" + extension.extensionId);
@ -88,17 +88,16 @@ define( [
addHook("onOfflineChanged");
addHook("onAsyncRunning");
// To store reference to modules that are accessible from extensions
// To access modules that are loaded after extensions
addHook("onFileMgrCreated");
addHook("onSynchronizerCreated");
addHook("onPublisherCreated");
// Operations on files
addHook("onFileSystemCreated");
addHook("onFileCreated");
addHook("onFileDeleted");
addHook("onFileChanged");
addHook("onFileSelected");
addHook("onContentChanged");
addHook("onTitleChanged");
// Sync events
@ -124,7 +123,7 @@ define( [
var onPreviewFinished = createHook("onPreviewFinished");
var onAsyncPreviewCallbackList = getExtensionCallbackList("onAsyncPreview");
extensionMgr["onAsyncPreview"] = function() {
console.debug("onAsyncPreview");
logger.debug("onAsyncPreview");
// Call onPreviewFinished callbacks when all async preview are finished
var counter = 0;
function tryFinished() {
@ -172,6 +171,14 @@ define( [
).sortBy(function(extension) {
return extension.extensionName.toLowerCase();
}).each(createSettings);
// Create extension buttons
logger.debug("onCreateButton");
var onCreateButtonCallbackList = getExtensionCallbackList("onCreateButton");
_.each(onCreateButtonCallbackList, function(callback) {
$("#extension-buttons").append($('<div class="btn-group">').append(callback()));
});
});
return extensionMgr;

View File

@ -9,20 +9,42 @@ define([
settingsBloc: '<p>Adds a "Publish document" button in the navigation bar.</p>'
};
var button = undefined;
var currentFileDesc = undefined;
var publishRunning = false;
var hasPublications = false;
var isOffline = false;
// Enable/disable the button
function updateButtonState() {
if(button === undefined) {
return;
}
if(publishRunning === true || hasPublications === false || isOffline === true) {
$(".action-force-publish").addClass("disabled");
button.addClass("disabled");
}
else {
$(".action-force-publish").removeClass("disabled");
button.removeClass("disabled");
}
};
var publisher = undefined;
buttonPublish.onPublisherCreated = function(publisherParameter) {
publisher = publisherParameter;
};
buttonPublish.onCreateButton = function() {
button = $([
'<button class="btn" title="Publish this document">',
'<i class="icon-share"></i>',
'</button>'].join("")
).click(function() {
if(!$(this).hasClass("disabled")) {
publisher.publish();
}
});
return button;
};
buttonPublish.onPublishRunning = function(isRunning) {
publishRunning = isRunning;
updateButtonState();

View File

@ -10,6 +10,26 @@ define([
settingsBloc: '<p>Adds a "Share document" button in the navigation bar.</p>'
};
buttonShare.onCreateButton = function() {
return $([
'<button class="btn dropdown-toggle" data-toggle="dropdown" title="Share this document">',
'<i class="icon-link"></i>',
'</button>',
'<div id="link-container" class="dropdown-menu pull-right">',
'<div class="link-list"></div>',
'<p class="no-link">To share this document you need first to <a',
'href="#" class="action-publish-gist">publish it as a Gist</a> in',
'Markdown format.',
'</p>',
'<blockquote class="muted">',
'<b>NOTE:</b> You can open any URL within StackEdit using <a',
'href="viewer.html?url=https://raw.github.com/benweet/stackedit/master/README.md"',
'title="Sharing example">viewer.html?url=...</a>',
'</blockquote>',
'</div>'].join("")
);
};
var fileDesc = undefined;
var lineTemplate = [
'<div class="input-prepend">',

View File

@ -9,19 +9,43 @@ define([
settingsBloc: '<p>Adds a "Synchronize documents" button in the navigation bar.</p>'
};
var button = undefined;
var syncRunning = false;
var uploadPending = false;
var isOffline = false;
// Enable/disable the button
var updateButtonState = function() {
if(button === undefined) {
return;
}
if(syncRunning === true || uploadPending === false || isOffline) {
$(".action-force-sync").addClass("disabled");
button.addClass("disabled");
}
else {
$(".action-force-sync").removeClass("disabled");
button.removeClass("disabled");
}
};
var synchronizer = undefined;
buttonSync.onSynchronizerCreated = function(synchronizerParameter) {
synchronizer = synchronizerParameter;
};
buttonSync.onCreateButton = function() {
button = $([
'<button class="btn" title="Synchronize all documents">',
'<i class="icon-refresh"></i>',
'</button>'].join("")
).click(function() {
if(!$(this).hasClass("disabled")) {
synchronizer.forceSync();
}
});
return button;
};
buttonSync.onReady = updateButtonState;
buttonSync.onSyncRunning = function(isRunning) {
syncRunning = isRunning;
uploadPending = true;
@ -38,8 +62,6 @@ define([
updateButtonState();
};
buttonSync.onReady = updateButtonState;
// Check that a file has synchronized locations
var checkSynchronization = function(fileDesc) {
if(_.size(fileDesc.syncLocations) !== 0) {
@ -48,7 +70,7 @@ define([
}
};
buttonSync.onFileChanged = checkSynchronization;
buttonSync.onContentChanged = checkSynchronization;
buttonSync.onTitleChanged = checkSynchronization;
return buttonSync;

View File

@ -1,7 +1,8 @@
define([
"jquery",
"underscore"
], function($, _) {
"underscore",
"file-system"
], function($, _, fileSystem) {
var documentSelector = {
extensionId: "documentSelector",
@ -9,11 +10,6 @@ define([
settingsBloc: '<p>Builds the "Open document" dropdown menu.</p>'
};
var fileSystem = undefined;
documentSelector.onFileSystemCreated = function(fileSystemParameter) {
fileSystem = fileSystemParameter;
};
var fileMgr = undefined;
documentSelector.onFileMgrCreated = function(fileMgrParameter) {
fileMgr = fileMgrParameter;

View File

@ -37,11 +37,11 @@ define([
$(".msg-no-publish").removeClass("hide");
}
_.each(publishAttributesList, function(publishAttributes) {
publishAttributes = _.extend({}, publishAttributes);
if(publishAttributes.password) {
publishAttributes.password = "********";
formattedAttributes = _.omit(publishAttributes, "provider", "publishIndex", "sharingLink");
if(formattedAttributes.password) {
formattedAttributes.password = "********";
}
var publishDesc = JSON.stringify(publishAttributes).replace(/{|}|"/g, "");
var publishDesc = JSON.stringify(formattedAttributes).replace(/{|}|"/g, "").replace(/,/g, ", ");
var lineElement = $(_.template(lineTemplate, {
provider: publishAttributes.provider,
publishDesc: publishDesc

View File

@ -58,12 +58,12 @@ define([
}
notifications.onMessage = function(message) {
console.log(message);
logger.log(message);
showMessage(message);
};
notifications.onError = function(error) {
console.error(error);
logger.error(error);
if(_.isString(error)) {
showMessage(error, "icon-warning-sign");
}

View File

@ -10,14 +10,36 @@ define([
], function($, _, core, utils, settings, extensionMgr, fileSystem, welcomeContent) {
var fileMgr = {};
// Defines a file descriptor in the file system (fileDesc objects)
function FileDescriptor(fileIndex, title, syncLocations, publishLocations) {
this.fileIndex = fileIndex;
this.title = title;
this.syncLocations = syncLocations || {};
this.publishLocations = publishLocations || {};
}
FileDescriptor.prototype.getContent = function() {
return localStorage[this.fileIndex + ".content"];
};
FileDescriptor.prototype.setContent = function(content) {
localStorage[this.fileIndex + ".content"] = content;
extensionMgr.onContentChanged(this);
};
FileDescriptor.prototype.setTitle = function(title) {
this.title = title;
localStorage[this.fileIndex + ".title"] = title;
extensionMgr.onTitleChanged(this);
};
// Load file descriptors from localStorage
_.chain(
localStorage["file.list"].split(";")
).compact().each(function(fileIndex) {
fileSystem[fileIndex] = new FileDescriptor(fileIndex, localStorage[fileIndex + ".title"]);
});
// Defines the current file
var currentFile = (function() {
var fileIndex = localStorage["file.current"];
if(fileIndex !== undefined) {
return fileSystem[fileIndex];
}
})();
var currentFile = undefined;
fileMgr.getCurrentFile = function() {
return currentFile;
};
@ -34,7 +56,7 @@ define([
}
};
// Caution: this function recreate the editor (reset undo operations)
// Caution: this function recreates the editor (reset undo operations)
fileMgr.selectFile = function(fileDesc) {
fileDesc = fileDesc || fileMgr.getCurrentFile();
@ -44,26 +66,33 @@ define([
if (fileSystemSize === 0) {
fileDesc = fileMgr.createFile(WELCOME_DOCUMENT_TITLE, welcomeContent);
}
// If no file is selected take the last created
else {
fileDesc = fileSystem[_.keys(fileSystem)[fileSystemSize - 1]];
var fileIndex = localStorage["file.current"];
// If no file is selected take the last created
if(fileIndex === undefined) {
fileIndex = _.keys(fileSystem)[fileSystemSize - 1];
}
fileDesc = fileSystem[fileIndex];
}
}
fileMgr.setCurrentFile(fileDesc);
// Notify extensions
extensionMgr.onFileSelected(fileDesc);
// Hide the viewer pencil button
if(fileDesc.fileIndex == TEMPORARY_FILE_INDEX) {
$(".action-edit-document").removeClass("hide");
}
else {
$(".action-edit-document").addClass("hide");
if(fileMgr.isCurrentFile(fileDesc) === false) {
fileMgr.setCurrentFile(fileDesc);
// Notify extensions
extensionMgr.onFileSelected(fileDesc);
// Hide the viewer pencil button
if(fileDesc.fileIndex == TEMPORARY_FILE_INDEX) {
$(".action-edit-document").removeClass("hide");
}
else {
$(".action-edit-document").addClass("hide");
}
}
// Recreate the editor
$("#wmd-input").val(localStorage[fileDesc.fileIndex + ".content"]);
$("#wmd-input").val(fileDesc.getContent());
core.createEditor(function() {
// Callback to save content when textarea changes
fileMgr.saveFile();
@ -72,7 +101,6 @@ define([
fileMgr.createFile = function(title, content, syncLocations, isTemporary) {
content = content !== undefined ? content : settings.defaultContent;
syncLocations = syncLocations || {};
if (!title) {
// Create a file title
title = DEFAULT_FILE_TITLE;
@ -92,24 +120,19 @@ define([
} while(_.has(fileSystem, fileIndex));
}
// Create the file in the localStorage
localStorage[fileIndex + ".content"] = content;
localStorage[fileIndex + ".title"] = title;
// Store syncIndexes associated to the file
// syncIndex associations
syncLocations = syncLocations || {};
var sync = _.reduce(syncLocations, function(sync, syncAttributes, syncIndex) {
return sync + syncIndex + ";";
}, ";");
localStorage[fileIndex + ".title"] = title;
localStorage[fileIndex + ".content"] = content;
localStorage[fileIndex + ".sync"] = sync;
// Store publishIndexes associated to the file
localStorage[fileIndex + ".publish"] = ";";
// Create the file descriptor
var fileDesc = {
fileIndex : fileIndex,
title : title,
syncLocations: syncLocations,
publishLocations: {}
};
var fileDesc = new FileDescriptor(fileIndex, title, syncLocations);
// Add the index to the file list
if(!isTemporary) {
@ -122,9 +145,11 @@ define([
fileMgr.deleteFile = function(fileDesc) {
fileDesc = fileDesc || fileMgr.getCurrentFile();
if(fileMgr.isCurrentFile(fileDesc)) {
if(fileMgr.isCurrentFile(fileDesc) === true) {
// Unset the current fileDesc
fileMgr.setCurrentFile();
// Refresh the editor with an other file
fileMgr.selectFile();
}
// Remove synchronized locations
@ -141,10 +166,12 @@ define([
var fileIndex = fileDesc.fileIndex;
localStorage["file.list"] = localStorage["file.list"].replace(";"
+ fileIndex + ";", ";");
localStorage.removeItem(fileIndex + ".title");
localStorage.removeItem(fileIndex + ".content");
localStorage.removeItem(fileIndex + ".sync");
localStorage.removeItem(fileIndex + ".publish");
fileSystem.removeItem(fileIndex);
extensionMgr.onFileDeleted(fileDesc);
};
@ -153,8 +180,7 @@ define([
fileMgr.saveFile = function() {
var content = $("#wmd-input").val();
var fileDesc = fileMgr.getCurrentFile();
localStorage[fileDesc.fileIndex + ".content"] = content;
extensionMgr.onFileChanged(fileDesc);
fileDesc.setContent(content);
};
// Add a synchronized location to a file
@ -211,7 +237,7 @@ define([
// Remove a publishIndex (publish location)
fileMgr.removePublish = function(publishAttributes, skipExtensions) {
var fileDesc = fileMgr.getFileFromPublish(publishAttributes.publishIndex);
var fileDesc = fileMgr.getFileFromPublishIndex(publishAttributes.publishIndex);
if(fileDesc !== undefined) {
localStorage[fileDesc.fileIndex + ".publish"] = localStorage[fileDesc.fileIndex + ".publish"].replace(";"
+ publishAttributes.publishIndex + ";", ";");
@ -225,7 +251,7 @@ define([
};
// Get the file descriptor associated to a publishIndex
fileMgr.getFileFromPublish = function(publishIndex) {
fileMgr.getFileFromPublishIndex = function(publishIndex) {
return _.find(fileSystem, function(fileDesc) {
return _.has(fileDesc.publishLocations, publishIndex);
});
@ -263,7 +289,6 @@ define([
});
$(".action-remove-file").click(function() {
fileMgr.deleteFile();
fileMgr.selectFile();
});
$("#file-title").click(function() {
if(viewerMode === true) {
@ -280,15 +305,10 @@ define([
$("#file-title").show();
var title = $.trim(input.val());
var fileDesc = fileMgr.getCurrentFile();
var fileIndexTitle = fileDesc.fileIndex + ".title";
if (title) {
if (title != localStorage[fileIndexTitle]) {
localStorage[fileIndexTitle] = title;
fileDesc.title = title;
extensionMgr.onTitleChanged(fileDesc);
}
if (title && title != fileDesc.title) {
fileDesc.setTitle(title);
}
input.val(localStorage[fileIndexTitle]);
input.val(fileDesc.title);
$("#wmd-input").focus();
}
$("#file-title-input").blur(function() {

View File

@ -1,22 +1,3 @@
define([
"underscore",
"extension-manager"
], function(_, extensionMgr) {
var fileSystem = {};
// Load file descriptors from localStorage
_.chain(
localStorage["file.list"].split(";")
).compact().each(function(fileIndex) {
fileSystem[fileIndex] = {
fileIndex : fileIndex,
title : localStorage[fileIndex + ".title"],
syncLocations: {},
publishLocations: {}
};
});
extensionMgr.onFileSystemCreated(fileSystem);
return fileSystem;
});
// The fileSystem module is empty when created. It's filled by fileMgr when loading.
// syncLocations and publishLocations are respectively loaded by synchronizer and publisher.
define({});

View File

@ -28,6 +28,7 @@ define([
syncAttributes.contentCRC = utils.crc32(content);
syncAttributes.titleCRC = utils.crc32(title);
syncAttributes.syncIndex = createSyncIndex(id);
utils.storeAttributes(syncAttributes);
return syncAttributes;
}
@ -43,7 +44,6 @@ define([
var fileDescList = [];
_.each(result, function(file) {
var syncAttributes = createSyncAttributes(file.id, file.etag, file.content, file.title);
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
var syncLocations = {};
syncLocations[syncAttributes.syncIndex] = syncAttributes;
var fileDesc = fileMgr.createFile(file.title, file.content, syncLocations);
@ -82,7 +82,6 @@ define([
return;
}
var syncAttributes = createSyncAttributes(result.id, result.etag, content, title);
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
callback(undefined, syncAttributes);
});
};
@ -92,7 +91,7 @@ define([
if(!id) {
return;
}
// Check that file is not synchronized with an other one
// Check that file is not synchronized with another an existing document
var syncIndex = createSyncIndex(id);
var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
if(fileDesc !== undefined) {
@ -106,7 +105,6 @@ define([
return;
}
var syncAttributes = createSyncAttributes(result.id, result.etag, content, title);
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
callback(undefined, syncAttributes);
});
};
@ -178,7 +176,7 @@ define([
return;
}
var localTitleChanged = syncAttributes.titleCRC != utils.crc32(localTitle);
var localContent = localStorage[fileDesc.fileIndex + ".content"];
var localContent = fileDesc.getContent();
var localContentChanged = syncAttributes.contentCRC != utils.crc32(localContent);
var file = change.file;
var remoteTitleCRC = utils.crc32(file.title);
@ -190,20 +188,17 @@ define([
// Conflict detection
if ((fileTitleChanged === true && localTitleChanged === true && remoteTitleChanged === true)
|| (fileContentChanged === true && localContentChanged === true && remoteContentChanged === true)) {
var backupFileDesc = fileMgr.createFile(localTitle + " (backup)", localContent);
extensionMgr.onTitleChanged(backupFileDesc);
fileMgr.createFile(localTitle + " (backup)", localContent);
extensionMgr.onMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.');
}
// If file title changed
if(fileTitleChanged && remoteTitleChanged === true) {
localStorage[fileDesc.fileIndex + ".title"] = file.title;
fileDesc.title = file.title;
extensionMgr.onTitleChanged(fileDesc);
fileDesc.setTitle(file.title);
extensionMgr.onMessage('"' + localTitle + '" has been renamed to "' + file.title + '" on Google Drive.');
}
// If file content changed
if(fileContentChanged && remoteContentChanged === true) {
localStorage[fileDesc.fileIndex + ".content"] = file.content;
fileDesc.setContent(file.content);
extensionMgr.onMessage('"' + file.title + '" has been updated from Google Drive.');
if(fileMgr.isCurrentFile(fileDesc)) {
fileMgr.selectFile(); // Refresh editor
@ -213,7 +208,7 @@ define([
syncAttributes.etag = file.etag;
syncAttributes.contentCRC = remoteContentCRC;
syncAttributes.titleCRC = remoteTitleCRC;
localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
utils.storeAttributes(syncAttributes);
});
localStorage[PROVIDER_GDRIVE + ".lastChangeId"] = newChangeId;
callback();
@ -263,7 +258,6 @@ define([
return;
}
var syncAttributes = createSyncAttributes(file.id, file.etag, file.content, file.title);
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
var syncLocations = {};
syncLocations[syncAttributes.syncIndex] = syncAttributes;
var fileDesc = fileMgr.createFile(file.title, file.content, syncAttributes);

View File

@ -224,7 +224,7 @@ define([
function handleError(error, task) {
var errorMsg = undefined;
if (error) {
console.error(error);
logger.error(error);
// Try to analyze the error
if (typeof error === "string") {
errorMsg = error;

View File

@ -326,7 +326,7 @@ define([
function handleError(error, task) {
var errorMsg = undefined;
if (error) {
console.error(error);
logger.error(error);
// Try to analyze the error
if (typeof error === "string") {
errorMsg = error;

View File

@ -23,6 +23,20 @@ requirejs.config({
}
});
// Defines the logger object
var logger = {
debug: function() {},
log: function() {},
info: function() {},
warn: function() {},
error: function() {}
};
// Use http://.../?console to print logs in the console
if (location.search.indexOf("console") !== -1) {
logger = console;
}
// RequireJS entry point. By requiring synchronizer and publisher, we are actually loading all the modules
require([
"jquery",
"core",
@ -31,6 +45,7 @@ require([
], function($, core) {
$(function() {
// If browser has detected a new application cache.
if (window.applicationCache) {
window.applicationCache.addEventListener('updateready', function(e) {
@ -41,6 +56,7 @@ require([
}, false);
}
// Here, all the modules are loaded and the DOM is ready
core.setReady();
});

View File

@ -132,7 +132,7 @@ define([
publishIndex = "publish." + utils.randomString();
} while(_.has(localStorage, publishIndex));
publishAttributes.publishIndex = publishIndex;
localStorage[publishIndex] = utils.serializeAttributes(publishAttributes);
utils.storeAttributes(publishAttributes);
fileMgr.addPublish(fileDesc, publishAttributes);
}
@ -230,12 +230,6 @@ define([
$(".action-process-publish").click(performNewLocation);
$(".action-force-publish").click(function() {
if(!$(this).hasClass("disabled")) {
publisher.publish();
}
});
// Save As menu items
$(".action-download-md").click(function() {
var content = $("#wmd-input").val();

View File

@ -63,7 +63,7 @@ define([
function handleError(error, task) {
var errorMsg = undefined;
if (error) {
console.error(error);
logger.error(error);
// Try to analyze the error
if (typeof error === "string") {
errorMsg = "SSH error: " + error + ".";

View File

@ -73,7 +73,7 @@ define([
}
if(uploadFlag) {
// Update syncAttributes in localStorage
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
utils.storeAttributes(syncAttributes);
}
locationUp(callback);
}
@ -90,7 +90,7 @@ define([
return;
}
// Dequeue a fileDesc
// Dequeue a fileDesc to synchronize
var fileDesc = uploadFileList.pop();
uploadSyncAttributesList = _.values(fileDesc.syncLocations);
if(uploadSyncAttributesList.length === 0) {
@ -99,7 +99,7 @@ define([
}
// Get document title/content
uploadContent = localStorage[fileDesc.fileIndex + ".content"];
uploadContent = fileDesc.getContent();
uploadContentCRC = utils.crc32(uploadContent);
uploadTitle = fileDesc.title;
uploadTitleCRC = utils.crc32(uploadTitle);
@ -226,9 +226,7 @@ define([
// Perform the provider's export
var fileDesc = fileMgr.getCurrentFile();
var title = fileDesc.title;
var content = localStorage[fileDesc.fileIndex + ".content"];
provider.exportFile(event, title, content, function(error, syncAttributes) {
provider.exportFile(event, fileDesc.title, fileDesc.getContent(), function(error, syncAttributes) {
if(error) {
return;
}
@ -245,9 +243,7 @@ define([
// Provider's manual export button
$(".action-sync-manual-" + provider.providerId).click(function(event) {
var fileDesc = fileMgr.getCurrentFile();
var title = fileDesc.title;
var content = localStorage[fileDesc.fileIndex + ".content"];
provider.exportManual(event, title, content, function(error, syncAttributes) {
provider.exportManual(event, fileDesc.title, fileDesc.getContent(), function(error, syncAttributes) {
if(error) {
return;
}
@ -255,12 +251,6 @@ define([
});
});
});
$(".action-force-sync").click(function() {
if(!$(this).hasClass("disabled")) {
synchronizer.forceSync();
}
});
});
extensionMgr.onSynchronizerCreated(synchronizer);

View File

@ -143,7 +143,7 @@ define([
function handleError(error, task) {
var errorMsg = undefined;
if (error) {
console.error(error);
logger.error(error);
// Try to analyze the error
if (typeof error === "string") {
errorMsg = error;

View File

@ -298,13 +298,14 @@ define([
utils.updateCurrentTime();
// Serialize sync/publish attributes
utils.serializeAttributes = function(attributes) {
// Serialize sync/publish attributes and store it in the fileStorage
utils.storeAttributes = function(attributes) {
var storeIndex = attributes.syncIndex || attributes.publishIndex;
// Don't store sync/publish index
attributes = _.omit(attributes, "syncIndex", "publishIndex");
// Store providerId instead of provider
attributes.provider = attributes.provider.providerId;
return JSON.stringify(attributes);
localStorage[storeIndex] = JSON.stringify(attributes);
};
return utils;

View File

@ -141,7 +141,7 @@ define([
function handleError(error, task) {
var errorMsg = undefined;
if (error) {
console.error(error);
logger.error(error);
// Try to analyze the error
if (typeof error === "string") {
errorMsg = error;