New extension pattern

This commit is contained in:
benweet 2013-05-27 20:45:33 +01:00
parent 56fa0c5873
commit d636e80646
59 changed files with 1160 additions and 927 deletions

View File

@ -6,7 +6,7 @@ index.html
viewer.html
css/main-min.css
js/main-min.js
js/require.js
js/lib/require.js
img/ajax-loader.gif
img/glyphicons-halflings.png
img/glyphicons-halflings-white.png

47
css/main-min.css vendored
View File

@ -5513,6 +5513,12 @@ code {
h1 {
margin: 30px 0 30px;
}
h4, h5, h6 {
line-height: 40px;
}
.toc ul {
list-style-type: none;
}
p, pre, blockquote {
margin: 0 0 20px;
}
@ -5727,9 +5733,48 @@ div.dropdown-menu i {
height: 80px;
max-width: 206px;
}
.tooltip-inner {
#modal-settings .accordion-group {
border: 0;
border-bottom: 1px solid #eee;
-webkit-border-radius: inherit;
-moz-border-radius: inherit;
border-radius: inherit;
margin-bottom: 10px;
}
#modal-settings .accordion-heading .checkbox {
padding: 8px 15px;
margin-bottom: 0px;
}
#modal-settings .accordion-inner {
border: 0;
padding: 10px 40px;
}
#modal-settings .accordion-inner .form-horizontal .control-group {
color: #999;
}
#modal-settings .accordion-inner .form-horizontal .control-label {
text-align: left;
}
.accordion-toggle {
cursor: help;
}
.nav-tabs > .active > a, .nav-tabs > .active > a:hover, .nav-tabs > .active > a:focus {
color: #fff;
background-color: #777;
border-color: #777;
border-bottom-color: transparent;
}
.nav-tabs {
border-bottom-color: #eee;
}
.nav > li > a:hover,
.nav > li > a:focus {
background-color: #eee;
}
.nav-tabs > li > a:hover,
.nav-tabs > li > a:focus {
border-color: #eee;
}
table {
margin-bottom: 20px;
}

View File

@ -19,13 +19,12 @@
document.write('<link href="css/main' + suffix + '.css" rel="stylesheet">');
var theme = localStorage.theme;
if (theme) {
document
.write('<link href="themes/' + theme + '/' + theme + '.css" rel="stylesheet">');
document.write('<link href="themes/' + theme + '/' + theme + '.css" rel="stylesheet">');
}
var require = { baseUrl : "js", deps : [ "main" + suffix ] };
var viewerMode = false;
</script>
<script src="js/require.js"></script>
<script src="js/lib/require.js"></script>
</head>
<body>
<div id="navbar" class="navbar navbar-fixed-top ui-layout-north">

View File

