Extension pattern

This commit is contained in:
benweet 2013-05-26 23:59:03 +01:00
parent 72334b2e54
commit a4c46085e4
11 changed files with 469 additions and 449 deletions

View File

@ -15,6 +15,7 @@ var ASYNC_TASK_DEFAULT_TIMEOUT = 60000;
var ASYNC_TASK_LONG_TIMEOUT = 120000; var ASYNC_TASK_LONG_TIMEOUT = 120000;
var SYNC_PERIOD = 180000; var SYNC_PERIOD = 180000;
var USER_IDLE_THRESHOLD = 300000; var USER_IDLE_THRESHOLD = 300000;
var TEMPORARY_FILE_INDEX = "file.tempIndex";
var WELCOME_DOCUMENT_TITLE = "Welcome document"; var WELCOME_DOCUMENT_TITLE = "Welcome document";
var DOWNLOAD_PROXY_URL = "http://stackedit-download-proxy.herokuapp.com/"; var DOWNLOAD_PROXY_URL = "http://stackedit-download-proxy.herokuapp.com/";
var WORDPRESS_CLIENT_ID = '3185'; var WORDPRESS_CLIENT_ID = '3185';

View File

@ -1,7 +1,16 @@
define( define([
[ "jquery", "utils", "extension-manager", "bootstrap", "layout", "Markdown.Editor", "storage", "config", "jquery",
"underscore", "FileSaver", "css_browser_selector" ], "utils",
function($, utils, extensionManager) { "extension-manager",
"bootstrap",
"layout",
"Markdown.Editor",
"storage",
"config",
"underscore",
"FileSaver",
"css_browser_selector"
], function($, utils, extensionManager) {
var core = {}; var core = {};
@ -159,11 +168,13 @@ define(
'</head>\n', '</head>\n',
'<body><%= documentHTML %></body>\n', '<body><%= documentHTML %></body>\n',
'</html>'].join(""), '</html>'].join(""),
sshProxy : SSH_PROXY_URL sshProxy : SSH_PROXY_URL,
extensionSettings: {}
}; };
if (_.has(localStorage, "settings")) { if (_.has(localStorage, "settings")) {
_.extend(core.settings, JSON.parse(localStorage.settings)); _.extend(core.settings, JSON.parse(localStorage.settings));
} }
extensionManager.init(core.settings.extensionSettings);
core.loadSettings = function() { core.loadSettings = function() {
@ -271,13 +282,7 @@ define(
layout.allowOverflow('north'); layout.allowOverflow('north');
}); });
extensionManager.onLayoutCreated(); extensionManager.onLayoutCreated(layout);
};
core.layoutRefresh = function() {
if(layout !== undefined) {
// Use defer to make sure UI has been updated
_.defer(layout.resizeAll);
}
}; };
// Create the PageDown editor // Create the PageDown editor
@ -413,9 +418,7 @@ define(
runReadyCallbacks(); runReadyCallbacks();
}); });
core.onReady(function() { core.onReady(extensionManager.onReady);
extensionManager.init(core.settings.extensionSettings);
});
core.onReady(function() { core.onReady(function() {
// Load theme list // Load theme list

View File

@ -1,12 +1,11 @@
define(["core", "utils", "dropbox-helper"], function(core, utils, dropboxHelper) { define(["core", "utils", "extension-manager", "dropbox-helper"], function(core, utils, extensionManager, dropboxHelper) {
var PROVIDER_DROPBOX = "dropbox"; var PROVIDER_DROPBOX = "dropbox";
var dropboxProvider = { var dropboxProvider = {
providerId: PROVIDER_DROPBOX, providerId: PROVIDER_DROPBOX,
providerName: "Dropbox", providerName: "Dropbox",
defaultPublishFormat: "template", defaultPublishFormat: "template"
useSync: false
}; };
function checkPath(path) { function checkPath(path) {
@ -23,19 +22,20 @@ define(["core", "utils", "dropbox-helper"], function(core, utils, dropboxHelper)
return path; return path;
} }
function createSyncIndex(path) {
return "sync." + PROVIDER_DROPBOX + "." + encodeURIComponent(path.toLowerCase());
}
function createSyncAttributes(path, versionTag, content) { function createSyncAttributes(path, versionTag, content) {
var syncAttributes = {}; var syncAttributes = {};
syncAttributes.provider = PROVIDER_DROPBOX; syncAttributes.provider = dropboxProvider;
syncAttributes.path = path; syncAttributes.path = path;
syncAttributes.version = versionTag; syncAttributes.version = versionTag;
syncAttributes.contentCRC = utils.crc32(content); syncAttributes.contentCRC = utils.crc32(content);
syncAttributes.syncIndex = createSyncIndex(path);
return syncAttributes; return syncAttributes;
} }
function createSyncIndex(path) {
return "sync." + PROVIDER_DROPBOX + "." + encodeURIComponent(path.toLowerCase());
}
function importFilesFromPaths(paths) { function importFilesFromPaths(paths) {
dropboxHelper.downloadMetadata(paths, function(error, result) { dropboxHelper.downloadMetadata(paths, function(error, result) {
if(error) { if(error) {
@ -45,16 +45,17 @@ define(["core", "utils", "dropbox-helper"], function(core, utils, dropboxHelper)
if(error) { if(error) {
return; return;
} }
var titleList = []; var fileDescList = [];
_.each(result, function(file) { _.each(result, function(file) {
var syncAttributes = createSyncAttributes(file.path, file.versionTag, file.content); var syncAttributes = createSyncAttributes(file.path, file.versionTag, file.content);
var syncIndex = createSyncIndex(syncAttributes.path); localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
localStorage[syncIndex] = JSON.stringify(syncAttributes); var syncLocations = {};
var fileIndex = core.fileManager.createFile(file.name, file.content, [syncIndex]); syncLocations[syncAttributes.syncIndex] = syncAttributes;
core.fileManager.selectFile(fileIndex); var fileDesc = core.fileManager.createFile(file.name, file.content, syncLocations);
titleList.push('"' + file.name + '"'); core.fileManager.selectFile(fileDesc);
fileDescList.push(fileDesc);
}); });
core.showMessage(titleList.join(", ") + ' imported successfully from Dropbox.'); extensionManager.onSyncImportSuccess(fileDescList, dropboxProvider);
}); });
}); });
} }
@ -67,10 +68,9 @@ define(["core", "utils", "dropbox-helper"], function(core, utils, dropboxHelper)
var importPaths = []; var importPaths = [];
_.each(paths, function(path) { _.each(paths, function(path) {
var syncIndex = createSyncIndex(path); var syncIndex = createSyncIndex(path);
var fileIndex = core.fileManager.getFileIndexFromSync(syncIndex); var fileDesc = core.fileManager.getFileFromSync(syncIndex);
if(fileIndex !== undefined) { if(fileDesc !== undefined) {
var title = localStorage[fileIndex + ".title"]; core.showError('"' + fileDesc.title + '" was already imported');
core.showError('"' + title + '" was already imported');
return; return;
} }
importPaths.push(path); importPaths.push(path);
@ -87,9 +87,9 @@ define(["core", "utils", "dropbox-helper"], function(core, utils, dropboxHelper)
} }
// Check that file is not synchronized with an other one // Check that file is not synchronized with an other one
var syncIndex = createSyncIndex(path); var syncIndex = createSyncIndex(path);
var fileIndex = core.fileManager.getFileIndexFromSync(syncIndex); var fileDesc = core.fileManager.getFileFromSync(syncIndex);
if(fileIndex !== undefined) { if(fileDesc !== undefined) {
var existingTitle = localStorage[fileIndex + ".title"]; var existingTitle = fileDesc.title;
core.showError('File path is already synchronized with "' + existingTitle + '"'); core.showError('File path is already synchronized with "' + existingTitle + '"');
callback(true); callback(true);
return; return;
@ -100,9 +100,8 @@ define(["core", "utils", "dropbox-helper"], function(core, utils, dropboxHelper)
return; return;
} }
var syncAttributes = createSyncAttributes(result.path, result.versionTag, content); var syncAttributes = createSyncAttributes(result.path, result.versionTag, content);
var syncIndex = createSyncIndex(syncAttributes.path); localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
localStorage[syncIndex] = JSON.stringify(syncAttributes); callback(undefined, syncIndex, syncAttributes);
callback(undefined, syncIndex);
}); });
} }
@ -135,10 +134,6 @@ define(["core", "utils", "dropbox-helper"], function(core, utils, dropboxHelper)
}; };
dropboxProvider.syncDown = function(callback) { dropboxProvider.syncDown = function(callback) {
if (dropboxProvider.useSync === false) {
callback();
return;
}
var lastChangeId = localStorage[PROVIDER_DROPBOX + ".lastChangeId"]; var lastChangeId = localStorage[PROVIDER_DROPBOX + ".lastChangeId"];
dropboxHelper.checkChanges(lastChangeId, function(error, changes, newChangeId) { dropboxHelper.checkChanges(lastChangeId, function(error, changes, newChangeId) {
if (error) { if (error) {
@ -148,23 +143,20 @@ define(["core", "utils", "dropbox-helper"], function(core, utils, dropboxHelper)
var interestingChanges = []; var interestingChanges = [];
_.each(changes, function(change) { _.each(changes, function(change) {
var syncIndex = createSyncIndex(change.path); var syncIndex = createSyncIndex(change.path);
var serializedAttributes = localStorage[syncIndex]; var syncAttributes = core.fileManager.getSyncAttributes(syncIndex);
if(serializedAttributes === undefined) { if(syncAttributes === undefined) {
return; return;
} }
// Store syncIndex to avoid 2 times formating // Store syncAttributes to avoid 2 times searching
change.syncIndex = syncIndex; change.syncAttributes = syncAttributes;
// Delete // Delete
if(change.wasRemoved === true) { if(change.wasRemoved === true) {
interestingChanges.push(change); interestingChanges.push(change);
return; return;
} }
// Modify // Modify
var syncAttributes = JSON.parse(serializedAttributes);
if(syncAttributes.version != change.stat.versionTag) { if(syncAttributes.version != change.stat.versionTag) {
interestingChanges.push(change); interestingChanges.push(change);
// Store syncAttributes to avoid 2 times parsing
change.syncAttributes = syncAttributes;
} }
}); });
dropboxHelper.downloadContent(interestingChanges, function(error, changes) { dropboxHelper.downloadContent(interestingChanges, function(error, changes) {
@ -174,23 +166,21 @@ define(["core", "utils", "dropbox-helper"], function(core, utils, dropboxHelper)
} }
var updateFileTitles = false; var updateFileTitles = false;
_.each(changes, function(change) { _.each(changes, function(change) {
var syncIndex = change.syncIndex; var syncAttributes = change.syncAttributes;
var fileIndex = core.fileManager.getFileIndexFromSync(syncIndex); var syncIndex = syncAttributes.syncIndex;
var fileDesc = core.fileManager.getFileFromSync(syncIndex);
// No file corresponding (file may have been deleted locally) // No file corresponding (file may have been deleted locally)
if(fileIndex === undefined) { if(fileDesc === undefined) {
core.fileManager.removeSync(syncIndex);
return; return;
} }
var localTitle = localStorage[fileIndex + ".title"]; var localTitle = fileDesc.title;
// File deleted // File deleted
if (change.wasRemoved === true) { if (change.wasRemoved === true) {
core.showError('"' + localTitle + '" has been removed from Dropbox.');
core.fileManager.removeSync(syncIndex); core.fileManager.removeSync(syncIndex);
updateFileTitles = true;
core.showMessage('"' + localTitle + '" has been removed from Dropbox.');
return; return;
} }
var syncAttributes = change.syncAttributes; var localContent = localStorage[fileDesc.index + ".content"];
var localContent = localStorage[fileIndex + ".content"];
var localContentChanged = syncAttributes.contentCRC != utils.crc32(localContent); var localContentChanged = syncAttributes.contentCRC != utils.crc32(localContent);
var file = change.stat; var file = change.stat;
var remoteContentCRC = utils.crc32(file.content); var remoteContentCRC = utils.crc32(file.content);
@ -204,9 +194,9 @@ define(["core", "utils", "dropbox-helper"], function(core, utils, dropboxHelper)
} }
// If file content changed // If file content changed
if(fileContentChanged && remoteContentChanged === true) { if(fileContentChanged && remoteContentChanged === true) {
localStorage[fileIndex + ".content"] = file.content; localStorage[fileDesc.index + ".content"] = file.content;
core.showMessage('"' + localTitle + '" has been updated from Dropbox.'); core.showMessage('"' + localTitle + '" has been updated from Dropbox.');
if(core.fileManager.isCurrentFileIndex(fileIndex)) { if(core.fileManager.isCurrentFile(fileDesc)) {
updateFileTitles = false; // Done by next function updateFileTitles = false; // Done by next function
core.fileManager.selectFile(); // Refresh editor core.fileManager.selectFile(); // Refresh editor
} }
@ -214,10 +204,10 @@ define(["core", "utils", "dropbox-helper"], function(core, utils, dropboxHelper)
// Update syncAttributes // Update syncAttributes
syncAttributes.version = file.versionTag; syncAttributes.version = file.versionTag;
syncAttributes.contentCRC = remoteContentCRC; syncAttributes.contentCRC = remoteContentCRC;
localStorage[syncIndex] = JSON.stringify(syncAttributes); localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
}); });
if(updateFileTitles) { if(updateFileTitles) {
core.fileManager.updateFileTitles(); extensionManager.onTitleChanged();
} }
localStorage[PROVIDER_DROPBOX + ".lastChangeId"] = newChangeId; localStorage[PROVIDER_DROPBOX + ".lastChangeId"] = newChangeId;
callback(); callback();

View File

@ -12,24 +12,25 @@ define( [
var extensionManager = {}; var extensionManager = {};
// Create a map with providerId: providerObject // Create a list of extensions
var extensionList = _.chain(arguments) var extensionList = _.chain(arguments)
.map(function(argument) { .map(function(argument) {
return _.isObject(argument) && argument.extensionId && argument; return _.isObject(argument) && argument.extensionId && argument;
}).compact().value(); }).compact().value();
// Return every named callbacks implemented in extensions // Return every named callbacks implemented in extensions
function getExtensionCallbackList(callbackName) { function getExtensionCallbackList(hookName) {
return _.chain(extensionList) return _.chain(extensionList)
.map(function(extension) { .map(function(extension) {
return extension.config.enabled && extension[callbackName]; return extension.config.enabled && extension[hookName];
}).compact().value(); }).compact().value();
} }
// Return a function that calls every callbacks from extensions // Return a function that calls every callbacks from extensions
function createCallback(callbackName) { function createHook(hookName) {
var callbackList = getExtensionCallbackList(callbackName); var callbackList = getExtensionCallbackList(hookName);
return function() { return function() {
console.debug(hookName);
var callbackArguments = arguments; var callbackArguments = arguments;
_.each(callbackList, function(callback) { _.each(callbackList, function(callback) {
callback.apply(null, callbackArguments); callback.apply(null, callbackArguments);
@ -37,9 +38,9 @@ define( [
}; };
} }
// Add a callback to the extensionManager // Add a Hook to the extensionManager
function addCallback(callbackName) { function addHook(hookName) {
extensionManager[callbackName] = createCallback(callbackName); extensionManager[hookName] = createHook(hookName);
} }
var accordionTmpl = [ var accordionTmpl = [
@ -75,12 +76,9 @@ define( [
extension.config.enabled = !extension.optional || extension.config.enabled === undefined || extension.config.enabled === true; extension.config.enabled = !extension.optional || extension.config.enabled === undefined || extension.config.enabled === true;
}); });
// Create accordion in settings dialog
_.each(extensionList, createSettings);
// Load/Save extension config from/to settings // Load/Save extension config from/to settings
addCallback("onLoadSettings");
extensionManager["onLoadSettings"] = function() { extensionManager["onLoadSettings"] = function() {
console.debug("onLoadSettings");
_.each(extensionList, function(extension) { _.each(extensionList, function(extension) {
utils.setInputChecked("#input-enable-extension-" + extension.extensionId, extension.config.enabled); utils.setInputChecked("#input-enable-extension-" + extension.extensionId, extension.config.enabled);
var onLoadSettingsCallback = extension.onLoadSettings; var onLoadSettingsCallback = extension.onLoadSettings;
@ -88,6 +86,7 @@ define( [
}); });
}; };
extensionManager["onSaveSettings"] = function(newExtensionSettings, event) { extensionManager["onSaveSettings"] = function(newExtensionSettings, event) {
console.debug("onSaveSettings");
_.each(extensionList, function(extension) { _.each(extensionList, function(extension) {
var newExtensionConfig = extension.defaultConfig || {}; var newExtensionConfig = extension.defaultConfig || {};
newExtensionConfig.enabled = utils.getInputChecked("#input-enable-extension-" + extension.extensionId); newExtensionConfig.enabled = utils.getInputChecked("#input-enable-extension-" + extension.extensionId);
@ -97,16 +96,40 @@ define( [
}); });
}; };
addCallback("onMessage"); addHook("onMessage");
addCallback("onError"); addHook("onError");
addCallback("onOfflineChanged"); addHook("onOfflineChanged");
addCallback("onLayoutConfigure");
addCallback("onLayoutCreated");
addCallback("onEditorConfigure");
var onPreviewFinished = createCallback("onPreviewFinished"); // To store reference to modules that are accessible from extensions
addHook("onFileManagerCreated");
addHook("onSynchronizerCreated");
addHook("onPublisherCreated");
// Operations on files
addHook("onFileSystemLoaded");
addHook("onFileCreated");
addHook("onFileDeleted");
addHook("onFileChanged");
addHook("onFileSelected");
addHook("onTitleChanged");
addHook("onSyncImportSuccess");
addHook("onSyncExportSuccess");
addHook("onSyncRemoved");
addHook("onPublishSuccess");
addHook("onNewPublishSuccess");
addHook("onPublishRemoved");
// Operations on Layout
addHook("onLayoutConfigure");
addHook("onLayoutCreated");
// Operations on PageDown
addHook("onEditorConfigure");
var onPreviewFinished = createHook("onPreviewFinished");
var onAsyncPreviewCallbackList = getExtensionCallbackList("onAsyncPreview"); var onAsyncPreviewCallbackList = getExtensionCallbackList("onAsyncPreview");
extensionManager["onAsyncPreview"] = function() { extensionManager["onAsyncPreview"] = function() {
console.debug("onAsyncPreview");
// Call onPreviewFinished callbacks when all async preview are finished // Call onPreviewFinished callbacks when all async preview are finished
var counter = 0; var counter = 0;
function tryFinished() { function tryFinished() {
@ -124,7 +147,14 @@ define( [
}; };
// Call onReady callbacks // Call onReady callbacks
createCallback("onReady")(); var onReady = createHook("onReady");
extensionManager["onReady"] = function() {
// Create accordion in settings dialog
_.each(extensionList, createSettings);
onReady();
};
}; };
return extensionManager; return extensionManager;

View File

@ -55,5 +55,35 @@ define( [ "jquery", "jgrowl", "underscore" ], function($) {
} }
}; };
notifications.onSyncImportSuccess = function(fileDescList, provider) {
if(!fileDescList) {
return;
}
var titles = _.map(fileDescList, function(fileDesc) {
return fileDesc.title;
}).join(", ");
showMessage(titles + ' imported successfully from ' + provider.providerName + '.');
};
notifications.onSyncExportSuccess = function(fileDesc, syncAttributes) {
showMessage('"' + fileDesc.title + '" will now be synchronized on ' + syncAttributes.provider.providerName + '.');
};
notifications.onSyncRemoved = function(fileDesc, syncAttributes) {
showMessage(syncAttributes.provider.providerName + " synchronized location has been removed.");
};
notifications.onPublishSuccess = function(fileDesc) {
showMessage('"' + fileDesc.title + '" successfully published.');
};
notifications.onNewPublishSuccess = function(fileDesc, publishIndex, publishAttributes) {
showMessage('"' + fileDesc.title + '" is now published on ' + publishAttributes.provider.providerName + '.');
};
notifications.onPublishRemoved = function(fileDesc, publishAttributes) {
showMessage(publishAttributes.provider.providerName + " publish location has been removed.");
};
return notifications; return notifications;
}); });

View File

@ -1,47 +1,84 @@
define(["jquery", "core", "utils", "synchronizer", "publisher", "sharing", "text!../WELCOME.md", "underscore"], define([
function($, core, utils, synchronizer, publisher, sharing, welcomeContent) { "jquery",
"core",
var TEMPORARY_FILE_INDEX = "file.tempIndex"; "utils",
"extension-manager",
"synchronizer",
"publisher",
"sharing",
"text!../WELCOME.md",
"underscore"
], function($, core, utils, extensionManager, synchronizer, publisher, sharing, welcomeContent) {
var fileManager = {}; var fileManager = {};
// Load file descriptors from localStorage and store in a map
var fileSystemDescriptor = _.chain(localStorage["file.list"].split(";"))
.compact()
.reduce(function(fileSystemDescriptor, fileIndex) {
var title = localStorage[fileIndex + ".title"];
var fileDesc = {
index : fileIndex,
title : title,
syncLocations: {},
publishLocations: {}
};
synchronizer.populateSyncLocations(fileDesc),
publisher.populatePublishLocations(fileDesc),
fileSystemDescriptor[fileIndex] = fileDesc;
return fileSystemDescriptor;
}, {})
.value();
extensionManager.onFileSystemLoaded(fileSystemDescriptor);
fileManager.getFileList = function() {
return _.values(fileSystemDescriptor);
};
// Defines the current file // Defines the current file
var currentFile = (function() {
var currentFileIndex = localStorage["file.current"]; var currentFileIndex = localStorage["file.current"];
fileManager.getCurrentFileIndex = function() { if(currentFileIndex !== undefined) {
return currentFileIndex; return fileSystemDescriptor[currentFileIndex];
}
})();
fileManager.getCurrentFile = function() {
return currentFile;
}; };
fileManager.isCurrentFileIndex = function(fileIndex) { fileManager.isCurrentFile = function(fileDesc) {
return fileIndex == currentFileIndex; return fileDesc === currentFile;
}; };
fileManager.setCurrentFileIndex = function(fileIndex) { fileManager.setCurrentFile = function(fileDesc) {
currentFileIndex = fileIndex; currentFile = fileDesc;
if(fileIndex === undefined) { if(fileDesc === undefined) {
localStorage.removeItem("file.current"); localStorage.removeItem("file.current");
} }
else if(fileIndex != TEMPORARY_FILE_INDEX) { else if(fileDesc.index != TEMPORARY_FILE_INDEX) {
localStorage["file.current"] = fileIndex; localStorage["file.current"] = fileDesc.index;
} }
}; };
// Caution: this function recreate the editor (reset undo operations) // Caution: this function recreate the editor (reset undo operations)
var fileDescList = []; fileManager.selectFile = function(fileDesc) {
fileManager.selectFile = function(fileIndex) {
// If no file create one // If no file create one
if (localStorage["file.list"].length === 1) { if (_.size(fileSystemDescriptor) === 0) {
fileIndex = fileManager.createFile(WELCOME_DOCUMENT_TITLE, welcomeContent); fileDesc = fileManager.createFile(WELCOME_DOCUMENT_TITLE, welcomeContent);
} }
if(fileIndex !== undefined) { if(fileDesc === undefined) {
fileManager.setCurrentFileIndex(fileIndex); // If no file is selected take the last created
fileDesc = fileSystemDescriptor[_.keys(fileSystemDescriptor)[fileSystemDescriptor.length - 1]];
} }
fileManager.setCurrentFile(fileDesc);
// Update the file titles // Update the file titles
fileManager.updateFileTitles(); fileManager.updateFileTitles();
synchronizer.refreshManageSync();
publisher.notifyPublish(); publisher.notifyPublish();
// Notify extensions
extensionManager.onFileSelected(fileDesc);
// Hide the viewer pencil button // Hide the viewer pencil button
if(fileIndex == TEMPORARY_FILE_INDEX) { if(fileDesc.index == TEMPORARY_FILE_INDEX) {
$(".action-edit-document").removeClass("hide"); $(".action-edit-document").removeClass("hide");
} }
else { else {
@ -49,22 +86,21 @@ define(["jquery", "core", "utils", "synchronizer", "publisher", "sharing", "text
} }
// Recreate the editor // Recreate the editor
fileIndex = fileManager.getCurrentFileIndex(); $("#wmd-input").val(localStorage[fileDesc.index + ".content"]);
$("#wmd-input").val(localStorage[fileIndex + ".content"]);
core.createEditor(function() { core.createEditor(function() {
// Callback to save content when textarea changes // Callback to save content when textarea changes
fileManager.saveFile(); fileManager.saveFile();
}); });
}; };
fileManager.createFile = function(title, content, syncIndexes, isTemporary) { fileManager.createFile = function(title, content, syncLocations, isTemporary) {
content = content !== undefined ? content : core.settings.defaultContent; content = content !== undefined ? content : core.settings.defaultContent;
syncIndexes = syncIndexes || []; syncLocations = syncLocations || {};
if (!title) { if (!title) {
// Create a file title // Create a file title
title = DEFAULT_FILE_TITLE; title = DEFAULT_FILE_TITLE;
var indicator = 2; var indicator = 2;
while(_.some(fileDescList, function(fileDesc) { while(_.some(fileSystemDescriptor, function(fileDesc) {
return fileDesc.title == title; return fileDesc.title == title;
})) { })) {
title = DEFAULT_FILE_TITLE + indicator++; title = DEFAULT_FILE_TITLE + indicator++;
@ -76,170 +112,152 @@ define(["jquery", "core", "utils", "synchronizer", "publisher", "sharing", "text
if(!isTemporary) { if(!isTemporary) {
do { do {
fileIndex = "file." + utils.randomString(); fileIndex = "file." + utils.randomString();
} while(_.has(localStorage, fileIndex + ".title")); } while(_.has(fileSystemDescriptor, fileIndex));
} }
// Create the file in the localStorage // Create the file in the localStorage
localStorage[fileIndex + ".content"] = content; localStorage[fileIndex + ".content"] = content;
localStorage[fileIndex + ".title"] = title; localStorage[fileIndex + ".title"] = title;
// Store syncIndexes associated to the file // Store syncIndexes associated to the file
var sync = _.reduce(syncIndexes, function(sync, syncIndex) { var sync = _.reduce(syncLocations, function(sync, syncAttributes, syncIndex) {
return sync + syncIndex + ";"; return sync + syncIndex + ";";
}, ";"); }, ";");
localStorage[fileIndex + ".sync"] = sync; localStorage[fileIndex + ".sync"] = sync;
// Store publishIndexes associated to the file // Store publishIndexes associated to the file
localStorage[fileIndex + ".publish"] = ";"; localStorage[fileIndex + ".publish"] = ";";
// Create the file descriptor
var fileDesc = {
index : fileIndex,
title : title,
syncLocations: syncLocations,
publishLocations: {}
};
// Add the index to the file list // Add the index to the file list
if(!isTemporary) { if(!isTemporary) {
localStorage["file.list"] += fileIndex + ";"; localStorage["file.list"] += fileIndex + ";";
fileSystemDescriptor[fileIndex] = fileDesc;
extensionManager.onFileCreated(fileDesc);
} }
return fileIndex; return fileDesc;
}; };
fileManager.deleteFile = function(fileIndex) { fileManager.deleteFile = function(fileDesc) {
fileIndex = fileIndex || fileManager.getCurrentFileIndex(); fileDesc = fileDesc || fileManager.getCurrentFile();
if(fileManager.isCurrentFileIndex(fileIndex)) { if(fileManager.isCurrentFile(fileDesc)) {
// Unset the current fileIndex // Unset the current fileDesc
fileManager.setCurrentFileIndex(); fileManager.setCurrentFile();
} }
// Remove synchronized locations // Remove synchronized locations
var syncIndexList = _.compact(localStorage[fileIndex + ".sync"].split(";")); _.each(fileDesc.syncLocations, function(syncAttributes, syncIndex) {
_.each(syncIndexList, function(syncIndex) { fileManager.removeSync(syncIndex, true);
fileManager.removeSync(syncIndex);
}); });
// Remove publish locations // Remove publish locations
var publishIndexList = _.compact(localStorage[fileIndex + ".publish"].split(";")); _.each(fileDesc.publishLocations, function(publishAttributes, publishIndex) {
_.each(publishIndexList, function(publishIndex) {
fileManager.removePublish(publishIndex); fileManager.removePublish(publishIndex);
}); });
// Remove the index from the file list // Remove the index from the file list
var fileIndex = fileDesc.index;
localStorage["file.list"] = localStorage["file.list"].replace(";" localStorage["file.list"] = localStorage["file.list"].replace(";"
+ fileIndex + ";", ";"); + fileIndex + ";", ";");
localStorage.removeItem(fileIndex + ".title"); localStorage.removeItem(fileIndex + ".title");
localStorage.removeItem(fileIndex + ".content"); localStorage.removeItem(fileIndex + ".content");
localStorage.removeItem(fileIndex + ".sync"); localStorage.removeItem(fileIndex + ".sync");
localStorage.removeItem(fileIndex + ".publish"); localStorage.removeItem(fileIndex + ".publish");
fileSystemDescriptor.removeItem(fileIndex);
extensionManager.onFileDeleted(fileDesc);
}; };
// Save current file in localStorage // Save current file in localStorage
fileManager.saveFile = function() { fileManager.saveFile = function() {
var content = $("#wmd-input").val(); var content = $("#wmd-input").val();
var fileIndex = fileManager.getCurrentFileIndex(); var fileDesc = fileManager.getCurrentFile();
localStorage[fileIndex + ".content"] = content; localStorage[fileDesc.index + ".content"] = content;
synchronizer.notifyChange(fileIndex); extensionManager.onFileChanged(fileDesc);
synchronizer.notifyChange(fileDesc);
}; };
fileManager.updateFileTitles = function() { // Add a syncIndex (synchronized location) to a file
fileDescList = _.chain(localStorage["file.list"].split(";")).compact() fileManager.addSync = function(fileDesc, syncIndex, syncAttributes) {
.reduce(function(fileDescList, fileIndex) { localStorage[fileDesc.index + ".sync"] += syncIndex + ";";
var title = localStorage[fileIndex + ".title"]; fileDesc.syncLocations[syncIndex] = syncAttributes;
fileDescList.push({ index : fileIndex, title : title }); // addSync is only used for export, not for import
return fileDescList; extensionManager.onSyncExportSuccess(fileDesc, syncIndex, syncAttributes);
}, [])
.sortBy(function(fileDesc) {
return fileDesc.title.toLowerCase();
}).value();
var fileIndex = fileManager.getCurrentFileIndex();
// If no default file take first one
if (fileIndex === undefined) {
fileIndex = fileDescList[0].index;
fileManager.setCurrentFileIndex(fileIndex);
}
synchronizer.resetSyncFlags();
function composeTitle(fileIndex, refreshSharing) {
var result = [];
var syncAttributesList = synchronizer.getSyncAttributesFromFile(fileIndex);
var publishAttributesList = publisher.getPublishAttributesFromFile(fileIndex);
var attributesList = syncAttributesList.concat(publishAttributesList);
if(refreshSharing === true) {
sharing.refreshDocumentSharing(attributesList);
}
_.chain(attributesList).sortBy(function(attributes) {
return attributes.provider;
}).each(function(attributes) {
result.push('<i class="icon-' + attributes.provider + '"></i>');
});
result.push(" ");
result.push(localStorage[fileIndex + ".title"]);
return result.join("");
}
// Update the file title
var title = localStorage[fileIndex + ".title"];
document.title = "StackEdit - " + title;
$("#file-title").html(composeTitle(fileIndex, true));
$(".file-title").text(title);
$("#file-title-input").val(title);
// Update the file selector
$("#file-selector li:not(.stick)").empty();
_.each(fileDescList, function(fileDesc) {
var a = $("<a>").html(composeTitle(fileDesc.index));
var li = $("<li>").append(a);
if (fileDesc.index == fileIndex) {
li.addClass("disabled");
} else {
a.prop("href", "#").click((function(fileIndex) {
return function() {
fileManager.selectFile(fileIndex);
};
})(fileDesc.index));
}
$("#file-selector").append(li);
});
core.layoutRefresh();
}; };
// Remove a syncIndex (synchronized location) // Remove a syncIndex (synchronized location)
fileManager.removeSync = function(syncIndex) { fileManager.removeSync = function(syncIndex, skipExtensions) {
var fileIndex = fileManager.getFileIndexFromSync(syncIndex); var fileDesc = fileManager.getFileFromSync(syncIndex);
if(fileIndex !== undefined) { if(fileDesc !== undefined) {
localStorage[fileIndex + ".sync"] = localStorage[fileIndex + ".sync"].replace(";" localStorage[fileDesc.index + ".sync"] = localStorage[fileDesc.index + ".sync"].replace(";"
+ syncIndex + ";", ";"); + syncIndex + ";", ";");
if(fileManager.isCurrentFileIndex(fileIndex)) {
synchronizer.refreshManageSync();
}
} }
// Remove sync attributes // Remove sync attributes
localStorage.removeItem(syncIndex); localStorage.removeItem(syncIndex);
var syncAttributes = fileDesc.syncLocations[syncIndex];
fileDesc.syncLocations.removeItem(syncIndex);
if(!skipExtensions) {
extensionManager.onSyncRemoved(fileDesc, syncAttributes);
}
}; };
// Get the fileIndex associated to a syncIndex // Get the file descriptor associated to a syncIndex
fileManager.getFileIndexFromSync = function(syncIndex) { fileManager.getFileFromSync = function(syncIndex) {
return _.chain(localStorage["file.list"].split(";")).compact() return _.find(fileSystemDescriptor, function(fileDesc) {
.find(function(fileIndex) { return _.has(fileDesc.syncLocations, syncIndex);
var sync = localStorage[fileIndex + ".sync"]; });
return sync.indexOf(";" + syncIndex + ";") !== -1; };
}).value();
// Get syncAttributes from syncIndex
fileManager.getSyncAttributes = function(syncIndex) {
var fileDesc = fileManager.getFileFromSync(syncIndex);
return fileDesc && fileDesc.syncLocations[syncIndex];
};
// Returns true if provider has locations to synchronize
fileManager.hasSync = function(provider) {
return _.some(fileSystemDescriptor, function(fileDesc) {
return _.some(fileDesc.syncLocations, function(syncAttributes) {
syncAttributes.provider == provider.providerId;
});
});
};
// Add a publishIndex (publish location) to a file
fileManager.addPublish = function(fileDesc, publishIndex, publishAttributes) {
localStorage[fileDesc.index + ".publish"] += publishIndex + ";";
fileDesc.publishLocations[publishIndex] = publishAttributes;
extensionManager.onNewPublishSuccess(fileDesc, publishIndex, publishAttributes);
}; };
// Remove a publishIndex (publish location) // Remove a publishIndex (publish location)
fileManager.removePublish = function(publishIndex) { fileManager.removePublish = function(publishIndex, skipExtensions) {
var fileIndex = fileManager.getFileIndexFromPublish(publishIndex); var fileDesc = fileManager.getFileFromPublish(publishIndex);
if(fileIndex !== undefined) { if(fileDesc !== undefined) {
localStorage[fileIndex + ".publish"] = localStorage[fileIndex + ".publish"].replace(";" localStorage[fileDesc.index + ".publish"] = localStorage[fileDesc.index + ".publish"].replace(";"
+ publishIndex + ";", ";"); + publishIndex + ";", ";");
if(fileManager.isCurrentFileIndex(fileIndex)) { if(fileManager.isCurrentFile(fileDesc)) {
publisher.notifyPublish(); publisher.notifyPublish();
} }
} }
// Remove publish attributes // Remove publish attributes
localStorage.removeItem(publishIndex); localStorage.removeItem(publishIndex);
var publishAttributes = fileDesc.publishLocations[publishIndex];
fileDesc.publishLocations.removeItem(publishIndex);
if(!skipExtensions) {
extensionManager.onPublishRemoved(fileDesc, publishAttributes);
}
}; };
// Get the fileIndex associated to a publishIndex // Get the file descriptor associated to a publishIndex
fileManager.getFileIndexFromPublish = function(publishIndex) { fileManager.getFileFromPublish = function(publishIndex) {
return _.chain(localStorage["file.list"].split(";")).compact() return _.find(fileSystemDescriptor, function(fileDesc) {
.find(function(fileIndex) { return _.has(fileDesc.publishLocations, publishIndex);
var sync = localStorage[fileIndex + ".publish"]; });
return sync.indexOf(";" + publishIndex + ";") !== -1;
}).value();
}; };
// Filter for search input in file selector // Filter for search input in file selector
@ -263,8 +281,8 @@ define(["jquery", "core", "utils", "synchronizer", "publisher", "sharing", "text
fileManager.selectFile(); fileManager.selectFile();
$(".action-create-file").click(function() { $(".action-create-file").click(function() {
var fileIndex = fileManager.createFile(); var fileDesc = fileManager.createFile();
fileManager.selectFile(fileIndex); fileManager.selectFile(fileDesc);
var wmdInput = $("#wmd-input").focus().get(0); var wmdInput = $("#wmd-input").focus().get(0);
if(wmdInput.setSelectionRange) { if(wmdInput.setSelectionRange) {
wmdInput.setSelectionRange(0, 0); wmdInput.setSelectionRange(0, 0);
@ -286,18 +304,21 @@ define(["jquery", "core", "utils", "synchronizer", "publisher", "sharing", "text
}); });
}); });
function applyTitle(input) { function applyTitle(input) {
input.hide();
$("#file-title").show();
var title = $.trim(input.val()); var title = $.trim(input.val());
var fileIndexTitle = fileManager.getCurrentFileIndex() + ".title"; var fileDesc = fileManager.getCurrentFile();
var fileIndexTitle = fileDesc.index + ".title";
if (title) { if (title) {
if (title != localStorage[fileIndexTitle]) { if (title != localStorage[fileIndexTitle]) {
localStorage[fileIndexTitle] = title; localStorage[fileIndexTitle] = title;
fileDesc.title = title;
fileManager.updateFileTitles(); fileManager.updateFileTitles();
fileManager.saveFile(); synchronizer.notifyChange(fileDesc);
extensionManager.onTitleChanged(fileDesc);
} }
} }
input.hide().val(localStorage[fileIndexTitle]); input.val(localStorage[fileIndexTitle]);
$("#file-title").show();
core.layoutRefresh();
$("#wmd-input").focus(); $("#wmd-input").focus();
} }
$("#file-title-input").blur(function() { $("#file-title-input").blur(function() {
@ -327,32 +348,33 @@ define(["jquery", "core", "utils", "synchronizer", "publisher", "sharing", "text
}); });
$(".action-edit-document").click(function() { $(".action-edit-document").click(function() {
var content = $("#wmd-input").val(); var content = $("#wmd-input").val();
var title = localStorage[fileManager.getCurrentFileIndex() + ".title"]; var title = fileManager.getCurrentFile().title;
var fileIndex = fileManager.createFile(title, content); var fileDesc = fileManager.createFile(title, content);
fileManager.selectFile(fileIndex); fileManager.selectFile(fileDesc);
window.location.href = "."; window.location.href = ".";
}); });
$(".action-download-md").click(function() { $(".action-download-md").click(function() {
var content = $("#wmd-input").val(); var content = $("#wmd-input").val();
var title = localStorage[fileManager.getCurrentFileIndex() + ".title"]; var title = fileManager.getCurrentFile().title;
core.saveFile(content, title + ".md"); core.saveFile(content, title + ".md");
}); });
$(".action-download-html").click(function() { $(".action-download-html").click(function() {
var content = $("#wmd-preview").html(); var content = $("#wmd-preview").html();
var title = localStorage[fileManager.getCurrentFileIndex() + ".title"]; var title = fileManager.getCurrentFile().title;
core.saveFile(content, title + ".html"); core.saveFile(content, title + ".html");
}); });
$(".action-download-template").click(function() { $(".action-download-template").click(function() {
var content = publisher.applyTemplate(); var content = publisher.applyTemplate();
var title = localStorage[fileManager.getCurrentFileIndex() + ".title"]; var title = fileManager.getCurrentFile().title;
core.saveFile(content, title + ".txt"); core.saveFile(content, title + ".txt");
}); });
$(".action-welcome-file").click(function() { $(".action-welcome-file").click(function() {
var fileIndex = fileManager.createFile(WELCOME_DOCUMENT_TITLE, welcomeContent); var fileDesc = fileManager.createFile(WELCOME_DOCUMENT_TITLE, welcomeContent);
fileManager.selectFile(fileIndex); fileManager.selectFile(fileDesc);
}); });
}); });
core.setFileManager(fileManager); core.setFileManager(fileManager);
extensionManager.onFileManagerCreated(fileManager);
return fileManager; return fileManager;
}); });

View File

@ -1,4 +1,4 @@
define(["core", "utils", "google-helper", "underscore"], function(core, utils, googleHelper) { define(["core", "utils", "extension-manager", "google-helper", "underscore"], function(core, utils, extensionManager, googleHelper) {
var PROVIDER_GDRIVE = "gdrive"; var PROVIDER_GDRIVE = "gdrive";
@ -6,13 +6,12 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
providerId: PROVIDER_GDRIVE, providerId: PROVIDER_GDRIVE,
providerName: "Google Drive", providerName: "Google Drive",
defaultPublishFormat: "template", defaultPublishFormat: "template",
exportPreferencesInputIds: ["gdrive-parentid"], exportPreferencesInputIds: ["gdrive-parentid"]
useSync: false
}; };
function createSyncAttributes(id, etag, content, title) { function createSyncAttributes(id, etag, content, title) {
var syncAttributes = {}; var syncAttributes = {};
syncAttributes.provider = PROVIDER_GDRIVE; syncAttributes.provider = gdriveProvider;
syncAttributes.id = id; syncAttributes.id = id;
syncAttributes.etag = etag; syncAttributes.etag = etag;
syncAttributes.contentCRC = utils.crc32(content); syncAttributes.contentCRC = utils.crc32(content);
@ -33,19 +32,18 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
if(error) { if(error) {
return; return;
} }
var titleList = []; var fileDescList = [];
_.each(result, function(file) { _.each(result, function(file) {
var syncAttributes = createSyncAttributes(file.id, file.etag, file.content, file.title); var syncAttributes = createSyncAttributes(file.id, file.etag, file.content, file.title);
var syncIndex = createSyncIndex(syncAttributes.id); var syncIndex = createSyncIndex(syncAttributes.id);
localStorage[syncIndex] = JSON.stringify(syncAttributes); localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
var fileIndex = core.fileManager.createFile(file.title, file.content, [syncIndex]); var syncLocations = {};
core.fileManager.selectFile(fileIndex); syncLocations[syncIndex] = syncAttributes;
titleList.push('"' + file.title + '"'); var fileDesc = core.fileManager.createFile(file.title, file.content, syncLocations);
core.fileManager.selectFile(fileDesc);
fileDescList.push(fileDesc);
}); });
if(titleList.length === 0) { extensionManager.onSyncImportSuccess(fileDescList, gdriveProvider);
return;
}
core.showMessage(titleList.join(", ") + ' imported successfully from Google Drive.');
}); });
}); });
}; };
@ -58,10 +56,9 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
var importIds = []; var importIds = [];
_.each(ids, function(id) { _.each(ids, function(id) {
var syncIndex = createSyncIndex(id); var syncIndex = createSyncIndex(id);
var fileIndex = core.fileManager.getFileIndexFromSync(syncIndex); var fileDesc = core.fileManager.getFileFromSync(syncIndex);
if(fileIndex !== undefined) { if(fileDesc !== undefined) {
var title = localStorage[fileIndex + ".title"]; core.showError('"' + fileDesc.title + '" was already imported');
core.showError('"' + title + '" was already imported');
return; return;
} }
importIds.push(id); importIds.push(id);
@ -79,8 +76,8 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
} }
var syncAttributes = createSyncAttributes(result.id, result.etag, content, title); var syncAttributes = createSyncAttributes(result.id, result.etag, content, title);
var syncIndex = createSyncIndex(syncAttributes.id); var syncIndex = createSyncIndex(syncAttributes.id);
localStorage[syncIndex] = JSON.stringify(syncAttributes); localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
callback(undefined, syncIndex); callback(undefined, syncIndex, syncAttributes);
}); });
}; };
@ -91,10 +88,9 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
} }
// Check that file is not synchronized with an other one // Check that file is not synchronized with an other one
var syncIndex = createSyncIndex(id); var syncIndex = createSyncIndex(id);
var fileIndex = core.fileManager.getFileIndexFromSync(syncIndex); var fileDesc = core.fileManager.getFileFromSync(syncIndex);
if(fileIndex !== undefined) { if(fileDesc !== undefined) {
var existingTitle = localStorage[fileIndex + ".title"]; core.showError('File ID is already synchronized with "' + fileDesc.title + '"');
core.showError('File ID is already synchronized with "' + existingTitle + '"');
callback(true); callback(true);
return; return;
} }
@ -105,8 +101,8 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
} }
var syncAttributes = createSyncAttributes(result.id, result.etag, content, title); var syncAttributes = createSyncAttributes(result.id, result.etag, content, title);
var syncIndex = createSyncIndex(syncAttributes.id); var syncIndex = createSyncIndex(syncAttributes.id);
localStorage[syncIndex] = JSON.stringify(syncAttributes); localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
callback(undefined, syncIndex); callback(undefined, syncIndex, syncAttributes);
}); });
}; };
@ -131,10 +127,6 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
}; };
gdriveProvider.syncDown = function(callback) { gdriveProvider.syncDown = function(callback) {
if (gdriveProvider.useSync === false) {
callback();
return;
}
var lastChangeId = parseInt(localStorage[PROVIDER_GDRIVE + ".lastChangeId"]); var lastChangeId = parseInt(localStorage[PROVIDER_GDRIVE + ".lastChangeId"]);
googleHelper.checkChanges(lastChangeId, function(error, changes, newChangeId) { googleHelper.checkChanges(lastChangeId, function(error, changes, newChangeId) {
if (error) { if (error) {
@ -144,8 +136,8 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
var interestingChanges = []; var interestingChanges = [];
_.each(changes, function(change) { _.each(changes, function(change) {
var syncIndex = createSyncIndex(change.fileId); var syncIndex = createSyncIndex(change.fileId);
var serializedAttributes = localStorage[syncIndex]; var syncAttributes = core.fileManager.getSyncAttributes(syncIndex);
if(serializedAttributes === undefined) { if(syncAttributes === undefined) {
return; return;
} }
// Store syncIndex to avoid 2 times formating // Store syncIndex to avoid 2 times formating
@ -156,10 +148,9 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
return; return;
} }
// Modify // Modify
var syncAttributes = JSON.parse(serializedAttributes);
if(syncAttributes.etag != change.file.etag) { if(syncAttributes.etag != change.file.etag) {
interestingChanges.push(change); interestingChanges.push(change);
// Store syncAttributes to avoid 2 times parsing // Store syncAttributes to avoid 2 times searching
change.syncAttributes = syncAttributes; change.syncAttributes = syncAttributes;
} }
}); });
@ -171,23 +162,21 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
var updateFileTitles = false; var updateFileTitles = false;
_.each(changes, function(change) { _.each(changes, function(change) {
var syncIndex = change.syncIndex; var syncIndex = change.syncIndex;
var fileIndex = core.fileManager.getFileIndexFromSync(syncIndex); var fileDesc = core.fileManager.getFileFromSync(syncIndex);
// No file corresponding (file may have been deleted locally) // No file corresponding (file may have been deleted locally)
if(fileIndex === undefined) { if(fileDesc === undefined) {
core.fileManager.removeSync(syncIndex);
return; return;
} }
var localTitle = localStorage[fileIndex + ".title"]; var localTitle = fileDesc.title;
// File deleted // File deleted
if (change.deleted === true) { if (change.deleted === true) {
core.showError('"' + localTitle + '" has been removed from Google Drive.');
core.fileManager.removeSync(syncIndex); core.fileManager.removeSync(syncIndex);
updateFileTitles = true;
core.showMessage('"' + localTitle + '" has been removed from Google Drive.');
return; return;
} }
var syncAttributes = change.syncAttributes; var syncAttributes = change.syncAttributes;
var localTitleChanged = syncAttributes.titleCRC != utils.crc32(localTitle); var localTitleChanged = syncAttributes.titleCRC != utils.crc32(localTitle);
var localContent = localStorage[fileIndex + ".content"]; var localContent = localStorage[fileDesc.index + ".content"];
var localContentChanged = syncAttributes.contentCRC != utils.crc32(localContent); var localContentChanged = syncAttributes.contentCRC != utils.crc32(localContent);
var file = change.file; var file = change.file;
var remoteTitleCRC = utils.crc32(file.title); var remoteTitleCRC = utils.crc32(file.title);
@ -205,15 +194,16 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
} }
// If file title changed // If file title changed
if(fileTitleChanged && remoteTitleChanged === true) { if(fileTitleChanged && remoteTitleChanged === true) {
localStorage[fileIndex + ".title"] = file.title; localStorage[fileDesc.index + ".title"] = file.title;
fileDesc.title = file.title;
updateFileTitles = true; updateFileTitles = true;
core.showMessage('"' + localTitle + '" has been renamed to "' + file.title + '" on Google Drive.'); core.showMessage('"' + localTitle + '" has been renamed to "' + file.title + '" on Google Drive.');
} }
// If file content changed // If file content changed
if(fileContentChanged && remoteContentChanged === true) { if(fileContentChanged && remoteContentChanged === true) {
localStorage[fileIndex + ".content"] = file.content; localStorage[fileDesc.index + ".content"] = file.content;
core.showMessage('"' + file.title + '" has been updated from Google Drive.'); core.showMessage('"' + file.title + '" has been updated from Google Drive.');
if(core.fileManager.isCurrentFileIndex(fileIndex)) { if(core.fileManager.isCurrentFile(fileDesc)) {
updateFileTitles = false; // Done by next function updateFileTitles = false; // Done by next function
core.fileManager.selectFile(); // Refresh editor core.fileManager.selectFile(); // Refresh editor
} }
@ -222,10 +212,10 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
syncAttributes.etag = file.etag; syncAttributes.etag = file.etag;
syncAttributes.contentCRC = remoteContentCRC; syncAttributes.contentCRC = remoteContentCRC;
syncAttributes.titleCRC = remoteTitleCRC; syncAttributes.titleCRC = remoteTitleCRC;
localStorage[syncIndex] = JSON.stringify(syncAttributes); localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
}); });
if(updateFileTitles) { if(updateFileTitles) {
core.fileManager.updateFileTitles(); extensionManager.onTitleChanged();
} }
localStorage[PROVIDER_GDRIVE + ".lastChangeId"] = newChangeId; localStorage[PROVIDER_GDRIVE + ".lastChangeId"] = newChangeId;
callback(); callback();
@ -275,8 +265,8 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
return; return;
} }
var syncIndex = createSyncAttributes(file.id, file.etag, file.content, file.title); var syncIndex = createSyncAttributes(file.id, file.etag, file.content, file.title);
var fileIndex = core.fileManager.createFile(file.title, file.content, [syncIndex]); var fileDesc = core.fileManager.createFile(file.title, file.content, [syncIndex]);
core.fileManager.selectFile(fileIndex); core.fileManager.selectFile(fileDesc);
core.showMessage('"' + file.title + '" created successfully on Google Drive.'); core.showMessage('"' + file.title + '" created successfully on Google Drive.');
}); });
} }
@ -284,9 +274,9 @@ define(["core", "utils", "google-helper", "underscore"], function(core, utils, g
var importIds = []; var importIds = [];
_.each(state.ids, function(id) { _.each(state.ids, function(id) {
var syncIndex = createSyncIndex(id); var syncIndex = createSyncIndex(id);
var fileIndex = core.fileManager.getFileIndexFromSync(syncIndex); var fileDesc = core.fileManager.getFileFromSync(syncIndex);
if(fileIndex !== undefined) { if(fileDesc !== undefined) {
core.fileManager.selectFile(fileIndex); core.fileManager.selectFile(fileDesc);
} }
else { else {
importIds.push(id); importIds.push(id);

View File

@ -1,5 +1,19 @@
define(["jquery", "core", "utils", "sharing", "blogger-provider", "dropbox-provider", "gist-provider", "github-provider", "gdrive-provider", "ssh-provider", "tumblr-provider", "wordpress-provider", "underscore"], define([
function($, core, utils, sharing) { "jquery",
"core",
"utils",
"extension-manager",
"sharing",
"blogger-provider",
"dropbox-provider",
"gist-provider",
"github-provider",
"gdrive-provider",
"ssh-provider",
"tumblr-provider",
"wordpress-provider",
"underscore"
], function($, core, utils, extensionManager, sharing) {
var publisher = {}; var publisher = {};
@ -14,17 +28,16 @@ define(["jquery", "core", "utils", "sharing", "blogger-provider", "dropbox-provi
// Allows external modules to update hasPublications flag // Allows external modules to update hasPublications flag
publisher.notifyPublish = function() { publisher.notifyPublish = function() {
var fileIndex = core.fileManager.getCurrentFileIndex(); var fileDesc = core.fileManager.getCurrentFile();
// Check that file has publications // Check that file has publications
if(localStorage[fileIndex + ".publish"].length === 1) { if(_.size(fileDesc.publishLocations) === 0) {
hasPublications = false; hasPublications = false;
} }
else { else {
hasPublications = true; hasPublications = true;
} }
publisher.updatePublishButton(); publisher.updatePublishButton();
publisher.refreshManagePublish();
}; };
// Used to enable/disable the publish button // Used to enable/disable the publish button
@ -41,10 +54,10 @@ define(["jquery", "core", "utils", "sharing", "blogger-provider", "dropbox-provi
// Apply template to the current document // Apply template to the current document
publisher.applyTemplate = function(publishAttributes) { publisher.applyTemplate = function(publishAttributes) {
var fileIndex = core.fileManager.getCurrentFileIndex(); var fileDesc = core.fileManager.getCurrentFile();
try { try {
return _.template(core.settings.template, { return _.template(core.settings.template, {
documentTitle: localStorage[fileIndex + ".title"], documentTitle: fileDesc.title,
documentMarkdown: $("#wmd-input").val(), documentMarkdown: $("#wmd-input").val(),
documentHTML: $("#wmd-preview").html(), documentHTML: $("#wmd-preview").html(),
publishAttributes: publishAttributes publishAttributes: publishAttributes
@ -72,18 +85,18 @@ define(["jquery", "core", "utils", "sharing", "blogger-provider", "dropbox-provi
} }
// Recursive function to publish a file on multiple locations // Recursive function to publish a file on multiple locations
var publishIndexList = []; var publishAttributesList = [];
var publishTitle = undefined; var publishTitle = undefined;
function publishLocation(callback, errorFlag) { function publishLocation(callback, errorFlag) {
// No more publish location for this document // No more publish location for this document
if (publishIndexList.length === 0) { if (publishAttributesList.length === 0) {
callback(errorFlag); callback(errorFlag);
return; return;
} }
// Dequeue a synchronized location // Dequeue a synchronized location
var publishIndex = publishIndexList.pop(); var publishIndex = publishAttributesList.pop();
var publishAttributes = JSON.parse(localStorage[publishIndex]); var publishAttributes = JSON.parse(localStorage[publishIndex]);
var content = getPublishContent(publishAttributes); var content = getPublishContent(publishAttributes);
@ -94,8 +107,6 @@ define(["jquery", "core", "utils", "sharing", "blogger-provider", "dropbox-provi
var errorMsg = error.toString(); var errorMsg = error.toString();
if(errorMsg.indexOf("|removePublish") !== -1) { if(errorMsg.indexOf("|removePublish") !== -1) {
core.fileManager.removePublish(publishIndex); core.fileManager.removePublish(publishIndex);
core.fileManager.updateFileTitles();
core.showMessage(provider.providerName + " publish location has been removed.");
} }
if(errorMsg.indexOf("|stopPublish") !== -1) { if(errorMsg.indexOf("|stopPublish") !== -1) {
callback(error); callback(error);
@ -115,26 +126,26 @@ define(["jquery", "core", "utils", "sharing", "blogger-provider", "dropbox-provi
publishRunning = true; publishRunning = true;
publisher.updatePublishButton(); publisher.updatePublishButton();
var fileIndex = core.fileManager.getCurrentFileIndex(); var fileDesc = fileManager.getCurrentFile();
publishTitle = localStorage[fileIndex + ".title"]; publishTitle = fileDesc.title;
publishIndexList = _.compact(localStorage[fileIndex + ".publish"].split(";")); publishAttributesList = _.values(fileDesc.publishLocations);
publishLocation(function(errorFlag) { publishLocation(function(errorFlag) {
publishRunning = false; publishRunning = false;
publisher.updatePublishButton(); publisher.updatePublishButton();
if(errorFlag === undefined) { if(errorFlag === undefined) {
core.showMessage('"' + publishTitle + '" successfully published.'); extensionManager.onPublishSuccess(fileDesc);
} }
}); });
}; };
// Generate a publishIndex associated to a fileIndex and store publishAttributes // Generate a publishIndex associated to a file and store publishAttributes
function createPublishIndex(fileIndex, publishAttributes) { function createPublishIndex(fileDesc, publishAttributes) {
var publishIndex = undefined; var publishIndex = undefined;
do { do {
publishIndex = "publish." + utils.randomString(); publishIndex = "publish." + utils.randomString();
} while(_.has(localStorage, publishIndex)); } while(_.has(localStorage, publishIndex));
localStorage[publishIndex] = JSON.stringify(publishAttributes); localStorage[publishIndex] = JSON.stringify(publishAttributes);
localStorage[fileIndex + ".publish"] += publishIndex + ";"; core.fileManager.addPublish(fileDesc, publishIndex, publishAttributes);
} }
// Initialize the "New publication" dialog // Initialize the "New publication" dialog
@ -174,18 +185,16 @@ define(["jquery", "core", "utils", "sharing", "blogger-provider", "dropbox-provi
} }
// Perform provider's publishing // Perform provider's publishing
var fileIndex = core.fileManager.getCurrentFileIndex(); var fileDesc = core.fileManager.getCurrentFile();
var title = localStorage[fileIndex + ".title"]; var title = fileDesc.title;
var content = getPublishContent(publishAttributes); var content = getPublishContent(publishAttributes);
provider.publish(publishAttributes, title, content, function(error) { provider.publish(publishAttributes, title, content, function(error) {
if(error === undefined) { if(error === undefined) {
publishAttributes.provider = provider.providerId; publishAttributes.provider = provider.providerId;
sharing.createLink(publishAttributes, function() { sharing.createLink(publishAttributes, function() {
createPublishIndex(fileIndex, publishAttributes); createPublishIndex(fileDesc, publishAttributes);
publisher.notifyPublish(); publisher.notifyPublish();
core.fileManager.updateFileTitles(); core.fileManager.updateFileTitles();
core.showMessage('"' + title
+ '" is now published on ' + provider.providerName + '.');
}); });
} }
}); });
@ -199,51 +208,20 @@ define(["jquery", "core", "utils", "sharing", "blogger-provider", "dropbox-provi
localStorage[provider.providerId + ".publishPreferences"] = JSON.stringify(publishPreferences); localStorage[provider.providerId + ".publishPreferences"] = JSON.stringify(publishPreferences);
} }
// Used to populate the "Manage publication" dialog // Retrieve file's publish locations from localStorage
var lineTemplate = ['<div class="input-prepend input-append">', publisher.populatePublishLocations = function(fileDesc) {
'<span class="add-on" title="<%= provider.providerName %>">', _.chain(localStorage[fileDesc.index + ".publish"].split(";"))
'<i class="icon-<%= provider.providerId %>"></i></span>', .compact()
'<input class="span5" type="text" value="<%= publishDesc %>" disabled />', .each(function(publishIndex) {
'</div>'].join("");
var removeButtonTemplate = '<a class="btn" title="Remove this location"><i class="icon-trash"></i></a>';
publisher.refreshManagePublish = function() {
var fileIndex = core.fileManager.getCurrentFileIndex();
var publishIndexList = _.compact(localStorage[fileIndex + ".publish"].split(";"));
$(".msg-no-publish, .msg-publish-list").addClass("hide");
var publishList = $("#manage-publish-list").empty();
if (publishIndexList.length > 0) {
$(".msg-publish-list").removeClass("hide");
} else {
$(".msg-no-publish").removeClass("hide");
}
_.each(publishIndexList, function(publishIndex) {
var publishAttributes = JSON.parse(localStorage[publishIndex]); var publishAttributes = JSON.parse(localStorage[publishIndex]);
if(publishAttributes.password) { // Store publishIndex
publishAttributes.password = "********"; publishAttributes.publishIndex = publishIndex;
} // Replace provider ID by provider module in attributes
var publishDesc = JSON.stringify(publishAttributes).replace(/{|}|"/g, ""); publishAttributes.provider = providerMap[publishAttributes.provider];
var lineElement = $(_.template(lineTemplate, { fileDesc.publishLocations[publishIndex] = publishAttributes;
provider: providerMap[publishAttributes.provider],
publishDesc: publishDesc
}));
lineElement.append($(removeButtonTemplate).click(function() {
core.fileManager.removePublish(publishIndex);
core.fileManager.updateFileTitles();
}));
publishList.append(lineElement);
}); });
}; };
publisher.getPublishAttributesFromFile = function(fileIndex) {
var publishIndexList = _.compact(localStorage[fileIndex + ".publish"].split(";"));
var attributesList = [];
_.each(publishIndexList, function(publishIndex) {
var publishAttributes = JSON.parse(localStorage[publishIndex]);
attributesList.push(publishAttributes);
});
return attributesList;
};
core.onReady(function() { core.onReady(function() {
// Add every provider // Add every provider
var publishMenu = $("#publish-menu"); var publishMenu = $("#publish-menu");
@ -273,5 +251,6 @@ define(["jquery", "core", "utils", "sharing", "blogger-provider", "dropbox-provi
}); });
}); });
extensionManager.onPublisherCreated(publisher);
return publisher; return publisher;
}); });

View File

@ -88,16 +88,12 @@ define(["jquery", "core", "utils", "async-runner", "download-provider", "gist-pr
return; return;
} }
localStorage.removeItem("missingSharingLink"); localStorage.removeItem("missingSharingLink");
var fileIndexList = _.compact(localStorage["file.list"].split(";")); var fileDescList = core.fileManager.getFileList();
_.each(fileIndexList, function(fileIndex) { _.each(fileDescList, function(fileDesc) {
var syncIndexList = localStorage[fileIndex + ".sync"].split(";"); _.each(fileDescList.publishLocations, function(publishAttributes, publishIndex) {
var publishIndexList = localStorage[fileIndex + ".publish"].split(";"); sharing.createLink(publishAttributes, function(shortUrl) {
var attributesIndexList = _.compact(syncIndexList.concat(publishIndexList));
_.each(attributesIndexList, function(attributesIndex) {
var attributes = JSON.parse(localStorage[attributesIndex]);
sharing.createLink(attributes, function(shortUrl) {
if(shortUrl !== undefined) { if(shortUrl !== undefined) {
localStorage[attributesIndex] = JSON.stringify(attributes); localStorage[publishIndex] = utils.serializeAttributes(attributes);
} }
}); });
}); });
@ -139,8 +135,8 @@ define(["jquery", "core", "utils", "async-runner", "download-provider", "gist-pr
if(error) { if(error) {
return; return;
} }
var fileIndex = core.fileManager.createFile(title, content, undefined, true); var fileDesc = core.fileManager.createFile(title, content, undefined, true);
core.fileManager.selectFile(fileIndex); core.fileManager.selectFile(fileDesc);
}); });
}); });

View File

@ -1,4 +1,13 @@
define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "underscore"], function($, core, utils) { define([
"jquery",
"core",
"utils",
"extension-manager",
"dropbox-provider",
"gdrive-provider",
"underscore"
], function($, core, utils, extensionManager) {
var synchronizer = {}; var synchronizer = {};
// Create a map with providerId: providerObject // Create a map with providerId: providerObject
@ -11,9 +20,9 @@ define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "under
var uploadPending = false; var uploadPending = false;
// Allows external modules to update uploadPending flag // Allows external modules to update uploadPending flag
synchronizer.notifyChange = function(fileIndex) { synchronizer.notifyChange = function(fileDesc) {
// Check that file has synchronized locations // Check that file has synchronized locations
if(localStorage[fileIndex + ".sync"].length !== 1) { if(_.size(fileDesc.syncLocations) !== 0) {
uploadPending = true; uploadPending = true;
synchronizer.updateSyncButton(); synchronizer.updateSyncButton();
} }
@ -38,7 +47,7 @@ define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "under
}; };
// Recursive function to upload a single file on multiple locations // Recursive function to upload a single file on multiple locations
var uploadFileSyncIndexList = []; var uploadSyncAttributesList = [];
var uploadContent = undefined; var uploadContent = undefined;
var uploadContentCRC = undefined; var uploadContentCRC = undefined;
var uploadTitle = undefined; var uploadTitle = undefined;
@ -46,16 +55,15 @@ define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "under
function locationUp(callback) { function locationUp(callback) {
// No more synchronized location for this document // No more synchronized location for this document
if (uploadFileSyncIndexList.length === 0) { if (uploadSyncAttributesList.length === 0) {
fileUp(callback); fileUp(callback);
return; return;
} }
// Dequeue a synchronized location // Dequeue a synchronized location
var syncIndex = uploadFileSyncIndexList.pop(); var syncAttributes = uploadSyncAttributesList.pop();
var syncAttributes = JSON.parse(localStorage[syncIndex]);
// Use the specified provider to perform the upload // Use the specified provider to perform the upload
providerMap[syncAttributes.provider].syncUp( syncAttributes.provider.syncUp(
uploadContent, uploadContent,
uploadContentCRC, uploadContentCRC,
uploadTitle, uploadTitle,
@ -74,7 +82,7 @@ define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "under
} }
if(uploadFlag) { if(uploadFlag) {
// Update syncAttributes in localStorage // Update syncAttributes in localStorage
localStorage[syncIndex] = JSON.stringify(syncAttributes); localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
} }
locationUp(callback); locationUp(callback);
} }
@ -82,31 +90,28 @@ define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "under
} }
// Recursive function to upload multiple files // Recursive function to upload multiple files
var uploadFileIndexList = []; var uploadFileList = [];
function fileUp(callback) { function fileUp(callback) {
// No more fileIndex to synchronize // No more fileDesc to synchronize
if (uploadFileIndexList.length === 0) { if (uploadFileList.length === 0) {
syncUp(callback); syncUp(callback);
return; return;
} }
// Dequeue a fileIndex // Dequeue a fileDesc
var fileIndex = uploadFileIndexList.pop(); var fileDesc = uploadFileList.pop();
var fileSyncIndexes = localStorage[fileIndex + ".sync"]; uploadSyncAttributesList = _.values(fileDesc.syncLocations);
if(fileSyncIndexes.length === 1) { if(uploadSyncAttributesList.length === 0) {
fileUp(callback); fileUp(callback);
return; return;
} }
// Get document title/content // Get document title/content
uploadContent = localStorage[fileIndex + ".content"]; uploadContent = localStorage[fileDesc.index + ".content"];
uploadContentCRC = utils.crc32(uploadContent); uploadContentCRC = utils.crc32(uploadContent);
uploadTitle = localStorage[fileIndex + ".title"]; uploadTitle = fileDesc.title;
uploadTitleCRC = utils.crc32(uploadTitle); uploadTitleCRC = utils.crc32(uploadTitle);
// Parse the list of synchronized locations associated to the document
uploadFileSyncIndexList = _.compact(fileSyncIndexes.split(";"));
locationUp(callback); locationUp(callback);
} }
@ -116,7 +121,7 @@ define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "under
if(uploadCycle === true) { if(uploadCycle === true) {
// New upload cycle // New upload cycle
uploadCycle = false; uploadCycle = false;
uploadFileIndexList = _.compact(localStorage["file.list"].split(";")); uploadFileList = core.fileManager.getFileList();
fileUp(callback); fileUp(callback);
} }
else { else {
@ -132,6 +137,14 @@ define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "under
return; return;
} }
var provider = providerList.pop(); var provider = providerList.pop();
// Check that provider has files to sync
if(!core.fileManager.hasSync(provider)) {
providerDown(callback);
return;
}
// Perform provider's syncDown
provider.syncDown(function(error) { provider.syncDown(function(error) {
if(error) { if(error) {
callback(error); callback(error);
@ -187,55 +200,20 @@ define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "under
core.addPeriodicCallback(synchronizer.sync); core.addPeriodicCallback(synchronizer.sync);
} }
// Used to populate the "Manage synchronization" dialog // Retrieve file's sync locations from localStorage
var lineTemplate = ['<div class="input-prepend input-append">', publisher.populateSyncLocations = function(fileDesc) {
'<span class="add-on" title="<%= provider.providerName %>">', _.chain(localStorage[fileDesc.index + ".sync"].split(";"))
'<i class="icon-<%= provider.providerId %>"></i></span>', .compact()
'<input class="span5" type="text" value="<%= syncDesc %>" disabled />', .each(function(syncIndex) {
'</div>'].join("");
var removeButtonTemplate = '<a class="btn" title="Remove this location"><i class="icon-trash"></i></a>';
synchronizer.refreshManageSync = function() {
var fileIndex = core.fileManager.getCurrentFileIndex();
var syncIndexList = _.compact(localStorage[fileIndex + ".sync"].split(";"));
$(".msg-no-sync, .msg-sync-list").addClass("hide");
var syncList = $("#manage-sync-list").empty();
if (syncIndexList.length > 0) {
$(".msg-sync-list").removeClass("hide");
} else {
$(".msg-no-sync").removeClass("hide");
}
_.each(syncIndexList, function(syncIndex) {
var syncAttributes = JSON.parse(localStorage[syncIndex]); var syncAttributes = JSON.parse(localStorage[syncIndex]);
var syncDesc = syncAttributes.id || syncAttributes.path; // Store syncIndex
var lineElement = $(_.template(lineTemplate, { syncAttributes.syncIndex = syncIndex;
provider: providerMap[syncAttributes.provider], // Replace provider ID by provider module in attributes
syncDesc: syncDesc syncAttributes.provider = providerMap[syncAttributes.provider];
})); fileDesc.syncLocations[syncIndex] = syncAttributes;
lineElement.append($(removeButtonTemplate).click(function() {
core.fileManager.removeSync(syncIndex);
core.fileManager.updateFileTitles();
}));
syncList.append(lineElement);
}); });
}; };
// Used to enable/disable provider synchronization
synchronizer.resetSyncFlags = function() {
_.each(providerMap, function(provider) {
provider.useSync = false;
});
};
synchronizer.getSyncAttributesFromFile = function(fileIndex) {
var syncIndexList = _.compact(localStorage[fileIndex + ".sync"].split(";"));
var attributesList = [];
_.each(syncIndexList, function(syncIndex) {
var syncAttributes = JSON.parse(localStorage[syncIndex]);
attributesList.push(syncAttributes);
providerMap[syncAttributes.provider].useSync = true;
});
return attributesList;
};
// Initialize the export dialog // Initialize the export dialog
function initExportDialog(provider) { function initExportDialog(provider) {
@ -269,19 +247,14 @@ define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "under
$(".action-sync-export-" + provider.providerId).click(function(event) { $(".action-sync-export-" + provider.providerId).click(function(event) {
// Perform the provider's export // Perform the provider's export
var fileIndex = core.fileManager.getCurrentFileIndex(); var fileDesc = core.fileManager.getCurrentFile();
var title = localStorage[fileIndex + ".title"]; var title = fileDesc.title;
var content = localStorage[fileIndex + ".content"]; var content = localStorage[fileDesc.index + ".content"];
provider.exportFile(event, title, content, function(error, syncIndex) { provider.exportFile(event, title, content, function(error, syncIndex, syncAttributes) {
if(error) { if(error) {
return; return;
} }
// Link syncIndex with fileIndex core.fileManager.addSync(fileDesc, syncIndex, syncAttributes);
localStorage[fileIndex + ".sync"] += syncIndex + ";";
synchronizer.refreshManageSync();
core.fileManager.updateFileTitles();
core.showMessage('"' + title
+ '" will now be synchronized on ' + provider.providerName + '.');
}); });
// Store input values as preferences for next time we open the export dialog // Store input values as preferences for next time we open the export dialog
@ -293,18 +266,14 @@ define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "under
}); });
// Provider's manual export button // Provider's manual export button
$(".action-sync-manual-" + provider.providerId).click(function(event) { $(".action-sync-manual-" + provider.providerId).click(function(event) {
var fileIndex = core.fileManager.getCurrentFileIndex(); var fileDesc = core.fileManager.getCurrentFile();
var title = localStorage[fileIndex + ".title"]; var title = fileDesc.title;
var content = localStorage[fileIndex + ".content"]; var content = localStorage[fileDesc.index + ".content"];
provider.exportManual(event, title, content, function(error, syncIndex) { provider.exportManual(event, title, content, function(error, syncIndex, syncAttributes) {
if(error) { if(error) {
return; return;
} }
localStorage[fileIndex + ".sync"] += syncIndex + ";"; core.fileManager.addSync(fileDesc, syncIndex, syncAttributes);
synchronizer.refreshManageSync();
core.fileManager.updateFileTitles();
core.showMessage('"' + title
+ '" will now be synchronized on ' + provider.providerName + '.');
}); });
}); });
}); });
@ -317,5 +286,6 @@ define(["jquery", "core", "utils", "dropbox-provider", "gdrive-provider", "under
}); });
}); });
extensionManager.onSynchronizerCreated(synchronizer);
return synchronizer; return synchronizer;
}); });

View File

@ -247,6 +247,15 @@ define([ "jquery", "underscore" ], function($) {
return _.random(4294967296).toString(36); return _.random(4294967296).toString(36);
}; };
// Serialize sync/publish attributes
utils.serializeAttributes = function(attributes) {
// 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);
};
return utils; return utils;
}); });