@ -2,7 +2,12 @@
* Used to run asynchronous tasks sequentially (ajax mainly). An asynchronous
* task is composed of different callback types: onRun, onSuccess, onError
*/
define([ "core", "underscore" ], function(core) {
define([
"underscore",
"core",
"utils",
"extension-manager"
], function(_, core, utils, extensionMgr) {
var asyncRunner = {};
@ -81,7 +86,7 @@ define([ "core", "underscore" ], function(core) {
}
error = error || new Error("Unknown error");
if(error.message) {
core.showError(error);
extensionMgr.onError(error);
}
runSafe(task, task.errorCallbacks, error);
// Exit the current call stack
@ -102,7 +107,7 @@ define([ "core", "underscore" ], function(core) {
}
// Implement an exponential backoff
var delay = Math.pow(2, task.retryCounter++) * 1000;
currentTaskStartTime = core.currentTime + delay;
currentTaskStartTime = utils.currentTime + delay;
currentTaskRunning = false;
asyncRunner.runTask();
};
@ -117,7 +122,7 @@ define([ "core", "underscore" ], function(core) {
// If there is a task currently running
if (currentTaskRunning === true) {
// If the current task takes too long
if (currentTaskStartTime + currentTask.timeout < core.currentTime) {
if (currentTaskStartTime + currentTask.timeout < utils.currentTime) {
currentTask.error(new Error("A timeout occurred."));
}
return;
@ -131,12 +136,12 @@ define([ "core", "underscore" ], function(core) {
// Dequeue an enqueued task
currentTask = taskQueue.shift();
currentTaskStartTime = core.currentTime;
core.showWorkingIndicator(true);
currentTaskStartTime = utils.currentTime;
extensionMgr.onAsyncRunning(true);
}
// Run the task
if (currentTaskStartTime <= core.currentTime) {
if (currentTaskStartTime <= utils.currentTime) {
currentTaskRunning = true;
currentTask.chain();
}
@ -157,7 +162,7 @@ define([ "core", "underscore" ], function(core) {
currentTaskRunning = false;
}
if (taskQueue.length === 0) {
core.showWorkingIndicator(false);
extensionMgr.onAsyncRunning(false);
} else {
asyncRunner.runTask();
}

View File

@ -1,4 +1,8 @@
define(["utils", "google-helper"], function(utils, googleHelper) {
define([
"underscore",
"utils",
"google-helper"
], function(_, utils, googleHelper) {
var PROVIDER_BLOGGER = "blogger";
@ -39,10 +43,11 @@ define(["utils", "google-helper"], function(utils, googleHelper) {
publishAttributes.labelList = [];
var labels = utils.getInputTextValue("#input-publish-labels");
if(labels !== undefined) {
publishAttributes.labelList = _.chain(labels.split(","))
.map(function(label) {
return utils.trim(label);
}).compact().value();
publishAttributes.labelList = _.chain(
labels.split(",")
).map(function(label) {
return utils.trim(label);
}).compact().value();
}
if(event.isPropagationStopped()) {
return undefined;

View File

@ -1,28 +1,18 @@
define([
"jquery",
"underscore",
"utils",
"settings",
"extension-manager",
"bootstrap",
"layout",
"Markdown.Editor",
"storage",
"config",
"underscore",
"FileSaver",
"css_browser_selector"
], function($, utils, extensionManager) {
"lib/bootstrap",
"lib/layout",
"lib/Markdown.Editor"
], function($, _, utils, settings, extensionMgr) {
var core = {};
// For convenience
core.doNothing = function() {};
// Time shared by others modules
function updateCurrentTime() {
core.currentTime = new Date().getTime();
}
updateCurrentTime();
// Used for periodic tasks
var intervalId = undefined;
var periodicCallbacks = [];
@ -38,11 +28,11 @@ define([
function setUserActive() {
userReal = true;
userActive = true;
userLastActivity = core.currentTime;
userLastActivity = utils.currentTime;
};
function isUserActive() {
if(userActive === true
&& core.currentTime - userLastActivity > USER_IDLE_THRESHOLD) {
&& utils.currentTime - userLastActivity > USER_IDLE_THRESHOLD) {
userActive = false;
}
return userActive && windowUnique;
@ -50,7 +40,7 @@ define([
// Used to only have 1 window of the application in the same browser
var windowId = undefined;
core.checkWindowUnique = function() {
function checkWindowUnique() {
if(userReal === false || windowUnique === false) {
return;
}
@ -70,136 +60,65 @@ define([
keyboard: false
});
}
};
}
// Export data on disk
core.saveFile = function(content, filename) {
if(saveAs !== undefined) {
var blob = new Blob([content], {type: "text/plain;charset=utf-8"});
saveAs(blob, filename);
}
else {
var uriContent = "data:application/octet-stream;base64,"
+ utils.encodeBase64(content);
window.open(uriContent, 'file');
}
};
// Used by asyncRunner
core.showWorkingIndicator = function(show) {
if (show === false) {
$(".working-indicator").removeClass("show");
$("body").removeClass("working");
} else {
$(".working-indicator").addClass("show");
$("body").addClass("working");
}
};
// Log a message
core.showMessage = function(message) {
console.log(message);
extensionManager.onMessage(message);
};
// Log an error
core.showError = function(error) {
console.error(error);
if(_.isString(error)) {
extensionManager.onMessage(error);
}
else if(_.isObject(error)) {
extensionManager.onMessage(error.message);
}
};
// Offline management
core.isOffline = false;
var offlineTime = core.currentTime;
var offlineListeners = [];
core.addOfflineListener = function(callback) {
offlineListeners.push(callback);
};
var offlineTime = utils.currentTime;
core.setOffline = function() {
offlineTime = core.currentTime;
offlineTime = utils.currentTime;
if(core.isOffline === false) {
core.isOffline = true;
extensionManager.onOfflineChanged(true);
_.each(offlineListeners, function(listener) {
listener();
});
extensionMgr.onOfflineChanged(true);
}
};
core.setOnline = function() {
function setOnline() {
if(core.isOffline === true) {
core.isOffline = false;
extensionManager.onOfflineChanged(false);
_.each(offlineListeners, function(listener) {
listener();
});
extensionMgr.onOfflineChanged(false);
}
};
}
function checkOnline() {
// Try to reconnect if we are offline but we have some network
if (core.isOffline === true && navigator.onLine === true
&& offlineTime + CHECK_ONLINE_PERIOD < core.currentTime) {
offlineTime = core.currentTime;
&& offlineTime + CHECK_ONLINE_PERIOD < utils.currentTime) {
offlineTime = utils.currentTime;
// Try to download anything to test the connection
$.ajax({
url : "//www.google.com/jsapi",
timeout : AJAX_TIMEOUT, dataType : "script"
}).done(function() {
core.setOnline();
setOnline();
});
}
}
// Setting management
core.settings = {
layoutOrientation : "horizontal",
lazyRendering : true,
editorFontSize : 14,
defaultContent: "\n\n\n> Written with [StackEdit](http://benweet.github.io/stackedit/).",
commitMsg : "Published by http://benweet.github.io/stackedit",
template : ['<!DOCTYPE html>\n',
'<html>\n',
'<head>\n',
'<title><%= documentTitle %></title>\n',
'</head>\n',
'<body><%= documentHTML %></body>\n',
'</html>'].join(""),
sshProxy : SSH_PROXY_URL,
extensionSettings: {}
};
if (_.has(localStorage, "settings")) {
_.extend(core.settings, JSON.parse(localStorage.settings));
}
extensionManager.init(core.settings.extensionSettings);
core.loadSettings = function() {
// Load settings in settings dialog
function loadSettings() {
// Layout orientation
utils.setInputRadio("radio-layout-orientation", core.settings.layoutOrientation);
utils.setInputRadio("radio-layout-orientation", settings.layoutOrientation);
// Theme
utils.setInputValue("#input-settings-theme", localStorage.theme);
// Lazy rendering
utils.setInputChecked("#input-settings-lazy-rendering", core.settings.lazyRendering);
utils.setInputChecked("#input-settings-lazy-rendering", settings.lazyRendering);
// Editor font size
utils.setInputValue("#input-settings-editor-font-size", core.settings.editorFontSize);
utils.setInputValue("#input-settings-editor-font-size", settings.editorFontSize);
// Default content
utils.setInputValue("#textarea-settings-default-content", core.settings.defaultContent);
utils.setInputValue("#textarea-settings-default-content", settings.defaultContent);
// Commit message
utils.setInputValue("#input-settings-publish-commit-msg", core.settings.commitMsg);
utils.setInputValue("#input-settings-publish-commit-msg", settings.commitMsg);
// Template
utils.setInputValue("#textarea-settings-publish-template", core.settings.template);
utils.setInputValue("#textarea-settings-publish-template", settings.template);
// SSH proxy
utils.setInputValue("#input-settings-ssh-proxy", core.settings.sshProxy);
utils.setInputValue("#input-settings-ssh-proxy", settings.sshProxy);
// Load extension settings
extensionManager.onLoadSettings();
};
extensionMgr.onLoadSettings();
}
core.saveSettings = function(event) {
// Save settings from settings dialog
function saveSettings(event) {
var newSettings = {};
// Layout orientation
@ -221,14 +140,14 @@ define([
// Save extension settings
newSettings.extensionSettings = {};
extensionManager.onSaveSettings(newSettings.extensionSettings, event);
extensionMgr.onSaveSettings(newSettings.extensionSettings, event);
if(!event.isPropagationStopped()) {
$.extend(core.settings, newSettings);
localStorage.settings = JSON.stringify(newSettings);
$.extend(settings, newSettings);
localStorage.settings = JSON.stringify(settings);
localStorage.theme = theme;
}
};
}
// Create the layout
var layout = undefined;
@ -250,8 +169,8 @@ define([
center__minWidth : 200,
center__minHeight : 200
};
extensionManager.onLayoutConfigure(layoutGlobalConfig);
if (core.settings.layoutOrientation == "horizontal") {
extensionMgr.onLayoutConfigure(layoutGlobalConfig);
if (settings.layoutOrientation == "horizontal") {
$(".ui-layout-south").remove();
$(".ui-layout-east").addClass("well").prop("id", "wmd-preview");
layout = $('body').layout(
@ -261,7 +180,7 @@ define([
east__minSize : 200
})
);
} else if (core.settings.layoutOrientation == "vertical") {
} else if (settings.layoutOrientation == "vertical") {
$(".ui-layout-east").remove();
$(".ui-layout-south").addClass("well").prop("id", "wmd-preview");
layout = $('body').layout(
@ -282,7 +201,7 @@ define([
layout.allowOverflow('north');
});
extensionManager.onLayoutCreated(layout);
extensionMgr.onLayoutCreated(layout);
};
// Create the PageDown editor
@ -320,7 +239,7 @@ define([
makePreview();
};
};
if(core.settings.lazyRendering === true) {
if(settings.lazyRendering === true) {
var lastRefresh = 0;
previewWrapper = function(makePreview) {
//var debouncedMakePreview = _.debounce(makePreview, 500);
@ -340,8 +259,8 @@ define([
};
};
}
extensionManager.onEditorConfigure(editor);
editor.hooks.chain("onPreviewRefresh", extensionManager.onAsyncPreview);
extensionMgr.onEditorConfigure(editor);
editor.hooks.chain("onPreviewRefresh", extensionMgr.onAsyncPreview);
// Convert email addresses (not managed by pagedown)
converter.hooks.chain("postConversion", function(text) {
@ -374,53 +293,29 @@ define([
$("#wmd-redo-button").append($("<i>").addClass("icon-share-alt"));
};
// Create an centered popup window
core.popupWindow = function(url, title, w, h) {
var left = (screen.width / 2) - (w / 2);
var top = (screen.height / 2) - (h / 2);
return window
.open(
url,
title,
'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width='
+ w
+ ', height='
+ h
+ ', top='
+ top
+ ', left='
+ left);
};
// Keep a reference to the fileManager
core.setFileManager = function(fileManager) {
core.fileManager = fileManager;
runReadyCallbacks();
};
// onReady event callbacks
var readyCallbacks = [];
core.onReady = function(callback) {
readyCallbacks.push(callback);
runReadyCallbacks();
};
var documentLoaded = false;
var ready = false;
core.setReady = function() {
ready = true;
runReadyCallbacks();
};
function runReadyCallbacks() {
if(documentLoaded === true && core.fileManager !== undefined) {
if(ready === true) {
_.each(readyCallbacks, function(callback) {
callback();
});
readyCallbacks = [];
}
}
$(function() {
documentLoaded = true;
runReadyCallbacks();
});
core.onReady(extensionManager.onReady);
core.onReady(function() {
// Load theme list
_.each(THEME_LIST, function(name, value) {
$("#input-settings-theme").append($('<option value="' + value + '">' + name + '</option>'));
@ -428,7 +323,7 @@ define([
// listen to online/offline events
$(window).on('offline', core.setOffline);
$(window).on('online', core.setOnline);
$(window).on('online', setOnline);
if (navigator.onLine === false) {
core.setOffline();
}
@ -460,10 +355,10 @@ define([
// Settings loading/saving
$(".action-load-settings").click(function() {
core.loadSettings();
loadSettings();
});
$(".action-apply-settings").click(function(e) {
core.saveSettings(e);
saveSettings(e);
if(!e.isPropagationStopped()) {
window.location.reload();
}
@ -487,8 +382,8 @@ define([
// Editor's textarea
$("#wmd-input, #md-section-helper").css({
// Apply editor font size
"font-size": core.settings.editorFontSize + "px",
"line-height": Math.round(core.settings.editorFontSize * (20/14)) + "px"
"font-size": settings.editorFontSize + "px",
"line-height": Math.round(settings.editorFontSize * (20/14)) + "px"
});
// Manage tab key
@ -564,8 +459,8 @@ define([
// Do periodic tasks
intervalId = window.setInterval(function() {
updateCurrentTime();
core.checkWindowUnique();
utils.updateCurrentTime();
checkWindowUnique();
if(isUserActive() === true || viewerMode === true) {
_.each(periodicCallbacks, function(callback) {
callback();

View File

@ -1,4 +1,8 @@
define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
define([
"jquery",
"core",
"async-runner"
], function($, core, asyncRunner) {
var PROVIDER_DOWNLOAD = "download";

View File

@ -1,4 +1,10 @@
define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
define([
"jquery",
"underscore",
"core",
"extension-manager",
"async-runner"
], function($, _, core, extensionMgr, asyncRunner) {
var client = undefined;
var authenticated = false;
@ -50,7 +56,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
var immediate = true;
function localAuthenticate() {
if (immediate === false) {
core.showMessage("Please make sure the Dropbox authorization popup is not blocked by your browser.");
extensionMgr.onMessage("Please make sure the Dropbox authorization popup is not blocked by your browser.");
// If not immediate we add time for user to enter his credentials
task.timeout = ASYNC_TASK_LONG_TIMEOUT;
}
@ -77,7 +83,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}
dropboxHelper.upload = function(path, content, callback) {
callback = callback || core.doNothing;
var result = undefined;
var task = asyncRunner.createTask();
connect(task);
@ -106,7 +111,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
};
dropboxHelper.checkChanges = function(lastChangeId, callback) {
callback = callback || core.doNothing;
var changes = [];
var newChangeId = lastChangeId || 0;
var task = asyncRunner.createTask();
@ -143,7 +147,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
};
dropboxHelper.downloadMetadata = function(paths, callback) {
callback = callback || core.doNothing;
var result = [];
var task = asyncRunner.createTask();
connect(task);
@ -177,7 +180,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
};
dropboxHelper.downloadContent = function(objects, callback) {
callback = callback || core.doNothing;
var result = [];
var task = asyncRunner.createTask();
connect(task);
@ -289,7 +291,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}
dropboxHelper.picker = function(callback) {
callback = callback || core.doNothing;
var paths = [];
var task = asyncRunner.createTask();
// Add some time for user to choose his files
@ -312,7 +313,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
task.chain();
};
Dropbox.choose(options);
core.showMessage("Please make sure the Dropbox chooser popup is not blocked by your browser.");
extensionMgr.onMessage("Please make sure the Dropbox chooser popup is not blocked by your browser.");
});
task.onSuccess(function() {
callback(undefined, paths);

View File

@ -1,4 +1,10 @@
define(["core", "utils", "extension-manager", "dropbox-helper"], function(core, utils, extensionManager, dropboxHelper) {
define([
"underscore",
"utils",
"extension-manager",
"file-manager",
"dropbox-helper"
], function(_, utils, extensionMgr, fileMgr, dropboxHelper) {
var PROVIDER_DROPBOX = "dropbox";
@ -13,7 +19,7 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
return undefined;
}
if(!path.match(/^[^\\<>:"\|?\*]+$/)) {
core.showError('"' + path + '" contains invalid characters.');
extensionMgr.onError('"' + path + '" contains invalid characters.');
return undefined;
}
if(path.indexOf("/") !== 0) {
@ -51,11 +57,11 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
var syncLocations = {};
syncLocations[syncAttributes.syncIndex] = syncAttributes;
var fileDesc = core.fileManager.createFile(file.name, file.content, syncLocations);
core.fileManager.selectFile(fileDesc);
var fileDesc = fileMgr.createFile(file.name, file.content, syncLocations);
fileMgr.selectFile(fileDesc);
fileDescList.push(fileDesc);
});
extensionManager.onSyncImportSuccess(fileDescList, dropboxProvider);
extensionMgr.onSyncImportSuccess(fileDescList, dropboxProvider);
});
});
}
@ -68,9 +74,9 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
var importPaths = [];
_.each(paths, function(path) {
var syncIndex = createSyncIndex(path);
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex);
var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
if(fileDesc !== undefined) {
core.showError('"' + fileDesc.title + '" was already imported');
extensionMgr.onError('"' + fileDesc.title + '" was already imported');
return;
}
importPaths.push(path);
@ -87,10 +93,10 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
}
// Check that file is not synchronized with an other one
var syncIndex = createSyncIndex(path);
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex);
var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
if(fileDesc !== undefined) {
var existingTitle = fileDesc.title;
core.showError('File path is already synchronized with "' + existingTitle + '"');
extensionMgr.onError('File path is already synchronized with "' + existingTitle + '"');
callback(true);
return;
}
@ -143,7 +149,7 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
var interestingChanges = [];
_.each(changes, function(change) {
var syncIndex = createSyncIndex(change.path);
var syncAttributes = core.fileManager.getSyncAttributes(syncIndex);
var syncAttributes = fileMgr.getSyncAttributes(syncIndex);
if(syncAttributes === undefined) {
return;
}
@ -164,11 +170,10 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
callback(error);
return;
}
var updateFileTitles = false;
_.each(changes, function(change) {
var syncAttributes = change.syncAttributes;
var syncIndex = syncAttributes.syncIndex;
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex);
var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
// No file corresponding (file may have been deleted locally)
if(fileDesc === undefined) {
return;
@ -176,8 +181,8 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
var localTitle = fileDesc.title;
// File deleted
if (change.wasRemoved === true) {
core.showError('"' + localTitle + '" has been removed from Dropbox.');
core.fileManager.removeSync(syncAttributes);
extensionMgr.onError('"' + localTitle + '" has been removed from Dropbox.');
fileMgr.removeSync(syncAttributes);
return;
}
var localContent = localStorage[fileDesc.fileIndex + ".content"];
@ -188,17 +193,16 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
var fileContentChanged = localContent != file.content;
// Conflict detection
if (fileContentChanged === true && localContentChanged === true && remoteContentChanged === true) {
core.fileManager.createFile(localTitle + " (backup)", localContent);
updateFileTitles = true;
core.showMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.');
var backupFileDesc = fileMgr.createFile(localTitle + " (backup)", localContent);
extensionMgr.onTitleChanged(backupFileDesc);
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;
core.showMessage('"' + localTitle + '" has been updated from Dropbox.');
if(core.fileManager.isCurrentFile(fileDesc)) {
updateFileTitles = false; // Done by next function
core.fileManager.selectFile(); // Refresh editor
extensionMgr.onMessage('"' + localTitle + '" has been updated from Dropbox.');
if(fileMgr.isCurrentFile(fileDesc)) {
fileMgr.selectFile(); // Refresh editor
}
}
// Update syncAttributes
@ -206,9 +210,6 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
syncAttributes.contentCRC = remoteContentCRC;
localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
});
if(updateFileTitles) {
extensionManager.onTitleChanged();
}
localStorage[PROVIDER_DROPBOX + ".lastChangeId"] = newChangeId;
callback();
});

View File

@ -1,29 +1,40 @@
define( [
"jquery",
"utils",
"underscore",
"bootstrap",
"utils",
"settings",
"extensions/button-publish",
"extensions/button-share",
"extensions/button-sync",
"extensions/document-selector",
"extensions/document-title",
"extensions/manage-publication",
"extensions/manage-synchronization",
"extensions/working-indicator",
"extensions/notifications",
"extensions/markdown-extra",
"extensions/toc",
"extensions/math-jax",
"extensions/scroll-link"
], function($, utils) {
"extensions/scroll-link",
"lib/bootstrap"
], function($, _, utils, settings) {
var extensionManager = {};
var extensionMgr = {};
// Create a list of extensions
var extensionList = _.chain(arguments)
.map(function(argument) {
return _.isObject(argument) && argument.extensionId && argument;
}).compact().value();
var extensionList = _.chain(
arguments
).map(function(argument) {
return _.isObject(argument) && argument.extensionId && argument;
}).compact().value();
// Return every named callbacks implemented in extensions
function getExtensionCallbackList(hookName) {
return _.chain(extensionList)
.map(function(extension) {
return extension.config.enabled && extension[hookName];
}).compact().value();
return _.chain(
extensionList
).map(function(extension) {
return extension.config.enabled && extension[hookName];
}).compact().value();
}
// Return a function that calls every callbacks from extensions
@ -38,9 +49,9 @@ define( [
};
}
// Add a Hook to the extensionManager
// Add a Hook to the extensionMgr
function addHook(hookName) {
extensionManager[hookName] = createHook(hookName);
extensionMgr[hookName] = createHook(hookName);
}
var accordionTmpl = [
@ -66,96 +77,97 @@ define( [
settingsBloc: extension.settingsBloc
})));
}
extensionManager.init = function(extensionSettings) {
// Set extension config
extensionSettings = extensionSettings || {};
_.each(extensionList, function(extension) {
extension.config = _.extend({}, extension.defaultConfig, extensionSettings[extension.extensionId]);
extension.config.enabled = !extension.optional || extension.config.enabled === undefined || extension.config.enabled === true;
});
// Load/Save extension config from/to settings
extensionManager["onLoadSettings"] = function() {
console.debug("onLoadSettings");
_.each(extensionList, function(extension) {
utils.setInputChecked("#input-enable-extension-" + extension.extensionId, extension.config.enabled);
var onLoadSettingsCallback = extension.onLoadSettings;
onLoadSettingsCallback && onLoadSettingsCallback();
});
};
extensionManager["onSaveSettings"] = function(newExtensionSettings, event) {
console.debug("onSaveSettings");
_.each(extensionList, function(extension) {
var newExtensionConfig = extension.defaultConfig || {};
newExtensionConfig.enabled = utils.getInputChecked("#input-enable-extension-" + extension.extensionId);
var onSaveSettingsCallback = extension.onSaveSettings;
onSaveSettingsCallback && onSaveSettingsCallback(newExtensionConfig, event);
newExtensionSettings[extension.extensionId] = newExtensionConfig;
});
};
addHook("onMessage");
addHook("onError");
addHook("onOfflineChanged");
// 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");
extensionManager["onAsyncPreview"] = function() {
console.debug("onAsyncPreview");
// Call onPreviewFinished callbacks when all async preview are finished
var counter = 0;
function tryFinished() {
if(counter === onAsyncPreviewCallbackList.length) {
onPreviewFinished();
}
}
_.each(onAsyncPreviewCallbackList, function(asyncPreviewCallback) {
asyncPreviewCallback(function() {
counter++;
tryFinished();
});
});
tryFinished();
};
// Call onReady callbacks
var onReady = createHook("onReady");
extensionManager["onReady"] = function() {
// Create accordion in settings dialog
_.each(extensionList, createSettings);
onReady();
};
// Set extension config
extensionSettings = settings.extensionSettings || {};
_.each(extensionList, function(extension) {
extension.config = _.extend({}, extension.defaultConfig, extensionSettings[extension.extensionId]);
extension.config.enabled = !extension.optional || extension.config.enabled === undefined || extension.config.enabled === true;
});
// Load/Save extension config from/to settings
extensionMgr["onLoadSettings"] = function() {
console.debug("onLoadSettings");
_.each(extensionList, function(extension) {
utils.setInputChecked("#input-enable-extension-" + extension.extensionId, extension.config.enabled);
var onLoadSettingsCallback = extension.onLoadSettings;
onLoadSettingsCallback && onLoadSettingsCallback();
});
};
extensionMgr["onSaveSettings"] = function(newExtensionSettings, event) {
console.debug("onSaveSettings");
_.each(extensionList, function(extension) {
var newExtensionConfig = extension.defaultConfig || {};
newExtensionConfig.enabled = utils.getInputChecked("#input-enable-extension-" + extension.extensionId);
var onSaveSettingsCallback = extension.onSaveSettings;
onSaveSettingsCallback && onSaveSettingsCallback(newExtensionConfig, event);
newExtensionSettings[extension.extensionId] = newExtensionConfig;
});
};
return extensionManager;
addHook("onReady");
addHook("onMessage");
addHook("onError");
addHook("onOfflineChanged");
addHook("onAsyncRunning");
// To store reference to modules that are accessible from extensions
addHook("onFileMgrCreated");
addHook("onSynchronizerCreated");
addHook("onPublisherCreated");
// Operations on files
addHook("onFileSystemCreated");
addHook("onFileCreated");
addHook("onFileDeleted");
addHook("onFileChanged");
addHook("onFileSelected");
addHook("onTitleChanged");
// Sync events
addHook("onSyncRunning");
addHook("onSyncSuccess");
addHook("onSyncImportSuccess");
addHook("onSyncExportSuccess");
addHook("onSyncRemoved");
// Publish events
addHook("onPublishRunning");
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");
extensionMgr["onAsyncPreview"] = function() {
console.debug("onAsyncPreview");
// Call onPreviewFinished callbacks when all async preview are finished
var counter = 0;
function tryFinished() {
if(counter === onAsyncPreviewCallbackList.length) {
onPreviewFinished();
}
}
_.each(onAsyncPreviewCallbackList, function(asyncPreviewCallback) {
asyncPreviewCallback(function() {
counter++;
tryFinished();
});
});
tryFinished();
};
$(function() {
// Create accordion in settings dialog
_.each(extensionList, createSettings);
});
return extensionMgr;
});

View File

@ -0,0 +1,58 @@
define([
"jquery",
"underscore"
], function($, _) {
var buttonPublish = {
extensionId: "buttonPublish",
extensionName: 'Button "Publish"',
optional: true,
settingsBloc: '<p>Adds a "Publish document" button in the navigation bar.</p>'
};
var currentFileDesc = undefined;
var publishRunning = false;
var hasPublications = false;
var isOffline = false;
// Enable/disable the button
function updateButtonState() {
if(publishRunning === true || hasPublications === false || isOffline === true) {
$(".action-force-publish").addClass("disabled");
}
else {
$(".action-force-publish").removeClass("disabled");
}
};
buttonPublish.onPublishRunning = function(isRunning) {
publishRunning = isRunning;
updateButtonState();
};
buttonPublish.onOfflineChanged = function(isOfflineParameter) {
isOffline = isOfflineParameter;
updateButtonState();
};
// Check that current file has publications
var checkPublication = function() {
if(_.size(currentFileDesc.publishLocations) === 0) {
hasPublications = false;
}
else {
hasPublications = true;
}
updateButtonState();
};
buttonPublish.onFileSelected = function(fileDesc) {
currentFileDesc = fileDesc;
checkPublication();
};
buttonPublish.onPublishRemoved = checkPublication;
buttonPublish.onNewPublishSuccess = checkPublication;
return buttonPublish;
});

View File

@ -1,12 +1,13 @@
define( [ "jquery", "underscore" ], function($) {
define([
"jquery",
"underscore"
], function($, _) {
var sharingButton = {
extensionId: "sharingButton",
extensionName: "Sharing button",
var buttonShare = {
extensionId: "buttonShare",
extensionName: 'Button "Share"',
optional: true,
settingsBloc: [
'<p>Adds a "Share document" button in the navigation bar.</p>'
].join("")
settingsBloc: '<p>Adds a "Share document" button in the navigation bar.</p>'
};
var fileDesc = undefined;
@ -14,8 +15,7 @@ define( [ "jquery", "underscore" ], function($) {
'<div class="input-prepend">',
'<a href="<%= link %>" class="add-on" title="Sharing location"><i class="icon-link"></i></a>',
'<input class="span2" type="text" value="<%= link %>" readonly />',
'</div>'
].join("");
'</div>'].join("");
var refreshDocumentSharing = function(fileDescParameter) {
if(fileDescParameter !== undefined && fileDescParameter !== fileDesc) {
return;
@ -39,14 +39,14 @@ define( [ "jquery", "underscore" ], function($) {
});
};
sharingButton.onFileSelected = function(fileDescParameter) {
buttonShare.onFileSelected = function(fileDescParameter) {
fileDesc = fileDescParameter;
refreshDocumentSharing(fileDescParameter);
};
sharingButton.onNewPublishSuccess = refreshDocumentSharing;
sharingButton.onPublishRemoved = refreshDocumentSharing;
buttonShare.onNewPublishSuccess = refreshDocumentSharing;
buttonShare.onPublishRemoved = refreshDocumentSharing;
return sharingButton;
return buttonShare;
});

View File

@ -0,0 +1,55 @@
define([
"jquery",
"underscore"
], function($, _) {
var buttonSync = {
extensionId: "buttonSync",
extensionName: 'Button "Synchronize"',
optional: true,
settingsBloc: '<p>Adds a "Synchronize documents" button in the navigation bar.</p>'
};
var syncRunning = false;
var uploadPending = false;
var isOffline = false;
// Enable/disable the button
function updateButtonState() {
if(syncRunning === true || uploadPending === false || isOffline) {
$(".action-force-sync").addClass("disabled");
}
else {
$(".action-force-sync").removeClass("disabled");
}
};
buttonSync.onSyncRunning = function(isRunning) {
syncRunning = isRunning;
uploadPending = true;
updateButtonState();
};
buttonSync.onSyncSuccess = function() {
uploadPending = false;
updateButtonState();
};
buttonSync.onOfflineChanged = function(isOfflineParameter) {
isOffline = isOfflineParameter;
updateButtonState();
};
// Check that a file has synchronized locations
var checkSynchronization = function(fileDesc) {
if(_.size(fileDesc.syncLocations) !== 0) {
uploadPending = true;
updateButtonState();
}
};
buttonSync.onFileChanged = checkSynchronization;
buttonSync.onTitleChanged = checkSynchronization;
return buttonSync;
});

View File

@ -1,64 +1,75 @@
define( [ "jquery", "underscore" ], function($) {
define([
"jquery",
"underscore"
], function($, _) {
var documentSelector = {
extensionId: "documentSelector",
extensionName: "Document selector",
settingsBloc: [
'<p>Builds the "Open document" dropdown menu.</p>'
].join("")
settingsBloc: '<p>Builds the "Open document" dropdown menu.</p>'
};
var fileSystemDescriptor = undefined;
documentSelector.onFileSystemLoaded = function(fileSystemDescriptorParameter) {
fileSystemDescriptor = fileSystemDescriptorParameter;
var fileSystem = undefined;
documentSelector.onFileSystemCreated = function(fileSystemParameter) {
fileSystem = fileSystemParameter;
};
var fileDesc = undefined;
var updateSelector = function() {
var sortedDescriptor = _.sortBy(fileSystemDescriptor, function(fileDesc) {
return fileDesc.title.toLowerCase();
});
var fileMgr = undefined;
documentSelector.onFileMgrCreated = function(fileMgrParameter) {
fileMgr = fileMgrParameter;
};
var liMap = undefined;
var buildSelector = function() {
function composeTitle(fileDesc) {
var result = [];
var syncAttributesList = _.values(fileDesc.syncLocations);
var publishAttributesList = _.values(fileDesc.publishLocations);
var attributesList = syncAttributesList.concat(publishAttributesList);
_.chain(attributesList).sortBy(function(attributes) {
return attributes.provider;
return attributes.provider.providerId;
}).each(function(attributes) {
result.push('<i class="icon-' + attributes.provider + '"></i>');
result.push('<i class="icon-' + attributes.provider.providerId + '"></i>');
});
result.push(" ");
result.push(fileDesc.title);
return result.join("");
}
liMap = {};
$("#file-selector li:not(.stick)").empty();
_.each(sortedDescriptor, function(fileDescToPrint) {
var a = $("<a>").html(composeTitle(fileDescToPrint.fileIndex));
_.chain(
fileSystem
).sortBy(function(fileDesc) {
return fileDesc.title.toLowerCase();
}).each(function(fileDesc) {
var a = $('<a href="#">').html(composeTitle(fileDesc)).click(function() {
if(liMap[fileDesc.fileIndex].is(".disabled")) {
fileMgr.selectFile(fileDesc);
}
});
var li = $("<li>").append(a);
if (fileDescToPrint === fileDesc) {
li.addClass("disabled");
} else {
a.prop("href", "#").click(function() {
fileManager.selectFile(fileDescToPrint);
});
}
liMap[fileDesc.fileIndex] = li;
$("#file-selector").append(li);
});
};
documentSelector.onFileSelected = function(fileDescParameter) {
fileDesc = fileDescParameter;
updateSelector();
documentSelector.onFileSelected = function(fileDesc) {
if(liMap === undefined) {
buildSelector();
}
$("#file-selector li:not(.stick)").removeClass("disabled");
liMap[fileDesc.fileIndex].addClass("disabled");
};
documentSelector.onTitleChanged = updateSelector;
documentSelector.onSyncExportSuccess = updateSelector;
documentSelector.onSyncRemoved = updateSelector;
documentSelector.onNewPublishSuccess = updateSelector;
documentSelector.onPublishRemoved = updateSelector;
documentSelector.onFileCreated = buildSelector;
documentSelector.onFileDeleted = buildSelector;
documentSelector.onTitleChanged = buildSelector;
documentSelector.onSyncExportSuccess = buildSelector;
documentSelector.onSyncRemoved = buildSelector;
documentSelector.onNewPublishSuccess = buildSelector;
documentSelector.onPublishRemoved = buildSelector;
return documentSelector;

View File

@ -1,11 +1,12 @@
define( [ "jquery", "underscore" ], function($) {
define([
"jquery",
"underscore"
], function($, _) {
var documentTitle = {
extensionId: "documentTitle",
extensionName: "Document title",
settingsBloc: [
'<p>Responsible for showing the document title in the navigation bar.</p>'
].join("")
settingsBloc: '<p>Responsible for showing the document title in the navigation bar.</p>'
};
var layout = undefined;
@ -15,7 +16,7 @@ define( [ "jquery", "underscore" ], function($) {
var fileDesc = undefined;
var updateTitle = function(fileDescParameter) {
if(fileDescParameter !== undefined && fileDescParameter !== fileDesc) {
if(fileDescParameter !== fileDesc) {
return;
}
@ -25,9 +26,9 @@ define( [ "jquery", "underscore" ], function($) {
var publishAttributesList = _.values(fileDesc.publishLocations);
var attributesList = syncAttributesList.concat(publishAttributesList);
_.chain(attributesList).sortBy(function(attributes) {
return attributes.provider;
return attributes.provider.providerId;
}).each(function(attributes) {
result.push('<i class="icon-' + attributes.provider + '"></i>');
result.push('<i class="icon-' + attributes.provider.providerId + '"></i>');
});
result.push(" ");
result.push(fileDesc.title);

View File

@ -1,16 +1,17 @@
define( [ "jquery", "underscore" ], function($) {
define([
"jquery",
"underscore"
], function($, _) {
var managePublication = {
extensionId: "managePublication",
extensionName: "Manage Publication",
settingsBloc: [
'<p>Populates the "Manage publication" dialog box.</p>'
].join("")
settingsBloc: '<p>Populates the "Manage publication" dialog box.</p>'
};
var fileManager = undefined;
manageSynchronization.onFileManagerCreated = function(fileManagerParameter) {
fileManager = fileManagerParameter;
var fileMgr = undefined;
managePublication.onFileMgrCreated = function(fileMgrParameter) {
fileMgr = fileMgrParameter;
};
var fileDesc = undefined;
@ -46,7 +47,7 @@ define( [ "jquery", "underscore" ], function($) {
publishDesc: publishDesc
}));
lineElement.append($(removeButtonTemplate).click(function() {
fileManager.removePublish(publishAttributes);
fileMgr.removePublish(publishAttributes);
}));
publishList.append(lineElement);
});

View File

@ -1,16 +1,17 @@
define( [ "jquery", "underscore" ], function($) {
define([
"jquery",
"underscore"
], function($, _) {
var manageSynchronization = {
extensionId: "manageSynchronization",
extensionName: "Manage Synchronization",
settingsBloc: [
'<p>Populates the "Manage synchronization" dialog box.</p>'
].join("")
settingsBloc: '<p>Populates the "Manage synchronization" dialog box.</p>'
};
var fileManager = undefined;
manageSynchronization.onFileManagerCreated = function(fileManagerParameter) {
fileManager = fileManagerParameter;
var fileMgr = undefined;
manageSynchronization.onFileMgrCreated = function(fileMgrParameter) {
fileMgr = fileMgrParameter;
};
var fileDesc = undefined;
@ -42,7 +43,7 @@ define( [ "jquery", "underscore" ], function($) {
syncDesc: syncDesc
}));
lineElement.append($(removeButtonTemplate).click(function() {
fileManager.removeSync(syncAttributes);
fileMgr.removeSync(syncAttributes);
}));
syncList.append(lineElement);
});

View File

@ -1,4 +1,7 @@
define( [ "utils", "Markdown.Extra" ], function(utils) {
define([
"utils",
"lib/Markdown.Extra"
], function(utils) {
var markdownExtra = {
extensionId: "markdownExtra",

View File

@ -1,4 +1,6 @@
define( [ "MathJax" ], function($) {
define([
"lib/MathJax"
], function() {
var mathJax = {
extensionId: "mathJax",

View File

@ -1,4 +1,8 @@
define( [ "jquery", "jgrowl", "underscore" ], function($) {
define([
"jquery",
"underscore",
"jgrowl"
], function($, _, jGrowl) {
var notifications = {
extensionId: "notifications",
@ -6,15 +10,15 @@ define( [ "jquery", "jgrowl", "underscore" ], function($) {
defaultConfig: {
showingTime: 5000
},
settingsBloc: "<p>Shows notification messages in the bottom-right corner of the screen.</p>"
settingsBloc: '<p>Shows notification messages in the bottom-right corner of the screen.</p>'
};
notifications.onReady = function() {
// jGrowl configuration
$.jGrowl.defaults.life = notifications.config.showingTime;
$.jGrowl.defaults.closer = false;
$.jGrowl.defaults.closeTemplate = '';
$.jGrowl.defaults.position = 'bottom-right';
jGrowl.defaults.life = notifications.config.showingTime;
jGrowl.defaults.closer = false;
jGrowl.defaults.closeTemplate = '';
jGrowl.defaults.position = 'bottom-right';
};
function showMessage(msg, iconClass, options) {
@ -30,15 +34,22 @@ define( [ "jquery", "jgrowl", "underscore" ], function($) {
}
options = options || {};
iconClass = iconClass || "icon-info-sign";
$.jGrowl("<i class='icon-white " + iconClass + "'></i> " + _.escape(msg), options);
jGrowl("<i class='icon-white " + iconClass + "'></i> " + _.escape(msg), options);
}
notifications.onMessage = function(message) {
console.log(message);
showMessage(message);
};
notifications.onError = function(error) {
showMessage(error, "icon-warning-sign");
console.error(error);
if(_.isString(error)) {
showMessage(error, "icon-warning-sign");
}
else if(_.isObject(error)) {
showMessage(error.message, "icon-warning-sign");
}
};
notifications.onOfflineChanged = function(isOffline) {

View File

@ -1,4 +1,8 @@
define( [ "jquery", "underscore" ], function($) {
define([
"jquery",
"underscore",
"lib/css_browser_selector"
], function($, _) {
var scrollLink = {
extensionId: "scrollLink",
@ -7,8 +11,8 @@ define( [ "jquery", "underscore" ], function($) {
settingsBloc: [
'<p>Binds together editor and preview scrollbars.</p>',
'<blockquote class="muted"><b>NOTE:</b> ',
'The mapping between Markdown and HTML is based on the position of the title elements (h1, h2, ...) in the page. ',
'Therefore, if your document does not contain any title, the mapping will be linear and consequently less accurate.',
'The mapping between Markdown and HTML is based on the position of the title elements (h1, h2, ...) in the page. ',
'Therefore, if your document does not contain any title, the mapping will be linear and consequently less accurate.',
'</bloquote>'
].join("")
};

View File

@ -1,25 +1,16 @@
define( [ "jquery", "underscore" ], function($) {
define([
"jquery",
"underscore",
"utils"
], function($, _, utils) {
var toc = {
extensionId: "toc",
extensionName: "Table Of Content",
optional: true,
settingsBloc: [
'<p>Generates tables of content using the marker [TOC].</p>'
].join("")
settingsBloc: '<p>Generates tables of content using the marker [TOC].</p>'
};
// Used to generate an anchor
function slugify(text)
{
return text.toLowerCase()
.replace(/\s+/g, '-') // Replace spaces with -
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
.replace(/\-\-+/g, '-') // Replace multiple - with single -
.replace(/^-+/, '') // Trim - from start of text
.replace(/-+$/, ''); // Trim - from end of text
}
// TOC element description
function TocElement(tagName, anchor, text) {
this.tagName = tagName;
@ -83,7 +74,7 @@ define( [ "jquery", "underscore" ], function($) {
function buildToc() {
var anchorList = {};
function createAnchor(element) {
var id = element.prop("id") || slugify(element.text());
var id = element.prop("id") || utils.slugify(element.text());
var anchor = id;
var index = 0;
while(_.has(anchorList, anchor)) {

View File

@ -0,0 +1,24 @@
define([
"jquery",
"underscore"
], function($, _) {
var workingIndicator = {
extensionId: "workingIndicator",
extensionName: "Working indicator",
settingsBloc: '<p>Displays an animated image when a network operation is running.</p>'
};
workingIndicator.onAsyncRunning = function(isRunning) {
if (isRunning === false) {
$(".working-indicator").removeClass("show");
$("body").removeClass("working");
} else {
$(".working-indicator").addClass("show");
$("body").addClass("working");
}
};
return workingIndicator;
});

View File

@ -1,53 +1,30 @@
define([
"jquery",
"underscore",
"core",
"utils",
"settings",
"extension-manager",
"synchronizer",
"publisher",
"sharing",
"text!../WELCOME.md",
"underscore"
], function($, core, utils, extensionManager, synchronizer, publisher, sharing, welcomeContent) {
"file-system",
"lib/text!../WELCOME.md"
], function($, _, core, utils, settings, extensionMgr, fileSystem, welcomeContent) {
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 = {
fileIndex : 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);
};
var fileMgr = {};
// Defines the current file
var currentFile = (function() {
var currentFileIndex = localStorage["file.current"];
if(currentFileIndex !== undefined) {
return fileSystemDescriptor[currentFileIndex];
var fileIndex = localStorage["file.current"];
if(fileIndex !== undefined) {
return fileSystem[fileIndex];
}
})();
fileManager.getCurrentFile = function() {
fileMgr.getCurrentFile = function() {
return currentFile;
};
fileManager.isCurrentFile = function(fileDesc) {
fileMgr.isCurrentFile = function(fileDesc) {
return fileDesc === currentFile;
};
fileManager.setCurrentFile = function(fileDesc) {
fileMgr.setCurrentFile = function(fileDesc) {
currentFile = fileDesc;
if(fileDesc === undefined) {
localStorage.removeItem("file.current");
@ -58,24 +35,21 @@ define([
};
// Caution: this function recreate the editor (reset undo operations)
fileManager.selectFile = function(fileDesc) {
fileMgr.selectFile = function(fileDesc) {
var fileSystemSize = _.size(fileSystem);
// If no file create one
if (_.size(fileSystemDescriptor) === 0) {
fileDesc = fileManager.createFile(WELCOME_DOCUMENT_TITLE, welcomeContent);
if (_.size(fileSystem) === 0) {
fileDesc = fileMgr.createFile(WELCOME_DOCUMENT_TITLE, welcomeContent);
}
if(fileDesc === undefined) {
// If no file is selected take the last created
fileDesc = fileSystemDescriptor[_.keys(fileSystemDescriptor)[fileSystemDescriptor.length - 1]];
fileDesc = fileSystem[_.keys(fileSystem)[fileSystemSize - 1]];
}
fileManager.setCurrentFile(fileDesc);
fileMgr.setCurrentFile(fileDesc);
// Update the file titles
fileManager.updateFileTitles();
publisher.notifyPublish();
// Notify extensions
extensionManager.onFileSelected(fileDesc);
extensionMgr.onFileSelected(fileDesc);
// Hide the viewer pencil button
if(fileDesc.fileIndex == TEMPORARY_FILE_INDEX) {
@ -89,18 +63,18 @@ define([
$("#wmd-input").val(localStorage[fileDesc.fileIndex + ".content"]);
core.createEditor(function() {
// Callback to save content when textarea changes
fileManager.saveFile();
fileMgr.saveFile();
});
};
fileManager.createFile = function(title, content, syncLocations, isTemporary) {
content = content !== undefined ? content : core.settings.defaultContent;
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;
var indicator = 2;
while(_.some(fileSystemDescriptor, function(fileDesc) {
while(_.some(fileSystem, function(fileDesc) {
return fileDesc.title == title;
})) {
title = DEFAULT_FILE_TITLE + indicator++;
@ -112,7 +86,7 @@ define([
if(!isTemporary) {
do {
fileIndex = "file." + utils.randomString();
} while(_.has(fileSystemDescriptor, fileIndex));
} while(_.has(fileSystem, fileIndex));
}
// Create the file in the localStorage
@ -137,27 +111,27 @@ define([
// Add the index to the file list
if(!isTemporary) {
localStorage["file.list"] += fileIndex + ";";
fileSystemDescriptor[fileIndex] = fileDesc;
extensionManager.onFileCreated(fileDesc);
fileSystem[fileIndex] = fileDesc;
extensionMgr.onFileCreated(fileDesc);
}
return fileDesc;
};
fileManager.deleteFile = function(fileDesc) {
fileDesc = fileDesc || fileManager.getCurrentFile();
if(fileManager.isCurrentFile(fileDesc)) {
fileMgr.deleteFile = function(fileDesc) {
fileDesc = fileDesc || fileMgr.getCurrentFile();
if(fileMgr.isCurrentFile(fileDesc)) {
// Unset the current fileDesc
fileManager.setCurrentFile();
fileMgr.setCurrentFile();
}
// Remove synchronized locations
_.each(fileDesc.syncLocations, function(syncAttributes) {
fileManager.removeSync(syncAttributes, true);
fileMgr.removeSync(syncAttributes, true);
});
// Remove publish locations
_.each(fileDesc.publishLocations, function(publishAttributes) {
fileManager.removePublish(publishAttributes, true);
fileMgr.removePublish(publishAttributes, true);
});
// Remove the index from the file list
@ -168,30 +142,29 @@ define([
localStorage.removeItem(fileIndex + ".content");
localStorage.removeItem(fileIndex + ".sync");
localStorage.removeItem(fileIndex + ".publish");
fileSystemDescriptor.removeItem(fileIndex);
extensionManager.onFileDeleted(fileDesc);
fileSystem.removeItem(fileIndex);
extensionMgr.onFileDeleted(fileDesc);
};
// Save current file in localStorage
fileManager.saveFile = function() {
fileMgr.saveFile = function() {
var content = $("#wmd-input").val();
var fileDesc = fileManager.getCurrentFile();
var fileDesc = fileMgr.getCurrentFile();
localStorage[fileDesc.fileIndex + ".content"] = content;
extensionManager.onFileChanged(fileDesc);
synchronizer.notifyChange(fileDesc);
extensionMgr.onFileChanged(fileDesc);
};
// Add a synchronized location to a file
fileManager.addSync = function(fileDesc, syncAttributes) {
fileMgr.addSync = function(fileDesc, syncAttributes) {
localStorage[fileDesc.fileIndex + ".sync"] += syncAttributes.syncIndex + ";";
fileDesc.syncLocations[syncAttributes.syncIndex] = syncAttributes;
// addSync is only used for export, not for import
extensionManager.onSyncExportSuccess(fileDesc, syncAttributes);
extensionMgr.onSyncExportSuccess(fileDesc, syncAttributes);
};
// Remove a synchronized location
fileManager.removeSync = function(syncAttributes, skipExtensions) {
var fileDesc = fileManager.getFileFromSyncIndex(syncAttributes.syncIndex);
fileMgr.removeSync = function(syncAttributes, skipExtensions) {
var fileDesc = fileMgr.getFileFromSyncIndex(syncAttributes.syncIndex);
if(fileDesc !== undefined) {
localStorage[fileDesc.fileIndex + ".sync"] = localStorage[fileDesc.fileIndex + ".sync"].replace(";"
+ syncAttributes.syncIndex + ";", ";");
@ -200,26 +173,26 @@ define([
localStorage.removeItem(syncAttributes.syncIndex);
fileDesc.syncLocations.removeItem(syncIndex);
if(!skipExtensions) {
extensionManager.onSyncRemoved(fileDesc, syncAttributes);
extensionMgr.onSyncRemoved(fileDesc, syncAttributes);
}
};
// Get the file descriptor associated to a syncIndex
fileManager.getFileFromSyncIndex = function(syncIndex) {
return _.find(fileSystemDescriptor, function(fileDesc) {
fileMgr.getFileFromSyncIndex = function(syncIndex) {
return _.find(fileSystem, function(fileDesc) {
return _.has(fileDesc.syncLocations, syncIndex);
});
};
// Get syncAttributes from syncIndex
fileManager.getSyncAttributes = function(syncIndex) {
var fileDesc = fileManager.getFileFromSyncIndex(syncIndex);
fileMgr.getSyncAttributes = function(syncIndex) {
var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
return fileDesc && fileDesc.syncLocations[syncIndex];
};
// Returns true if provider has locations to synchronize
fileManager.hasSync = function(provider) {
return _.some(fileSystemDescriptor, function(fileDesc) {
fileMgr.hasSync = function(provider) {
return _.some(fileSystem, function(fileDesc) {
return _.some(fileDesc.syncLocations, function(syncAttributes) {
syncAttributes.provider == provider.providerId;
});
@ -227,33 +200,30 @@ define([
};
// Add a publishIndex (publish location) to a file
fileManager.addPublish = function(fileDesc, publishAttributes) {
fileMgr.addPublish = function(fileDesc, publishAttributes) {
localStorage[fileDesc.fileIndex + ".publish"] += publishAttributes.publishIndex + ";";
fileDesc.publishLocations[publishAttributes.publishIndex] = publishAttributes;
extensionManager.onNewPublishSuccess(fileDesc, publishAttributes);
extensionMgr.onNewPublishSuccess(fileDesc, publishAttributes);
};
// Remove a publishIndex (publish location)
fileManager.removePublish = function(publishAttributes, skipExtensions) {
var fileDesc = fileManager.getFileFromPublish(publishAttributes.publishIndex);
fileMgr.removePublish = function(publishAttributes, skipExtensions) {
var fileDesc = fileMgr.getFileFromPublish(publishAttributes.publishIndex);
if(fileDesc !== undefined) {
localStorage[fileDesc.fileIndex + ".publish"] = localStorage[fileDesc.fileIndex + ".publish"].replace(";"
+ publishAttributes.publishIndex + ";", ";");
if(fileManager.isCurrentFile(fileDesc)) {
publisher.notifyPublish();
}
}
// Remove publish attributes
localStorage.removeItem(publishAttributes.publishIndex);
fileDesc.publishLocations.removeItem(publishIndex);
if(!skipExtensions) {
extensionManager.onPublishRemoved(fileDesc, publishAttributes);
extensionMgr.onPublishRemoved(fileDesc, publishAttributes);
}
};
// Get the file descriptor associated to a publishIndex
fileManager.getFileFromPublish = function(publishIndex) {
return _.find(fileSystemDescriptor, function(fileDesc) {
fileMgr.getFileFromPublish = function(publishIndex) {
return _.find(fileSystem, function(fileDesc) {
return _.has(fileDesc.publishLocations, publishIndex);
});
};
@ -276,11 +246,12 @@ define([
}
core.onReady(function() {
fileManager.selectFile();
fileMgr.selectFile();
$(".action-create-file").click(function() {
var fileDesc = fileManager.createFile();
fileManager.selectFile(fileDesc);
var fileDesc = fileMgr.createFile();
fileMgr.selectFile(fileDesc);
var wmdInput = $("#wmd-input").focus().get(0);
if(wmdInput.setSelectionRange) {
wmdInput.setSelectionRange(0, 0);
@ -288,8 +259,8 @@ define([
$("#file-title").click();
});
$(".action-remove-file").click(function() {
fileManager.deleteFile();
fileManager.selectFile();
fileMgr.deleteFile();
fileMgr.selectFile();
});
$("#file-title").click(function() {
if(viewerMode === true) {
@ -305,15 +276,13 @@ define([
input.hide();
$("#file-title").show();
var title = $.trim(input.val());
var fileDesc = fileManager.getCurrentFile();
var fileDesc = fileMgr.getCurrentFile();
var fileIndexTitle = fileDesc.fileIndex + ".title";
if (title) {
if (title != localStorage[fileIndexTitle]) {
localStorage[fileIndexTitle] = title;
fileDesc.title = title;
fileManager.updateFileTitles();
synchronizer.notifyChange(fileDesc);
extensionManager.onTitleChanged(fileDesc);
extensionMgr.onTitleChanged(fileDesc);
}
}
input.val(localStorage[fileIndexTitle]);
@ -346,33 +315,17 @@ define([
});
$(".action-edit-document").click(function() {
var content = $("#wmd-input").val();
var title = fileManager.getCurrentFile().title;
var fileDesc = fileManager.createFile(title, content);
fileManager.selectFile(fileDesc);
var title = fileMgr.getCurrentFile().title;
var fileDesc = fileMgr.createFile(title, content);
fileMgr.selectFile(fileDesc);
window.location.href = ".";
});
$(".action-download-md").click(function() {
var content = $("#wmd-input").val();
var title = fileManager.getCurrentFile().title;
core.saveFile(content, title + ".md");
});
$(".action-download-html").click(function() {
var content = $("#wmd-preview").html();
var title = fileManager.getCurrentFile().title;
core.saveFile(content, title + ".html");
});
$(".action-download-template").click(function() {
var content = publisher.applyTemplate();
var title = fileManager.getCurrentFile().title;
core.saveFile(content, title + ".txt");
});
$(".action-welcome-file").click(function() {
var fileDesc = fileManager.createFile(WELCOME_DOCUMENT_TITLE, welcomeContent);
fileManager.selectFile(fileDesc);
var fileDesc = fileMgr.createFile(WELCOME_DOCUMENT_TITLE, welcomeContent);
fileMgr.selectFile(fileDesc);
});
});
core.setFileManager(fileManager);
extensionManager.onFileManagerCreated(fileManager);
return fileManager;
extensionMgr.onFileMgrCreated(fileMgr);
return fileMgr;
});

22
js/file-system.js Normal file
View File

@ -0,0 +1,22 @@
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;
});

View File

@ -1,4 +1,11 @@
define(["core", "utils", "extension-manager", "google-helper", "underscore"], function(core, utils, extensionManager, googleHelper) {
define([
"underscore",
"core",
"utils",
"extension-manager",
"file-manager",
"google-helper"
], function(_, core, utils, extensionMgr, fileMgr, googleHelper) {
var PROVIDER_GDRIVE = "gdrive";
@ -39,11 +46,11 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
var syncLocations = {};
syncLocations[syncAttributes.syncIndex] = syncAttributes;
var fileDesc = core.fileManager.createFile(file.title, file.content, syncLocations);
core.fileManager.selectFile(fileDesc);
var fileDesc = fileMgr.createFile(file.title, file.content, syncLocations);
fileMgr.selectFile(fileDesc);
fileDescList.push(fileDesc);
});
extensionManager.onSyncImportSuccess(fileDescList, gdriveProvider);
extensionMgr.onSyncImportSuccess(fileDescList, gdriveProvider);
});
});
};
@ -56,9 +63,9 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
var importIds = [];
_.each(ids, function(id) {
var syncIndex = createSyncIndex(id);
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex);
var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
if(fileDesc !== undefined) {
core.showError('"' + fileDesc.title + '" was already imported');
extensionMgr.onError('"' + fileDesc.title + '" was already imported');
return;
}
importIds.push(id);
@ -87,9 +94,9 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
}
// Check that file is not synchronized with an other one
var syncIndex = createSyncIndex(id);
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex);
var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
if(fileDesc !== undefined) {
core.showError('File ID is already synchronized with "' + fileDesc.title + '"');
extensionMgr.onError('File ID is already synchronized with "' + fileDesc.title + '"');
callback(true);
return;
}
@ -134,7 +141,7 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
var interestingChanges = [];
_.each(changes, function(change) {
var syncIndex = createSyncIndex(change.fileId);
var syncAttributes = core.fileManager.getSyncAttributes(syncIndex);
var syncAttributes = fileMgr.getSyncAttributes(syncIndex);
if(syncAttributes === undefined) {
return;
}
@ -155,11 +162,10 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
callback(error);
return;
}
var updateFileTitles = false;
_.each(changes, function(change) {
var syncAttributes = change.syncAttributes;
var syncIndex = syncAttributes.syncIndex;
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex);
var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
// No file corresponding (file may have been deleted locally)
if(fileDesc === undefined) {
return;
@ -167,8 +173,8 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
var localTitle = fileDesc.title;
// File deleted
if (change.deleted === true) {
core.showError('"' + localTitle + '" has been removed from Google Drive.');
core.fileManager.removeSync(syncAttributes);
extensionMgr.onError('"' + localTitle + '" has been removed from Google Drive.');
fileMgr.removeSync(syncAttributes);
return;
}
var localTitleChanged = syncAttributes.titleCRC != utils.crc32(localTitle);
@ -184,24 +190,23 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
// Conflict detection
if ((fileTitleChanged === true && localTitleChanged === true && remoteTitleChanged === true)
|| (fileContentChanged === true && localContentChanged === true && remoteContentChanged === true)) {
core.fileManager.createFile(localTitle + " (backup)", localContent);
updateFileTitles = true;
core.showMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.');
var backupFileDesc = fileMgr.createFile(localTitle + " (backup)", localContent);
extensionMgr.onTitleChanged(backupFileDesc);
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;
updateFileTitles = true;
core.showMessage('"' + localTitle + '" has been renamed to "' + file.title + '" on Google Drive.');
extensionMgr.onTitleChanged(fileDesc);
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;
core.showMessage('"' + file.title + '" has been updated from Google Drive.');
if(core.fileManager.isCurrentFile(fileDesc)) {
updateFileTitles = false; // Done by next function
core.fileManager.selectFile(); // Refresh editor
extensionMgr.onMessage('"' + file.title + '" has been updated from Google Drive.');
if(fileMgr.isCurrentFile(fileDesc)) {
fileMgr.selectFile(); // Refresh editor
}
}
// Update syncAttributes
@ -210,9 +215,6 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
syncAttributes.titleCRC = remoteTitleCRC;
localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
});
if(updateFileTitles) {
extensionManager.onTitleChanged();
}
localStorage[PROVIDER_GDRIVE + ".lastChangeId"] = newChangeId;
callback();
});
@ -264,18 +266,18 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
var syncLocations = {};
syncLocations[syncAttributes.syncIndex] = syncAttributes;
var fileDesc = core.fileManager.createFile(file.title, file.content, syncAttributes);
core.fileManager.selectFile(fileDesc);
core.showMessage('"' + file.title + '" created successfully on Google Drive.');
var fileDesc = fileMgr.createFile(file.title, file.content, syncAttributes);
fileMgr.selectFile(fileDesc);
extensionMgr.onMessage('"' + file.title + '" created successfully on Google Drive.');
});
}
else if (state.action == "open") {
var importIds = [];
_.each(state.ids, function(id) {
var syncIndex = createSyncIndex(id);
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex);
var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
if(fileDesc !== undefined) {
core.fileManager.selectFile(fileDesc);
fileMgr.selectFile(fileDesc);
}
else {
importIds.push(id);

View File

@ -1,4 +1,7 @@
define(["utils", "github-helper"], function(utils, githubHelper) {
define([
"utils",
"github-helper"
], function(utils, githubHelper) {
var PROVIDER_GIST = "gist";

View File

@ -1,4 +1,10 @@
define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
define([
"jquery",
"core",
"utils",
"extension-manager",
"async-runner"
], function($, core, utils, extensionMgr, asyncRunner) {
var connected = undefined;
var github = undefined;
@ -51,14 +57,14 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
task.chain();
return;
}
core.showMessage("Please make sure the Github authorization popup is not blocked by your browser.");
extensionMgr.onMessage("Please make sure the Github authorization popup is not blocked by your browser.");
var errorMsg = "Failed to retrieve a token from GitHub.";
// We add time for user to enter his credentials
task.timeout = ASYNC_TASK_LONG_TIMEOUT;
var code = undefined;
function getCode() {
localStorage.removeItem("githubCode");
authWindow = core.popupWindow(
authWindow = utils.popupWindow(
'github-oauth-client.html?client_id=' + GITHUB_CLIENT_ID,
'stackedit-github-oauth', 960, 600);
authWindow.focus();
@ -106,7 +112,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}
githubHelper.upload = function(reponame, branch, path, content, commitMsg, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask();
connect(task);
authenticate(task);
@ -145,7 +150,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
};
githubHelper.uploadGist = function(gistId, filename, isPublic, title, content, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask();
connect(task);
authenticate(task);
@ -184,7 +188,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
};
githubHelper.downloadGist = function(gistId, filename, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask();
connect(task);
// No need for authentication

View File

@ -1,4 +1,8 @@
define(["core", "utils", "github-helper"], function(core, utils, githubHelper) {
define([
"utils",
"settings",
"github-helper"
], function(utils, settings, githubHelper) {
var PROVIDER_GITHUB = "github";
@ -9,7 +13,7 @@ define(["core", "utils", "github-helper"], function(core, utils, githubHelper) {
};
githubProvider.publish = function(publishAttributes, title, content, callback) {
var commitMsg = core.settings.commitMsg;
var commitMsg = settings.commitMsg;
githubHelper.upload(publishAttributes.repository, publishAttributes.branch,
publishAttributes.path, content, commitMsg, callback);
};

View File

@ -1,4 +1,10 @@
define(["jquery", "core", "utils", "async-runner"], function($, core, utils, asyncRunner) {
define([
"jquery",
"core",
"utils",
"extension-manager",
"async-runner"
], function($, core, utils, extensionMgr, asyncRunner) {
var connected = false;
var authenticated = false;
@ -44,7 +50,7 @@ define(["jquery", "core", "utils", "async-runner"], function($, core, utils, asy
var immediate = true;
function localAuthenticate() {
if (immediate === false) {
core.showMessage("Please make sure the Google authorization popup is not blocked by your browser.");
extensionMgr.onMessage("Please make sure the Google authorization popup is not blocked by your browser.");
// If not immediate we add time for user to enter his credentials
task.timeout = ASYNC_TASK_LONG_TIMEOUT;
}
@ -74,7 +80,6 @@ define(["jquery", "core", "utils", "async-runner"], function($, core, utils, asy
}
googleHelper.upload = function(fileId, parentId, title, content, etag, callback) {
callback = callback || core.doNothing;
var result = undefined;
var task = asyncRunner.createTask();
connect(task);
@ -151,7 +156,6 @@ define(["jquery", "core", "utils", "async-runner"], function($, core, utils, asy
};
googleHelper.checkChanges = function(lastChangeId, callback) {
callback = callback || core.doNothing;
var changes = [];
var newChangeId = lastChangeId || 0;
var task = asyncRunner.createTask();
@ -202,7 +206,6 @@ define(["jquery", "core", "utils", "async-runner"], function($, core, utils, asy
};
googleHelper.downloadMetadata = function(ids, callback, skipAuth) {
callback = callback || core.doNothing;
var result = [];
var task = asyncRunner.createTask();
connect(task);
@ -255,7 +258,6 @@ define(["jquery", "core", "utils", "async-runner"], function($, core, utils, asy
};
googleHelper.downloadContent = function(objects, callback, skipAuth) {
callback = callback || core.doNothing;
var result = [];
var task = asyncRunner.createTask();
// Add some time for user to choose his files
@ -378,7 +380,6 @@ define(["jquery", "core", "utils", "async-runner"], function($, core, utils, asy
}
googleHelper.picker = function(callback) {
callback = callback || core.doNothing;
var ids = [];
var picker = undefined;
function hidePicker() {

View File

View File

@ -1,5 +1,5 @@
/** vim: et:ts=4:sw=4:sts=4
* @license RequireJS 2.1.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
* @license RequireJS 2.1.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details
*/
@ -12,7 +12,7 @@ var requirejs, require, define;
(function (global) {
var req, s, head, baseElement, dataMain, src,
interactiveScript, currentlyAddingScript, mainScript, subPath,
version = '2.1.5',
version = '2.1.6',
commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
jsSuffixRegExp = /\.js$/,
@ -22,7 +22,7 @@ var requirejs, require, define;
hasOwn = op.hasOwnProperty,
ap = Array.prototype,
apsp = ap.splice,
isBrowser = !!(typeof window !== 'undefined' && navigator && document),
isBrowser = !!(typeof window !== 'undefined' && navigator && window.document),
isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
//PS3 indicates loaded and complete, but need to wait for complete
//specifically. Sequence is 'loading', 'loaded', execution,
@ -134,6 +134,10 @@ var requirejs, require, define;
return document.getElementsByTagName('script');
}
function defaultOnError(err) {
throw err;
}
//Allow getting a global that expressed in
//dot notation, like 'a.b.c'.
function getGlobal(value) {
@ -500,7 +504,12 @@ var requirejs, require, define;
fn(defined[id]);
}
} else {
getModule(depMap).on(name, fn);
mod = getModule(depMap);
if (mod.error && name === 'error') {
fn(mod.error);
} else {
mod.on(name, fn);
}
}
}
@ -571,7 +580,13 @@ var requirejs, require, define;
id: mod.map.id,
uri: mod.map.url,
config: function () {
return (config.config && getOwn(config.config, mod.map.id)) || {};
var c,
pkg = getOwn(config.pkgs, mod.map.id);
// For packages, only support config targeted
// at the main module.
c = pkg ? getOwn(config.config, mod.map.id + '/' + pkg.main) :
getOwn(config.config, mod.map.id);
return c || {};
},
exports: defined[mod.map.id]
});
@ -840,8 +855,13 @@ var requirejs, require, define;
if (this.depCount < 1 && !this.defined) {
if (isFunction(factory)) {
//If there is an error listener, favor passing
//to that instead of throwing an error.
if (this.events.error) {
//to that instead of throwing an error. However,
//only do it for define()'d modules. require
//errbacks should not be called for failures in
//their callbacks (#699). However if a global
//onError is set, use that.
if ((this.events.error && this.map.isDefine) ||
req.onError !== defaultOnError) {
try {
exports = context.execCb(id, factory, depExports, exports);
} catch (e) {
@ -869,8 +889,8 @@ var requirejs, require, define;
if (err) {
err.requireMap = this.map;
err.requireModules = [this.map.id];
err.requireType = 'define';
err.requireModules = this.map.isDefine ? [this.map.id] : null;
err.requireType = this.map.isDefine ? 'define' : 'require';
return onError((this.error = err));
}
@ -1093,7 +1113,7 @@ var requirejs, require, define;
}));
if (this.errback) {
on(depMap, 'error', this.errback);
on(depMap, 'error', bind(this, this.errback));
}
}
@ -1605,7 +1625,7 @@ var requirejs, require, define;
},
/**
* Executes a module callack function. Broken out as a separate function
* Executes a module callback function. Broken out as a separate function
* solely to allow the build system to sequence the files in the built
* layer in the right sequence.
*
@ -1643,7 +1663,7 @@ var requirejs, require, define;
onScriptError: function (evt) {
var data = getScriptData(evt);
if (!hasPathFallback(data.id)) {
return onError(makeError('scripterror', 'Script error', evt, [data.id]));
return onError(makeError('scripterror', 'Script error for: ' + data.id, evt, [data.id]));
}
}
};
@ -1772,9 +1792,7 @@ var requirejs, require, define;
* function. Intercept/override it if you want custom error handling.
* @param {Error} err the error object.
*/
req.onError = function (err) {
throw err;
};
req.onError = defaultOnError;
/**
* Does the request to load a module for the browser case.
@ -1906,24 +1924,31 @@ var requirejs, require, define;
//baseUrl, if it is not already set.
dataMain = script.getAttribute('data-main');
if (dataMain) {
//Preserve dataMain in case it is a path (i.e. contains '?')
mainScript = dataMain;
//Set final baseUrl if there is not already an explicit one.
if (!cfg.baseUrl) {
//Pull off the directory of data-main for use as the
//baseUrl.
src = dataMain.split('/');
src = mainScript.split('/');
mainScript = src.pop();
subPath = src.length ? src.join('/') + '/' : './';
cfg.baseUrl = subPath;
dataMain = mainScript;
}
//Strip off any trailing .js since dataMain is now
//Strip off any trailing .js since mainScript is now
//like a module name.
dataMain = dataMain.replace(jsSuffixRegExp, '');
mainScript = mainScript.replace(jsSuffixRegExp, '');
//If mainScript is still a path, fall back to dataMain
if (req.jsExtRegExp.test(mainScript)) {
mainScript = dataMain;
}
//Put the data-main script in the files to load.
cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain];
cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
return true;
}
@ -1951,12 +1976,13 @@ var requirejs, require, define;
//This module may not have dependencies
if (!isArray(deps)) {
callback = deps;
deps = [];
deps = null;
}
//If no name, and callback is a function, then figure out if it a
//CommonJS thing with dependencies.
if (!deps.length && isFunction(callback)) {
if (!deps && isFunction(callback)) {
deps = [];
//Remove comments from the callback string,
//look for require calls, and pull them into the dependencies,
//but only if there are function args.

286
js/main-min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -2,19 +2,34 @@
requirejs.config({
waitSeconds: 0,
paths: {
MathJax: '../lib/MathJax/MathJax.js?config=TeX-AMS_HTML'
"jquery": "lib/jquery",
"underscore": "lib/underscore",
"jgrowl": "lib/jgrowl",
"lib/MathJax": '../lib/MathJax/MathJax.js?config=TeX-AMS_HTML'
},
shim: {
'jquery-ui': ['jquery'],
'bootstrap': ['jquery'],
'jgrowl': ['jquery'],
'layout': ['jquery-ui'],
'Markdown.Extra': ['Markdown.Converter', 'prettify'],
'Markdown.Editor': ['Markdown.Converter']
'lib/underscore': {
exports: '_'
},
'lib/jgrowl': {
deps: ['lib/jquery'],
exports: 'jQuery.jGrowl'
},
'lib/jquery-ui': ['lib/jquery'],
'lib/bootstrap': ['lib/jquery'],
'lib/layout': ['lib/jquery-ui'],
'lib/Markdown.Extra': ['lib/Markdown.Converter', 'lib/prettify'],
'lib/Markdown.Editor': ['lib/Markdown.Converter']
}
});
require(["jquery", "file-manager", "synchronizer", "publisher"], function($) {
require([
"jquery",
"core",
"synchronizer",
"publisher"
], function($, core) {
$(function() {
// If browser has detected a new application cache.
if (window.applicationCache) {
@ -25,5 +40,8 @@ require(["jquery", "file-manager", "synchronizer", "publisher"], function($) {
}
}, false);
}
core.setReady();
});
});

View File

@ -1,8 +1,12 @@
define([
"jquery",
"underscore",
"core",
"utils",
"settings",
"extension-manager",
"file-system",
"file-manager",
"sharing",
"blogger-provider",
"dropbox-provider",
@ -11,59 +15,44 @@ define([
"gdrive-provider",
"ssh-provider",
"tumblr-provider",
"wordpress-provider",
"underscore"
], function($, core, utils, extensionManager, sharing) {
"wordpress-provider"
], function($, _, core, utils, settings, extensionMgr, fileSystem, fileMgr, sharing) {
var publisher = {};
// Create a map with providerId: providerObject
var providerMap = _.chain(arguments)
.map(function(argument) {
return argument && argument.providerId && [argument.providerId, argument];
}).compact().object().value();
// Used to know if the current file has publications
var hasPublications = false;
// Create a map with providerId: providerModule
var providerMap = _.chain(
arguments
).map(function(argument) {
return argument && argument.providerId && [argument.providerId, argument];
}).compact().object().value();
// Allows external modules to update hasPublications flag
publisher.notifyPublish = function() {
var fileDesc = core.fileManager.getCurrentFile();
// Check that file has publications
if(_.size(fileDesc.publishLocations) === 0) {
hasPublications = false;
}
else {
hasPublications = true;
}
publisher.updatePublishButton();
};
// Used to enable/disable the publish button
publisher.updatePublishButton = function() {
if(publishRunning === true || hasPublications === false || core.isOffline) {
$(".action-force-publish").addClass("disabled");
}
else {
$(".action-force-publish").removeClass("disabled");
}
};
// Run updatePublishButton function on online/offline event
core.addOfflineListener(publisher.updatePublishButton);
// Retrieve publish locations from localStorage
_.each(fileSystem, function(fileDesc) {
_.chain(
localStorage[fileDesc.fileIndex + ".publish"].split(";")
).compact().each(function(publishIndex) {
var publishAttributes = JSON.parse(localStorage[publishIndex]);
// Store publishIndex
publishAttributes.publishIndex = publishIndex;
// Replace provider ID by provider module in attributes
publishAttributes.provider = providerMap[publishAttributes.provider];
fileDesc.publishLocations[publishIndex] = publishAttributes;
});
});
// Apply template to the current document
publisher.applyTemplate = function(publishAttributes) {
var fileDesc = core.fileManager.getCurrentFile();
var fileDesc = fileMgr.getCurrentFile();
try {
return _.template(core.settings.template, {
return _.template(settings.template, {
documentTitle: fileDesc.title,
documentMarkdown: $("#wmd-input").val(),
documentHTML: $("#wmd-preview").html(),
publishAttributes: publishAttributes
});
} catch(e) {
core.showError(e);
extensionMgr.onError(e);
throw e;
}
};
@ -105,7 +94,7 @@ define([
if(error !== undefined) {
var errorMsg = error.toString();
if(errorMsg.indexOf("|removePublish") !== -1) {
core.fileManager.removePublish(publishAttributes);
fileMgr.removePublish(publishAttributes);
}
if(errorMsg.indexOf("|stopPublish") !== -1) {
callback(error);
@ -124,15 +113,15 @@ define([
}
publishRunning = true;
publisher.updatePublishButton();
var fileDesc = fileManager.getCurrentFile();
extensionMgr.onPublishRunning(true);
var fileDesc = fileMgr.getCurrentFile();
publishTitle = fileDesc.title;
publishAttributesList = _.values(fileDesc.publishLocations);
publishLocation(function(errorFlag) {
publishRunning = false;
publisher.updatePublishButton();
extensionMgr.onPublishRunning(false);
if(errorFlag === undefined) {
extensionManager.onPublishSuccess(fileDesc);
extensionMgr.onPublishSuccess(fileDesc);
}
});
};
@ -144,8 +133,8 @@ define([
publishIndex = "publish." + utils.randomString();
} while(_.has(localStorage, publishIndex));
publishAttributes.publishIndex = publishIndex;
localStorage[publishIndex] = JSON.stringify(publishAttributes);
core.fileManager.addPublish(fileDesc, publishAttributes);
localStorage[publishIndex] = utils.serializeAttributes(publishAttributes);
fileMgr.addPublish(fileDesc, publishAttributes);
}
// Initialize the "New publication" dialog
@ -185,7 +174,7 @@ define([
}
// Perform provider's publishing
var fileDesc = core.fileManager.getCurrentFile();
var fileDesc = fileMgr.getCurrentFile();
var title = fileDesc.title;
var content = getPublishContent(publishAttributes);
provider.publish(publishAttributes, title, content, function(error) {
@ -193,8 +182,6 @@ define([
publishAttributes.provider = provider.providerId;
sharing.createLink(publishAttributes, function() {
createPublishIndex(fileDesc, publishAttributes);
publisher.notifyPublish();
core.fileManager.updateFileTitles();
});
}
});
@ -210,16 +197,16 @@ define([
// Retrieve file's publish locations from localStorage
publisher.populatePublishLocations = function(fileDesc) {
_.chain(localStorage[fileDesc.fileIndex + ".publish"].split(";"))
.compact()
.each(function(publishIndex) {
var publishAttributes = JSON.parse(localStorage[publishIndex]);
// Store publishIndex
publishAttributes.publishIndex = publishIndex;
// Replace provider ID by provider module in attributes
publishAttributes.provider = providerMap[publishAttributes.provider];
fileDesc.publishLocations[publishIndex] = publishAttributes;
});
_.chain(
localStorage[fileDesc.fileIndex + ".publish"].split(";")
).compact().each(function(publishIndex) {
var publishAttributes = JSON.parse(localStorage[publishIndex]);
// Store publishIndex
publishAttributes.publishIndex = publishIndex;
// Replace provider ID by provider module in attributes
publishAttributes.provider = providerMap[publishAttributes.provider];
fileDesc.publishLocations[publishIndex] = publishAttributes;
});
};
core.onReady(function() {
@ -249,8 +236,25 @@ define([
publisher.publish();
}
});
// Save As menu items
$(".action-download-md").click(function() {
var content = $("#wmd-input").val();
var title = fileMgr.getCurrentFile().title;
utils.saveAs(content, title + ".md");
});
$(".action-download-html").click(function() {
var content = $("#wmd-preview").html();
var title = fileMgr.getCurrentFile().title;
utils.saveAs(content, title + ".html");
});
$(".action-download-template").click(function() {
var content = publisher.applyTemplate();
var title = fileMgr.getCurrentFile().title;
utils.saveAs(content, title + ".txt");
});
});
extensionManager.onPublisherCreated(publisher);
extensionMgr.onPublisherCreated(publisher);
return publisher;
});

28
js/settings.js Normal file
View File

@ -0,0 +1,28 @@
define([
"underscore"
], function(_) {
var settings = {
layoutOrientation : "horizontal",
lazyRendering : true,
editorFontSize : 14,
defaultContent: "\n\n\n> Written with [StackEdit](http://benweet.github.io/stackedit/).",
commitMsg : "Published by http://benweet.github.io/stackedit",
template : [
'<!DOCTYPE html>\n',
'<html>\n',
'<head>\n',
'<title><%= documentTitle %></title>\n',
'</head>\n',
'<body><%= documentHTML %></body>\n',
'</html>'].join(""),
sshProxy : SSH_PROXY_URL,
extensionSettings: {}
};
if (_.has(localStorage, "settings")) {
_.extend(settings, JSON.parse(localStorage.settings));
}
return settings;
});

View File

@ -1,11 +1,24 @@
define(["jquery", "core", "utils", "async-runner", "download-provider", "gist-provider", "underscore"], function($, core, utils, asyncRunner) {
define([
"jquery",
"underscore",
"core",
"utils",
"extension-manager",
"file-system",
"file-manager",
"async-runner",
"download-provider",
"gist-provider"
], function($, _, core, utils, extensionMgr, fileMgr, asyncRunner) {
var sharing = {};
// Create a map with providerId: providerObject
var providerMap = _.chain(arguments)
.map(function(argument) {
return argument && argument.providerId && [argument.providerId, argument];
}).compact().object().value();
// Create a map with providerId: providerModule
var providerMap = _.chain(
arguments
).map(function(argument) {
return argument && argument.providerId && [argument.providerId, argument];
}).compact().object().value();
// Used to populate the "Sharing" dropdown box
var lineTemplate = ['<div class="input-prepend">',
@ -52,11 +65,12 @@ define(["jquery", "core", "utils", "async-runner", "download-provider", "gist-pr
url.push('=');
url.push(encodeURIComponent(attributes[attributeName]));
});
url = url.join("");
$.getJSON(
"https://api-ssl.bitly.com/v3/shorten",
{
"access_token": BITLY_ACCESS_TOKEN,
"longUrl": url.join("")
"longUrl": url
},
function(response)
{
@ -64,46 +78,22 @@ define(["jquery", "core", "utils", "async-runner", "download-provider", "gist-pr
shortUrl = response.data.url;
attributes.sharingLink = shortUrl;
}
else {
extensionMgr.onError("An error occured while creating sharing link.");
attributes.sharingLink = url;
}
task.chain();
}
);
});
function onFinish() {
if(shortUrl === undefined) {
localStorage["missingSharingLink"] = true;
}
callback(shortUrl);
callback();
}
task.onSuccess(onFinish);
task.onError(onFinish);
asyncRunner.addTask(task);
};
// Create the possible missing links
function checkMissingLinks() {
if(core.isOffline === true) {
return;
}
if(!_.has(localStorage, "missingSharingLink")) {
return;
}
localStorage.removeItem("missingSharingLink");
var fileDescList = core.fileManager.getFileList();
_.each(fileDescList, function(fileDesc) {
_.each(fileDescList.publishLocations, function(publishAttributes, publishIndex) {
sharing.createLink(publishAttributes, function(shortUrl) {
if(shortUrl !== undefined) {
localStorage[publishIndex] = utils.serializeAttributes(attributes);
}
});
});
});
}
// Periodically check that links are not missing
if(viewerMode === false) {
core.addPeriodicCallback(checkMissingLinks);
}
core.onReady(function() {
if(viewerMode === false) {
return;
@ -135,8 +125,8 @@ define(["jquery", "core", "utils", "async-runner", "download-provider", "gist-pr
if(error) {
return;
}
var fileDesc = core.fileManager.createFile(title, content, undefined, true);
core.fileManager.selectFile(fileDesc);
var fileDesc = fileMgr.createFile(title, content, undefined, true);
fileMgr.selectFile(fileDesc);
});
});

View File

@ -1,4 +1,8 @@
define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
define([
"jquery",
"core",
"async-runner"
], function($, core, asyncRunner) {
var sshHelper = {};
@ -14,7 +18,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}
sshHelper.upload = function(host, port, username, password, path, title, content, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask();
connect(task);
task.onRun(function() {

View File

@ -1,4 +1,7 @@
define([ "utils", "ssh-helper" ], function(utils, sshHelper) {
define([
"utils",
"ssh-helper"
], function(utils, sshHelper) {
var PROVIDER_SSH = "ssh";

View File

@ -1,5 +1,7 @@
// Setup an empty localStorage or upgrade an existing one
define( [ "underscore" ], function() {
// Setup an empty localStorage or upgrade an existing one
define([
"underscore"
], function(_) {
// Create the file system if not exist
if (localStorage["file.list"] === undefined) {
@ -122,8 +124,6 @@ define( [ "underscore" ], function() {
}
});
});
// Force creation of sharing links
localStorage["missingSharingLink"] = true;
version = "v6";
}

View File

@ -1,44 +1,37 @@
define([
"jquery",
"underscore",
"core",
"utils",
"extension-manager",
"file-system",
"file-manager",
"dropbox-provider",
"gdrive-provider",
"underscore"
], function($, core, utils, extensionManager) {
"gdrive-provider"
], function($, _, core, utils, extensionMgr, fileSystem, fileMgr) {
var synchronizer = {};
// Create a map with providerId: providerObject
var providerMap = _.chain(arguments)
.map(function(argument) {
return argument && argument.providerId && [argument.providerId, argument];
}).compact().object().value();
// Used to know if user can force synchronization
var uploadPending = false;
// Create a map with providerId: providerModule
var providerMap = _.chain(
arguments
).map(function(argument) {
return argument && argument.providerId && [argument.providerId, argument];
}).compact().object().value();
// Allows external modules to update uploadPending flag
synchronizer.notifyChange = function(fileDesc) {
// Check that file has synchronized locations
if(_.size(fileDesc.syncLocations) !== 0) {
uploadPending = true;
synchronizer.updateSyncButton();
}
};
// Used to enable/disable the synchronization button
synchronizer.updateSyncButton = function() {
if(syncRunning === true || uploadPending === false || core.isOffline) {
$(".action-force-sync").addClass("disabled");
}
else {
$(".action-force-sync").removeClass("disabled");
}
};
// Run updateSyncButton on online/offline event
core.addOfflineListener(synchronizer.updateSyncButton);
// Retrieve sync locations from localStorage
_.each(fileSystem, function(fileDesc) {
_.chain(
localStorage[fileDesc.fileIndex + ".sync"].split(";")
).compact().each(function(syncIndex) {
var syncAttributes = JSON.parse(localStorage[syncIndex]);
// Store syncIndex
syncAttributes.syncIndex = syncIndex;
// Replace provider ID by provider module in attributes
syncAttributes.provider = providerMap[syncAttributes.provider];
fileDesc.syncLocations[syncIndex] = syncAttributes;
});
});
// Force the synchronization
synchronizer.forceSync = function() {
@ -73,8 +66,6 @@ define([
if(uploadFlag === true) {
// If uploadFlag is true, request another upload cycle
uploadCycle = true;
// When page is refreshed, this flag is false but should be true here
uploadPending = true;
}
if(error) {
callback(error);
@ -121,7 +112,7 @@ define([
if(uploadCycle === true) {
// New upload cycle
uploadCycle = false;
uploadFileList = core.fileManager.getFileList();
uploadFileList = fileMgr.getFileList();
fileUp(callback);
}
else {
@ -139,7 +130,7 @@ define([
var provider = providerList.pop();
// Check that provider has files to sync
if(!core.fileManager.hasSync(provider)) {
if(!fileMgr.hasSync(provider)) {
providerDown(callback);
return;
}
@ -165,18 +156,18 @@ define([
var lastSync = 0;
synchronizer.sync = function() {
// If sync is already running or timeout is not reached or offline
if (syncRunning || lastSync + SYNC_PERIOD > core.currentTime || core.isOffline) {
if (syncRunning || lastSync + SYNC_PERIOD > utils.currentTime || core.isOffline) {
return;
}
syncRunning = true;
extensionMgr.onSyncRunning(true);
uploadCycle = true;
lastSync = core.currentTime;
synchronizer.updateSyncButton();
lastSync = utils.currentTime;
function isError(error) {
if(error !== undefined) {
syncRunning = false;
synchronizer.updateSyncButton();
extensionMgr.onSyncRunning(false);
return true;
}
return false;
@ -191,7 +182,8 @@ define([
return;
}
syncRunning = false;
uploadPending = false;
extensionMgr.onSyncRunning(false);
extensionMgr.onSyncSuccess();
});
});
};
@ -200,20 +192,6 @@ define([
core.addPeriodicCallback(synchronizer.sync);
}
// Retrieve file's sync locations from localStorage
publisher.populateSyncLocations = function(fileDesc) {
_.chain(localStorage[fileDesc.fileIndex + ".sync"].split(";"))
.compact()
.each(function(syncIndex) {
var syncAttributes = JSON.parse(localStorage[syncIndex]);
// Store syncIndex
syncAttributes.syncIndex = syncIndex;
// Replace provider ID by provider module in attributes
syncAttributes.provider = providerMap[syncAttributes.provider];
fileDesc.syncLocations[syncIndex] = syncAttributes;
});
};
// Initialize the export dialog
function initExportDialog(provider) {
@ -247,14 +225,14 @@ define([
$(".action-sync-export-" + provider.providerId).click(function(event) {
// Perform the provider's export
var fileDesc = core.fileManager.getCurrentFile();
var fileDesc = fileMgr.getCurrentFile();
var title = fileDesc.title;
var content = localStorage[fileDesc.fileIndex + ".content"];
provider.exportFile(event, title, content, function(error, syncAttributes) {
if(error) {
return;
}
core.fileManager.addSync(fileDesc, syncAttributes);
fileMgr.addSync(fileDesc, syncAttributes);
});
// Store input values as preferences for next time we open the export dialog
@ -266,19 +244,18 @@ define([
});
// Provider's manual export button
$(".action-sync-manual-" + provider.providerId).click(function(event) {
var fileDesc = core.fileManager.getCurrentFile();
var fileDesc = fileMgr.getCurrentFile();
var title = fileDesc.title;
var content = localStorage[fileDesc.fileIndex + ".content"];
provider.exportManual(event, title, content, function(error, syncAttributes) {
if(error) {
return;
}
core.fileManager.addSync(fileDesc, syncAttributes);
fileMgr.addSync(fileDesc, syncAttributes);
});
});
});
synchronizer.updateSyncButton();
$(".action-force-sync").click(function() {
if(!$(this).hasClass("disabled")) {
synchronizer.forceSync();
@ -286,6 +263,6 @@ define([
});
});
extensionManager.onSynchronizerCreated(synchronizer);
extensionMgr.onSynchronizerCreated(synchronizer);
return synchronizer;
});

View File

@ -1,4 +1,10 @@
define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
define([
"jquery",
"core",
"utils",
"extension-manager",
"async-runner"
], function($, core, utils, extensionMgr, asyncRunner) {
var oauthParams = undefined;
@ -30,7 +36,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
task.chain();
return;
}
core.showMessage("Please make sure the Tumblr authorization popup is not blocked by your browser.");
extensionMgr.onMessage("Please make sure the Tumblr authorization popup is not blocked by your browser.");
var errorMsg = "Failed to retrieve a token from Tumblr.";
// We add time for user to enter his credentials
task.timeout = ASYNC_TASK_LONG_TIMEOUT;
@ -48,7 +54,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}
function getVerifier() {
localStorage.removeItem("tumblrVerifier");
authWindow = core.popupWindow(
authWindow = utils.popupWindow(
'tumblr-oauth-client.html?oauth_token=' + oauth_object.oauth_token,
'stackedit-tumblr-oauth', 800, 600);
authWindow.focus();
@ -92,7 +98,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}
tumblrHelper.upload = function(blogHostname, postId, tags, format, title, content, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask();
connect(task);
authenticate(task);

View File

@ -1,4 +1,7 @@
define(["utils", "tumblr-helper"], function(utils, tumblrHelper) {
define([
"utils",
"tumblr-helper"
], function(utils, tumblrHelper) {
var PROVIDER_TUMBLR = "tumblr";

View File

@ -1,4 +1,8 @@
define([ "jquery", "underscore" ], function($) {
define([
"jquery",
"underscore",
"lib/FileSaver"
], function($, _) {
var utils = {};
@ -107,6 +111,16 @@ define([ "jquery", "underscore" ], function($) {
return $.trim(str);
};
// Slug function
utils.slugify = function(text) {
return text.toLowerCase()
.replace(/\s+/g, '-') // Replace spaces with -
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
.replace(/\-\-+/g, '-') // Replace multiple - with single -
.replace(/^-+/, '') // Trim - from start of text
.replace(/-+$/, ''); // Trim - from end of text
};
// Check an URL
utils.checkUrl = function(url, addSlash) {
if(!url) {
@ -242,11 +256,48 @@ define([ "jquery", "underscore" ], function($) {
return crc.toString(16);
};
// Create an centered popup window
utils.popupWindow = function(url, title, width, height) {
var left = (screen.width / 2) - (width / 2);
var top = (screen.height / 2) - (height / 2);
return window.open(
url,
title,
'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width='
+ width
+ ', height='
+ height
+ ', top='
+ top
+ ', left='
+ left);
};
// Export data on disk
utils.saveAs = function(content, filename) {
if(saveAs !== undefined) {
var blob = new Blob([content], {type: "text/plain;charset=utf-8"});
saveAs(blob, filename);
}
else {
var uriContent = "data:application/octet-stream;base64,"
+ utils.encodeBase64(content);
window.open(uriContent, 'file');
}
};
// Generates a random string
utils.randomString = function() {
return _.random(4294967296).toString(36);
};
// Time shared by others modules
utils.updateCurrentTime = function() {
utils.currentTime = new Date().getTime();
};
utils.updateCurrentTime();
// Serialize sync/publish attributes
utils.serializeAttributes = function(attributes) {
// Don't store sync/publish index

View File

@ -1,4 +1,10 @@
define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
define([
"jquery",
"core",
"utils",
"extension-manager",
"async-runner"
], function($, core, utils, extensionMgr, asyncRunner) {
var token = undefined;
@ -25,14 +31,14 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
task.chain();
return;
}
core.showMessage("Please make sure the Wordpress authorization popup is not blocked by your browser.");
extensionMgr.onMessage("Please make sure the Wordpress authorization popup is not blocked by your browser.");
var errorMsg = "Failed to retrieve a token from Wordpress.";
// We add time for user to enter his credentials
task.timeout = ASYNC_TASK_LONG_TIMEOUT;
var code = undefined;
function getCode() {
localStorage.removeItem("wordpressCode");
authWindow = core.popupWindow(
authWindow = utils.popupWindow(
'wordpress-oauth-client.html?client_id=' + WORDPRESS_CLIENT_ID,
'stackedit-wordpress-oauth', 960, 600);
authWindow.focus();
@ -76,7 +82,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}
wordpressHelper.upload = function(site, postId, tags, title, content, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask();
connect(task);
authenticate(task);

View File

@ -1,4 +1,7 @@
define(["utils", "wordpress-helper"], function(utils, wordpressHelper) {
define([
"utils",
"wordpress-helper"
], function(utils, wordpressHelper) {
var PROVIDER_WORDPRESS = "wordpress";

View File

@ -24,7 +24,7 @@
var require = { baseUrl : "js", deps : [ "main" + suffix ] };
var viewerMode = true;
</script>
<script src="js/require.js"></script>
<script src="js/lib/require.js"></script>
</head>
<body class="viewer">
<div id="navbar" class="navbar navbar-fixed-top ui-layout-north">