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 viewer.html
css/main-min.css css/main-min.css
js/main-min.js js/main-min.js
js/require.js js/lib/require.js
img/ajax-loader.gif img/ajax-loader.gif
img/glyphicons-halflings.png img/glyphicons-halflings.png
img/glyphicons-halflings-white.png img/glyphicons-halflings-white.png

47
css/main-min.css vendored
View File

@ -5513,6 +5513,12 @@ code {
h1 { h1 {
margin: 30px 0 30px; margin: 30px 0 30px;
} }
h4, h5, h6 {
line-height: 40px;
}
.toc ul {
list-style-type: none;
}
p, pre, blockquote { p, pre, blockquote {
margin: 0 0 20px; margin: 0 0 20px;
} }
@ -5727,9 +5733,48 @@ div.dropdown-menu i {
height: 80px; height: 80px;
max-width: 206px; 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; 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 { table {
margin-bottom: 20px; margin-bottom: 20px;
} }

View File

@ -19,13 +19,12 @@
document.write('<link href="css/main' + suffix + '.css" rel="stylesheet">'); document.write('<link href="css/main' + suffix + '.css" rel="stylesheet">');
var theme = localStorage.theme; var theme = localStorage.theme;
if (theme) { if (theme) {
document document.write('<link href="themes/' + theme + '/' + theme + '.css" rel="stylesheet">');
.write('<link href="themes/' + theme + '/' + theme + '.css" rel="stylesheet">');
} }
var require = { baseUrl : "js", deps : [ "main" + suffix ] }; var require = { baseUrl : "js", deps : [ "main" + suffix ] };
var viewerMode = false; var viewerMode = false;
</script> </script>
<script src="js/require.js"></script> <script src="js/lib/require.js"></script>
</head> </head>
<body> <body>
<div id="navbar" class="navbar navbar-fixed-top ui-layout-north"> <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 * Used to run asynchronous tasks sequentially (ajax mainly). An asynchronous
* task is composed of different callback types: onRun, onSuccess, onError * 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 = {}; var asyncRunner = {};
@ -81,7 +86,7 @@ define([ "core", "underscore" ], function(core) {
} }
error = error || new Error("Unknown error"); error = error || new Error("Unknown error");
if(error.message) { if(error.message) {
core.showError(error); extensionMgr.onError(error);
} }
runSafe(task, task.errorCallbacks, error); runSafe(task, task.errorCallbacks, error);
// Exit the current call stack // Exit the current call stack
@ -102,7 +107,7 @@ define([ "core", "underscore" ], function(core) {
} }
// Implement an exponential backoff // Implement an exponential backoff
var delay = Math.pow(2, task.retryCounter++) * 1000; var delay = Math.pow(2, task.retryCounter++) * 1000;
currentTaskStartTime = core.currentTime + delay; currentTaskStartTime = utils.currentTime + delay;
currentTaskRunning = false; currentTaskRunning = false;
asyncRunner.runTask(); asyncRunner.runTask();
}; };
@ -117,7 +122,7 @@ define([ "core", "underscore" ], function(core) {
// If there is a task currently running // If there is a task currently running
if (currentTaskRunning === true) { if (currentTaskRunning === true) {
// If the current task takes too long // 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.")); currentTask.error(new Error("A timeout occurred."));
} }
return; return;
@ -131,12 +136,12 @@ define([ "core", "underscore" ], function(core) {
// Dequeue an enqueued task // Dequeue an enqueued task
currentTask = taskQueue.shift(); currentTask = taskQueue.shift();
currentTaskStartTime = core.currentTime; currentTaskStartTime = utils.currentTime;
core.showWorkingIndicator(true); extensionMgr.onAsyncRunning(true);
} }
// Run the task // Run the task
if (currentTaskStartTime <= core.currentTime) { if (currentTaskStartTime <= utils.currentTime) {
currentTaskRunning = true; currentTaskRunning = true;
currentTask.chain(); currentTask.chain();
} }
@ -157,7 +162,7 @@ define([ "core", "underscore" ], function(core) {
currentTaskRunning = false; currentTaskRunning = false;
} }
if (taskQueue.length === 0) { if (taskQueue.length === 0) {
core.showWorkingIndicator(false); extensionMgr.onAsyncRunning(false);
} else { } else {
asyncRunner.runTask(); 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"; var PROVIDER_BLOGGER = "blogger";
@ -39,8 +43,9 @@ define(["utils", "google-helper"], function(utils, googleHelper) {
publishAttributes.labelList = []; publishAttributes.labelList = [];
var labels = utils.getInputTextValue("#input-publish-labels"); var labels = utils.getInputTextValue("#input-publish-labels");
if(labels !== undefined) { if(labels !== undefined) {
publishAttributes.labelList = _.chain(labels.split(",")) publishAttributes.labelList = _.chain(
.map(function(label) { labels.split(",")
).map(function(label) {
return utils.trim(label); return utils.trim(label);
}).compact().value(); }).compact().value();
} }

View File

@ -1,28 +1,18 @@
define([ define([
"jquery", "jquery",
"underscore",
"utils", "utils",
"settings",
"extension-manager", "extension-manager",
"bootstrap",
"layout",
"Markdown.Editor",
"storage", "storage",
"config", "config",
"underscore", "lib/bootstrap",
"FileSaver", "lib/layout",
"css_browser_selector" "lib/Markdown.Editor"
], function($, utils, extensionManager) { ], function($, _, utils, settings, extensionMgr) {
var core = {}; var core = {};
// For convenience
core.doNothing = function() {};
// Time shared by others modules
function updateCurrentTime() {
core.currentTime = new Date().getTime();
}
updateCurrentTime();
// Used for periodic tasks // Used for periodic tasks
var intervalId = undefined; var intervalId = undefined;
var periodicCallbacks = []; var periodicCallbacks = [];
@ -38,11 +28,11 @@ define([
function setUserActive() { function setUserActive() {
userReal = true; userReal = true;
userActive = true; userActive = true;
userLastActivity = core.currentTime; userLastActivity = utils.currentTime;
}; };
function isUserActive() { function isUserActive() {
if(userActive === true if(userActive === true
&& core.currentTime - userLastActivity > USER_IDLE_THRESHOLD) { && utils.currentTime - userLastActivity > USER_IDLE_THRESHOLD) {
userActive = false; userActive = false;
} }
return userActive && windowUnique; return userActive && windowUnique;
@ -50,7 +40,7 @@ define([
// Used to only have 1 window of the application in the same browser // Used to only have 1 window of the application in the same browser
var windowId = undefined; var windowId = undefined;
core.checkWindowUnique = function() { function checkWindowUnique() {
if(userReal === false || windowUnique === false) { if(userReal === false || windowUnique === false) {
return; return;
} }
@ -70,136 +60,65 @@ define([
keyboard: false 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 // Offline management
core.isOffline = false; core.isOffline = false;
var offlineTime = core.currentTime; var offlineTime = utils.currentTime;
var offlineListeners = [];
core.addOfflineListener = function(callback) {
offlineListeners.push(callback);
};
core.setOffline = function() { core.setOffline = function() {
offlineTime = core.currentTime; offlineTime = utils.currentTime;
if(core.isOffline === false) { if(core.isOffline === false) {
core.isOffline = true; core.isOffline = true;
extensionManager.onOfflineChanged(true); extensionMgr.onOfflineChanged(true);
_.each(offlineListeners, function(listener) {
listener();
});
} }
}; };
core.setOnline = function() { function setOnline() {
if(core.isOffline === true) { if(core.isOffline === true) {
core.isOffline = false; core.isOffline = false;
extensionManager.onOfflineChanged(false); extensionMgr.onOfflineChanged(false);
_.each(offlineListeners, function(listener) { }
listener();
});
} }
};
function checkOnline() { function checkOnline() {
// Try to reconnect if we are offline but we have some network // Try to reconnect if we are offline but we have some network
if (core.isOffline === true && navigator.onLine === true if (core.isOffline === true && navigator.onLine === true
&& offlineTime + CHECK_ONLINE_PERIOD < core.currentTime) { && offlineTime + CHECK_ONLINE_PERIOD < utils.currentTime) {
offlineTime = core.currentTime; offlineTime = utils.currentTime;
// Try to download anything to test the connection // Try to download anything to test the connection
$.ajax({ $.ajax({
url : "//www.google.com/jsapi", url : "//www.google.com/jsapi",
timeout : AJAX_TIMEOUT, dataType : "script" timeout : AJAX_TIMEOUT, dataType : "script"
}).done(function() { }).done(function() {
core.setOnline(); setOnline();
}); });
} }
} }
// Setting management // Load settings in settings dialog
core.settings = { function loadSettings() {
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() {
// Layout orientation // Layout orientation
utils.setInputRadio("radio-layout-orientation", core.settings.layoutOrientation); utils.setInputRadio("radio-layout-orientation", settings.layoutOrientation);
// Theme // Theme
utils.setInputValue("#input-settings-theme", localStorage.theme); utils.setInputValue("#input-settings-theme", localStorage.theme);
// Lazy rendering // Lazy rendering
utils.setInputChecked("#input-settings-lazy-rendering", core.settings.lazyRendering); utils.setInputChecked("#input-settings-lazy-rendering", settings.lazyRendering);
// Editor font size // Editor font size
utils.setInputValue("#input-settings-editor-font-size", core.settings.editorFontSize); utils.setInputValue("#input-settings-editor-font-size", settings.editorFontSize);
// Default content // Default content
utils.setInputValue("#textarea-settings-default-content", core.settings.defaultContent); utils.setInputValue("#textarea-settings-default-content", settings.defaultContent);
// Commit message // Commit message
utils.setInputValue("#input-settings-publish-commit-msg", core.settings.commitMsg); utils.setInputValue("#input-settings-publish-commit-msg", settings.commitMsg);
// Template // Template
utils.setInputValue("#textarea-settings-publish-template", core.settings.template); utils.setInputValue("#textarea-settings-publish-template", settings.template);
// SSH proxy // SSH proxy
utils.setInputValue("#input-settings-ssh-proxy", core.settings.sshProxy); utils.setInputValue("#input-settings-ssh-proxy", settings.sshProxy);
// Load extension settings // Load extension settings
extensionManager.onLoadSettings(); extensionMgr.onLoadSettings();
}; }
core.saveSettings = function(event) { // Save settings from settings dialog
function saveSettings(event) {
var newSettings = {}; var newSettings = {};
// Layout orientation // Layout orientation
@ -221,14 +140,14 @@ define([
// Save extension settings // Save extension settings
newSettings.extensionSettings = {}; newSettings.extensionSettings = {};
extensionManager.onSaveSettings(newSettings.extensionSettings, event); extensionMgr.onSaveSettings(newSettings.extensionSettings, event);
if(!event.isPropagationStopped()) { if(!event.isPropagationStopped()) {
$.extend(core.settings, newSettings); $.extend(settings, newSettings);
localStorage.settings = JSON.stringify(newSettings); localStorage.settings = JSON.stringify(settings);
localStorage.theme = theme; localStorage.theme = theme;
} }
}; }
// Create the layout // Create the layout
var layout = undefined; var layout = undefined;
@ -250,8 +169,8 @@ define([
center__minWidth : 200, center__minWidth : 200,
center__minHeight : 200 center__minHeight : 200
}; };
extensionManager.onLayoutConfigure(layoutGlobalConfig); extensionMgr.onLayoutConfigure(layoutGlobalConfig);
if (core.settings.layoutOrientation == "horizontal") { if (settings.layoutOrientation == "horizontal") {
$(".ui-layout-south").remove(); $(".ui-layout-south").remove();
$(".ui-layout-east").addClass("well").prop("id", "wmd-preview"); $(".ui-layout-east").addClass("well").prop("id", "wmd-preview");
layout = $('body').layout( layout = $('body').layout(
@ -261,7 +180,7 @@ define([
east__minSize : 200 east__minSize : 200
}) })
); );
} else if (core.settings.layoutOrientation == "vertical") { } else if (settings.layoutOrientation == "vertical") {
$(".ui-layout-east").remove(); $(".ui-layout-east").remove();
$(".ui-layout-south").addClass("well").prop("id", "wmd-preview"); $(".ui-layout-south").addClass("well").prop("id", "wmd-preview");
layout = $('body').layout( layout = $('body').layout(
@ -282,7 +201,7 @@ define([
layout.allowOverflow('north'); layout.allowOverflow('north');
}); });
extensionManager.onLayoutCreated(layout); extensionMgr.onLayoutCreated(layout);
}; };
// Create the PageDown editor // Create the PageDown editor
@ -320,7 +239,7 @@ define([
makePreview(); makePreview();
}; };
}; };
if(core.settings.lazyRendering === true) { if(settings.lazyRendering === true) {
var lastRefresh = 0; var lastRefresh = 0;
previewWrapper = function(makePreview) { previewWrapper = function(makePreview) {
//var debouncedMakePreview = _.debounce(makePreview, 500); //var debouncedMakePreview = _.debounce(makePreview, 500);
@ -340,8 +259,8 @@ define([
}; };
}; };
} }
extensionManager.onEditorConfigure(editor); extensionMgr.onEditorConfigure(editor);
editor.hooks.chain("onPreviewRefresh", extensionManager.onAsyncPreview); editor.hooks.chain("onPreviewRefresh", extensionMgr.onAsyncPreview);
// Convert email addresses (not managed by pagedown) // Convert email addresses (not managed by pagedown)
converter.hooks.chain("postConversion", function(text) { converter.hooks.chain("postConversion", function(text) {
@ -374,49 +293,25 @@ define([
$("#wmd-redo-button").append($("<i>").addClass("icon-share-alt")); $("#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 // onReady event callbacks
var readyCallbacks = []; var readyCallbacks = [];
core.onReady = function(callback) { core.onReady = function(callback) {
readyCallbacks.push(callback); readyCallbacks.push(callback);
runReadyCallbacks(); runReadyCallbacks();
}; };
var documentLoaded = false; var ready = false;
core.setReady = function() {
ready = true;
runReadyCallbacks();
};
function runReadyCallbacks() { function runReadyCallbacks() {
if(documentLoaded === true && core.fileManager !== undefined) { if(ready === true) {
_.each(readyCallbacks, function(callback) { _.each(readyCallbacks, function(callback) {
callback(); callback();
}); });
readyCallbacks = []; readyCallbacks = [];
} }
} }
$(function() {
documentLoaded = true;
runReadyCallbacks();
});
core.onReady(extensionManager.onReady); core.onReady(extensionManager.onReady);
core.onReady(function() { core.onReady(function() {
@ -428,7 +323,7 @@ define([
// listen to online/offline events // listen to online/offline events
$(window).on('offline', core.setOffline); $(window).on('offline', core.setOffline);
$(window).on('online', core.setOnline); $(window).on('online', setOnline);
if (navigator.onLine === false) { if (navigator.onLine === false) {
core.setOffline(); core.setOffline();
} }
@ -460,10 +355,10 @@ define([
// Settings loading/saving // Settings loading/saving
$(".action-load-settings").click(function() { $(".action-load-settings").click(function() {
core.loadSettings(); loadSettings();
}); });
$(".action-apply-settings").click(function(e) { $(".action-apply-settings").click(function(e) {
core.saveSettings(e); saveSettings(e);
if(!e.isPropagationStopped()) { if(!e.isPropagationStopped()) {
window.location.reload(); window.location.reload();
} }
@ -487,8 +382,8 @@ define([
// Editor's textarea // Editor's textarea
$("#wmd-input, #md-section-helper").css({ $("#wmd-input, #md-section-helper").css({
// Apply editor font size // Apply editor font size
"font-size": core.settings.editorFontSize + "px", "font-size": settings.editorFontSize + "px",
"line-height": Math.round(core.settings.editorFontSize * (20/14)) + "px" "line-height": Math.round(settings.editorFontSize * (20/14)) + "px"
}); });
// Manage tab key // Manage tab key
@ -564,8 +459,8 @@ define([
// Do periodic tasks // Do periodic tasks
intervalId = window.setInterval(function() { intervalId = window.setInterval(function() {
updateCurrentTime(); utils.updateCurrentTime();
core.checkWindowUnique(); checkWindowUnique();
if(isUserActive() === true || viewerMode === true) { if(isUserActive() === true || viewerMode === true) {
_.each(periodicCallbacks, function(callback) { _.each(periodicCallbacks, function(callback) {
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"; 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 client = undefined;
var authenticated = false; var authenticated = false;
@ -50,7 +56,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
var immediate = true; var immediate = true;
function localAuthenticate() { function localAuthenticate() {
if (immediate === false) { 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 // If not immediate we add time for user to enter his credentials
task.timeout = ASYNC_TASK_LONG_TIMEOUT; task.timeout = ASYNC_TASK_LONG_TIMEOUT;
} }
@ -77,7 +83,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
} }
dropboxHelper.upload = function(path, content, callback) { dropboxHelper.upload = function(path, content, callback) {
callback = callback || core.doNothing;
var result = undefined; var result = undefined;
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
connect(task); connect(task);
@ -106,7 +111,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}; };
dropboxHelper.checkChanges = function(lastChangeId, callback) { dropboxHelper.checkChanges = function(lastChangeId, callback) {
callback = callback || core.doNothing;
var changes = []; var changes = [];
var newChangeId = lastChangeId || 0; var newChangeId = lastChangeId || 0;
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
@ -143,7 +147,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}; };
dropboxHelper.downloadMetadata = function(paths, callback) { dropboxHelper.downloadMetadata = function(paths, callback) {
callback = callback || core.doNothing;
var result = []; var result = [];
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
connect(task); connect(task);
@ -177,7 +180,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}; };
dropboxHelper.downloadContent = function(objects, callback) { dropboxHelper.downloadContent = function(objects, callback) {
callback = callback || core.doNothing;
var result = []; var result = [];
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
connect(task); connect(task);
@ -289,7 +291,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
} }
dropboxHelper.picker = function(callback) { dropboxHelper.picker = function(callback) {
callback = callback || core.doNothing;
var paths = []; var paths = [];
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
// Add some time for user to choose his files // Add some time for user to choose his files
@ -312,7 +313,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
task.chain(); task.chain();
}; };
Dropbox.choose(options); 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() { task.onSuccess(function() {
callback(undefined, paths); 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"; var PROVIDER_DROPBOX = "dropbox";
@ -13,7 +19,7 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
return undefined; return undefined;
} }
if(!path.match(/^[^\\<>:"\|?\*]+$/)) { if(!path.match(/^[^\\<>:"\|?\*]+$/)) {
core.showError('"' + path + '" contains invalid characters.'); extensionMgr.onError('"' + path + '" contains invalid characters.');
return undefined; return undefined;
} }
if(path.indexOf("/") !== 0) { if(path.indexOf("/") !== 0) {
@ -51,11 +57,11 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes); localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
var syncLocations = {}; var syncLocations = {};
syncLocations[syncAttributes.syncIndex] = syncAttributes; syncLocations[syncAttributes.syncIndex] = syncAttributes;
var fileDesc = core.fileManager.createFile(file.name, file.content, syncLocations); var fileDesc = fileMgr.createFile(file.name, file.content, syncLocations);
core.fileManager.selectFile(fileDesc); fileMgr.selectFile(fileDesc);
fileDescList.push(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 = []; var importPaths = [];
_.each(paths, function(path) { _.each(paths, function(path) {
var syncIndex = createSyncIndex(path); var syncIndex = createSyncIndex(path);
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex); var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
if(fileDesc !== undefined) { if(fileDesc !== undefined) {
core.showError('"' + fileDesc.title + '" was already imported'); extensionMgr.onError('"' + fileDesc.title + '" was already imported');
return; return;
} }
importPaths.push(path); 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 // Check that file is not synchronized with an other one
var syncIndex = createSyncIndex(path); var syncIndex = createSyncIndex(path);
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex); var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
if(fileDesc !== undefined) { if(fileDesc !== undefined) {
var existingTitle = fileDesc.title; var existingTitle = fileDesc.title;
core.showError('File path is already synchronized with "' + existingTitle + '"'); extensionMgr.onError('File path is already synchronized with "' + existingTitle + '"');
callback(true); callback(true);
return; return;
} }
@ -143,7 +149,7 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
var interestingChanges = []; var interestingChanges = [];
_.each(changes, function(change) { _.each(changes, function(change) {
var syncIndex = createSyncIndex(change.path); var syncIndex = createSyncIndex(change.path);
var syncAttributes = core.fileManager.getSyncAttributes(syncIndex); var syncAttributes = fileMgr.getSyncAttributes(syncIndex);
if(syncAttributes === undefined) { if(syncAttributes === undefined) {
return; return;
} }
@ -164,11 +170,10 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
callback(error); callback(error);
return; return;
} }
var updateFileTitles = false;
_.each(changes, function(change) { _.each(changes, function(change) {
var syncAttributes = change.syncAttributes; var syncAttributes = change.syncAttributes;
var syncIndex = syncAttributes.syncIndex; var syncIndex = syncAttributes.syncIndex;
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex); var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
// No file corresponding (file may have been deleted locally) // No file corresponding (file may have been deleted locally)
if(fileDesc === undefined) { if(fileDesc === undefined) {
return; return;
@ -176,8 +181,8 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
var localTitle = fileDesc.title; var localTitle = fileDesc.title;
// File deleted // File deleted
if (change.wasRemoved === true) { if (change.wasRemoved === true) {
core.showError('"' + localTitle + '" has been removed from Dropbox.'); extensionMgr.onError('"' + localTitle + '" has been removed from Dropbox.');
core.fileManager.removeSync(syncAttributes); fileMgr.removeSync(syncAttributes);
return; return;
} }
var localContent = localStorage[fileDesc.fileIndex + ".content"]; var localContent = localStorage[fileDesc.fileIndex + ".content"];
@ -188,17 +193,16 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
var fileContentChanged = localContent != file.content; var fileContentChanged = localContent != file.content;
// Conflict detection // Conflict detection
if (fileContentChanged === true && localContentChanged === true && remoteContentChanged === true) { if (fileContentChanged === true && localContentChanged === true && remoteContentChanged === true) {
core.fileManager.createFile(localTitle + " (backup)", localContent); var backupFileDesc = fileMgr.createFile(localTitle + " (backup)", localContent);
updateFileTitles = true; extensionMgr.onTitleChanged(backupFileDesc);
core.showMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.'); extensionMgr.onMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.');
} }
// If file content changed // If file content changed
if(fileContentChanged && remoteContentChanged === true) { if(fileContentChanged && remoteContentChanged === true) {
localStorage[fileDesc.fileIndex + ".content"] = file.content; localStorage[fileDesc.fileIndex + ".content"] = file.content;
core.showMessage('"' + localTitle + '" has been updated from Dropbox.'); extensionMgr.onMessage('"' + localTitle + '" has been updated from Dropbox.');
if(core.fileManager.isCurrentFile(fileDesc)) { if(fileMgr.isCurrentFile(fileDesc)) {
updateFileTitles = false; // Done by next function fileMgr.selectFile(); // Refresh editor
core.fileManager.selectFile(); // Refresh editor
} }
} }
// Update syncAttributes // Update syncAttributes
@ -206,9 +210,6 @@ define(["core", "utils", "extension-manager", "dropbox-helper"], function(core,
syncAttributes.contentCRC = remoteContentCRC; syncAttributes.contentCRC = remoteContentCRC;
localStorage[syncIndex] = utils.serializeAttributes(syncAttributes); localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
}); });
if(updateFileTitles) {
extensionManager.onTitleChanged();
}
localStorage[PROVIDER_DROPBOX + ".lastChangeId"] = newChangeId; localStorage[PROVIDER_DROPBOX + ".lastChangeId"] = newChangeId;
callback(); callback();
}); });

View File

@ -1,27 +1,38 @@
define( [ define( [
"jquery", "jquery",
"utils",
"underscore", "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/notifications",
"extensions/markdown-extra", "extensions/markdown-extra",
"extensions/toc", "extensions/toc",
"extensions/math-jax", "extensions/math-jax",
"extensions/scroll-link" "extensions/scroll-link",
], function($, utils) { "lib/bootstrap"
], function($, _, utils, settings) {
var extensionManager = {}; var extensionMgr = {};
// Create a list of extensions // Create a list of extensions
var extensionList = _.chain(arguments) var extensionList = _.chain(
.map(function(argument) { arguments
).map(function(argument) {
return _.isObject(argument) && argument.extensionId && argument; return _.isObject(argument) && argument.extensionId && argument;
}).compact().value(); }).compact().value();
// Return every named callbacks implemented in extensions // Return every named callbacks implemented in extensions
function getExtensionCallbackList(hookName) { function getExtensionCallbackList(hookName) {
return _.chain(extensionList) return _.chain(
.map(function(extension) { extensionList
).map(function(extension) {
return extension.config.enabled && extension[hookName]; return extension.config.enabled && extension[hookName];
}).compact().value(); }).compact().value();
} }
@ -38,9 +49,9 @@ define( [
}; };
} }
// Add a Hook to the extensionManager // Add a Hook to the extensionMgr
function addHook(hookName) { function addHook(hookName) {
extensionManager[hookName] = createHook(hookName); extensionMgr[hookName] = createHook(hookName);
} }
var accordionTmpl = [ var accordionTmpl = [
@ -67,17 +78,15 @@ define( [
}))); })));
} }
extensionManager.init = function(extensionSettings) {
// Set extension config // Set extension config
extensionSettings = extensionSettings || {}; extensionSettings = settings.extensionSettings || {};
_.each(extensionList, function(extension) { _.each(extensionList, function(extension) {
extension.config = _.extend({}, extension.defaultConfig, extensionSettings[extension.extensionId]); extension.config = _.extend({}, extension.defaultConfig, extensionSettings[extension.extensionId]);
extension.config.enabled = !extension.optional || extension.config.enabled === undefined || extension.config.enabled === true; extension.config.enabled = !extension.optional || extension.config.enabled === undefined || extension.config.enabled === true;
}); });
// Load/Save extension config from/to settings // Load/Save extension config from/to settings
extensionManager["onLoadSettings"] = function() { extensionMgr["onLoadSettings"] = function() {
console.debug("onLoadSettings"); console.debug("onLoadSettings");
_.each(extensionList, function(extension) { _.each(extensionList, function(extension) {
utils.setInputChecked("#input-enable-extension-" + extension.extensionId, extension.config.enabled); utils.setInputChecked("#input-enable-extension-" + extension.extensionId, extension.config.enabled);
@ -85,7 +94,7 @@ define( [
onLoadSettingsCallback && onLoadSettingsCallback(); onLoadSettingsCallback && onLoadSettingsCallback();
}); });
}; };
extensionManager["onSaveSettings"] = function(newExtensionSettings, event) { extensionMgr["onSaveSettings"] = function(newExtensionSettings, event) {
console.debug("onSaveSettings"); console.debug("onSaveSettings");
_.each(extensionList, function(extension) { _.each(extensionList, function(extension) {
var newExtensionConfig = extension.defaultConfig || {}; var newExtensionConfig = extension.defaultConfig || {};
@ -96,25 +105,34 @@ define( [
}); });
}; };
addHook("onReady");
addHook("onMessage"); addHook("onMessage");
addHook("onError"); addHook("onError");
addHook("onOfflineChanged"); addHook("onOfflineChanged");
addHook("onAsyncRunning");
// To store reference to modules that are accessible from extensions // To store reference to modules that are accessible from extensions
addHook("onFileManagerCreated"); addHook("onFileMgrCreated");
addHook("onSynchronizerCreated"); addHook("onSynchronizerCreated");
addHook("onPublisherCreated"); addHook("onPublisherCreated");
// Operations on files // Operations on files
addHook("onFileSystemLoaded"); addHook("onFileSystemCreated");
addHook("onFileCreated"); addHook("onFileCreated");
addHook("onFileDeleted"); addHook("onFileDeleted");
addHook("onFileChanged"); addHook("onFileChanged");
addHook("onFileSelected"); addHook("onFileSelected");
addHook("onTitleChanged"); addHook("onTitleChanged");
// Sync events
addHook("onSyncRunning");
addHook("onSyncSuccess");
addHook("onSyncImportSuccess"); addHook("onSyncImportSuccess");
addHook("onSyncExportSuccess"); addHook("onSyncExportSuccess");
addHook("onSyncRemoved"); addHook("onSyncRemoved");
// Publish events
addHook("onPublishRunning");
addHook("onPublishSuccess"); addHook("onPublishSuccess");
addHook("onNewPublishSuccess"); addHook("onNewPublishSuccess");
addHook("onPublishRemoved"); addHook("onPublishRemoved");
@ -128,7 +146,7 @@ define( [
var onPreviewFinished = createHook("onPreviewFinished"); var onPreviewFinished = createHook("onPreviewFinished");
var onAsyncPreviewCallbackList = getExtensionCallbackList("onAsyncPreview"); var onAsyncPreviewCallbackList = getExtensionCallbackList("onAsyncPreview");
extensionManager["onAsyncPreview"] = function() { extensionMgr["onAsyncPreview"] = function() {
console.debug("onAsyncPreview"); console.debug("onAsyncPreview");
// Call onPreviewFinished callbacks when all async preview are finished // Call onPreviewFinished callbacks when all async preview are finished
var counter = 0; var counter = 0;
@ -146,16 +164,10 @@ define( [
tryFinished(); tryFinished();
}; };
// Call onReady callbacks $(function() {
var onReady = createHook("onReady");
extensionManager["onReady"] = function() {
// Create accordion in settings dialog // Create accordion in settings dialog
_.each(extensionList, createSettings); _.each(extensionList, createSettings);
});
onReady();
}; return extensionMgr;
};
return extensionManager;
}); });

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 = { var buttonShare = {
extensionId: "sharingButton", extensionId: "buttonShare",
extensionName: "Sharing button", extensionName: 'Button "Share"',
optional: true, optional: true,
settingsBloc: [ settingsBloc: '<p>Adds a "Share document" button in the navigation bar.</p>'
'<p>Adds a "Share document" button in the navigation bar.</p>'
].join("")
}; };
var fileDesc = undefined; var fileDesc = undefined;
@ -14,8 +15,7 @@ define( [ "jquery", "underscore" ], function($) {
'<div class="input-prepend">', '<div class="input-prepend">',
'<a href="<%= link %>" class="add-on" title="Sharing location"><i class="icon-link"></i></a>', '<a href="<%= link %>" class="add-on" title="Sharing location"><i class="icon-link"></i></a>',
'<input class="span2" type="text" value="<%= link %>" readonly />', '<input class="span2" type="text" value="<%= link %>" readonly />',
'</div>' '</div>'].join("");
].join("");
var refreshDocumentSharing = function(fileDescParameter) { var refreshDocumentSharing = function(fileDescParameter) {
if(fileDescParameter !== undefined && fileDescParameter !== fileDesc) { if(fileDescParameter !== undefined && fileDescParameter !== fileDesc) {
return; return;
@ -39,14 +39,14 @@ define( [ "jquery", "underscore" ], function($) {
}); });
}; };
sharingButton.onFileSelected = function(fileDescParameter) { buttonShare.onFileSelected = function(fileDescParameter) {
fileDesc = fileDescParameter; fileDesc = fileDescParameter;
refreshDocumentSharing(fileDescParameter); refreshDocumentSharing(fileDescParameter);
}; };
sharingButton.onNewPublishSuccess = refreshDocumentSharing; buttonShare.onNewPublishSuccess = refreshDocumentSharing;
sharingButton.onPublishRemoved = 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,23 +1,26 @@
define( [ "jquery", "underscore" ], function($) { define([
"jquery",
"underscore"
], function($, _) {
var documentSelector = { var documentSelector = {
extensionId: "documentSelector", extensionId: "documentSelector",
extensionName: "Document selector", extensionName: "Document selector",
settingsBloc: [ settingsBloc: '<p>Builds the "Open document" dropdown menu.</p>'
'<p>Builds the "Open document" dropdown menu.</p>'
].join("")
}; };
var fileSystemDescriptor = undefined; var fileSystem = undefined;
documentSelector.onFileSystemLoaded = function(fileSystemDescriptorParameter) { documentSelector.onFileSystemCreated = function(fileSystemParameter) {
fileSystemDescriptor = fileSystemDescriptorParameter; fileSystem = fileSystemParameter;
}; };
var fileDesc = undefined; var fileMgr = undefined;
var updateSelector = function() { documentSelector.onFileMgrCreated = function(fileMgrParameter) {
var sortedDescriptor = _.sortBy(fileSystemDescriptor, function(fileDesc) { fileMgr = fileMgrParameter;
return fileDesc.title.toLowerCase(); };
});
var liMap = undefined;
var buildSelector = function() {
function composeTitle(fileDesc) { function composeTitle(fileDesc) {
var result = []; var result = [];
@ -25,40 +28,48 @@ define( [ "jquery", "underscore" ], function($) {
var publishAttributesList = _.values(fileDesc.publishLocations); var publishAttributesList = _.values(fileDesc.publishLocations);
var attributesList = syncAttributesList.concat(publishAttributesList); var attributesList = syncAttributesList.concat(publishAttributesList);
_.chain(attributesList).sortBy(function(attributes) { _.chain(attributesList).sortBy(function(attributes) {
return attributes.provider; return attributes.provider.providerId;
}).each(function(attributes) { }).each(function(attributes) {
result.push('<i class="icon-' + attributes.provider + '"></i>'); result.push('<i class="icon-' + attributes.provider.providerId + '"></i>');
}); });
result.push(" "); result.push(" ");
result.push(fileDesc.title); result.push(fileDesc.title);
return result.join(""); return result.join("");
} }
liMap = {};
$("#file-selector li:not(.stick)").empty(); $("#file-selector li:not(.stick)").empty();
_.each(sortedDescriptor, function(fileDescToPrint) { _.chain(
var a = $("<a>").html(composeTitle(fileDescToPrint.fileIndex)); fileSystem
var li = $("<li>").append(a); ).sortBy(function(fileDesc) {
if (fileDescToPrint === fileDesc) { return fileDesc.title.toLowerCase();
li.addClass("disabled"); }).each(function(fileDesc) {
} else { var a = $('<a href="#">').html(composeTitle(fileDesc)).click(function() {
a.prop("href", "#").click(function() { if(liMap[fileDesc.fileIndex].is(".disabled")) {
fileManager.selectFile(fileDescToPrint); fileMgr.selectFile(fileDesc);
});
} }
});
var li = $("<li>").append(a);
liMap[fileDesc.fileIndex] = li;
$("#file-selector").append(li); $("#file-selector").append(li);
}); });
}; };
documentSelector.onFileSelected = function(fileDescParameter) { documentSelector.onFileSelected = function(fileDesc) {
fileDesc = fileDescParameter; if(liMap === undefined) {
updateSelector(); buildSelector();
}
$("#file-selector li:not(.stick)").removeClass("disabled");
liMap[fileDesc.fileIndex].addClass("disabled");
}; };
documentSelector.onTitleChanged = updateSelector; documentSelector.onFileCreated = buildSelector;
documentSelector.onSyncExportSuccess = updateSelector; documentSelector.onFileDeleted = buildSelector;
documentSelector.onSyncRemoved = updateSelector; documentSelector.onTitleChanged = buildSelector;
documentSelector.onNewPublishSuccess = updateSelector; documentSelector.onSyncExportSuccess = buildSelector;
documentSelector.onPublishRemoved = updateSelector; documentSelector.onSyncRemoved = buildSelector;
documentSelector.onNewPublishSuccess = buildSelector;
documentSelector.onPublishRemoved = buildSelector;
return documentSelector; return documentSelector;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,8 @@
define( [ "jquery", "underscore" ], function($) { define([
"jquery",
"underscore",
"lib/css_browser_selector"
], function($, _) {
var scrollLink = { var scrollLink = {
extensionId: "scrollLink", extensionId: "scrollLink",

View File

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

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"; var PROVIDER_GDRIVE = "gdrive";
@ -39,11 +46,11 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes); localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
var syncLocations = {}; var syncLocations = {};
syncLocations[syncAttributes.syncIndex] = syncAttributes; syncLocations[syncAttributes.syncIndex] = syncAttributes;
var fileDesc = core.fileManager.createFile(file.title, file.content, syncLocations); var fileDesc = fileMgr.createFile(file.title, file.content, syncLocations);
core.fileManager.selectFile(fileDesc); fileMgr.selectFile(fileDesc);
fileDescList.push(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 = []; var importIds = [];
_.each(ids, function(id) { _.each(ids, function(id) {
var syncIndex = createSyncIndex(id); var syncIndex = createSyncIndex(id);
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex); var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
if(fileDesc !== undefined) { if(fileDesc !== undefined) {
core.showError('"' + fileDesc.title + '" was already imported'); extensionMgr.onError('"' + fileDesc.title + '" was already imported');
return; return;
} }
importIds.push(id); 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 // Check that file is not synchronized with an other one
var syncIndex = createSyncIndex(id); var syncIndex = createSyncIndex(id);
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex); var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
if(fileDesc !== undefined) { 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); callback(true);
return; return;
} }
@ -134,7 +141,7 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
var interestingChanges = []; var interestingChanges = [];
_.each(changes, function(change) { _.each(changes, function(change) {
var syncIndex = createSyncIndex(change.fileId); var syncIndex = createSyncIndex(change.fileId);
var syncAttributes = core.fileManager.getSyncAttributes(syncIndex); var syncAttributes = fileMgr.getSyncAttributes(syncIndex);
if(syncAttributes === undefined) { if(syncAttributes === undefined) {
return; return;
} }
@ -155,11 +162,10 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
callback(error); callback(error);
return; return;
} }
var updateFileTitles = false;
_.each(changes, function(change) { _.each(changes, function(change) {
var syncAttributes = change.syncAttributes; var syncAttributes = change.syncAttributes;
var syncIndex = syncAttributes.syncIndex; var syncIndex = syncAttributes.syncIndex;
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex); var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
// No file corresponding (file may have been deleted locally) // No file corresponding (file may have been deleted locally)
if(fileDesc === undefined) { if(fileDesc === undefined) {
return; return;
@ -167,8 +173,8 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
var localTitle = fileDesc.title; var localTitle = fileDesc.title;
// File deleted // File deleted
if (change.deleted === true) { if (change.deleted === true) {
core.showError('"' + localTitle + '" has been removed from Google Drive.'); extensionMgr.onError('"' + localTitle + '" has been removed from Google Drive.');
core.fileManager.removeSync(syncAttributes); fileMgr.removeSync(syncAttributes);
return; return;
} }
var localTitleChanged = syncAttributes.titleCRC != utils.crc32(localTitle); var localTitleChanged = syncAttributes.titleCRC != utils.crc32(localTitle);
@ -184,24 +190,23 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
// Conflict detection // Conflict detection
if ((fileTitleChanged === true && localTitleChanged === true && remoteTitleChanged === true) if ((fileTitleChanged === true && localTitleChanged === true && remoteTitleChanged === true)
|| (fileContentChanged === true && localContentChanged === true && remoteContentChanged === true)) { || (fileContentChanged === true && localContentChanged === true && remoteContentChanged === true)) {
core.fileManager.createFile(localTitle + " (backup)", localContent); var backupFileDesc = fileMgr.createFile(localTitle + " (backup)", localContent);
updateFileTitles = true; extensionMgr.onTitleChanged(backupFileDesc);
core.showMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.'); extensionMgr.onMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.');
} }
// If file title changed // If file title changed
if(fileTitleChanged && remoteTitleChanged === true) { if(fileTitleChanged && remoteTitleChanged === true) {
localStorage[fileDesc.fileIndex + ".title"] = file.title; localStorage[fileDesc.fileIndex + ".title"] = file.title;
fileDesc.title = file.title; fileDesc.title = file.title;
updateFileTitles = true; extensionMgr.onTitleChanged(fileDesc);
core.showMessage('"' + localTitle + '" has been renamed to "' + file.title + '" on Google Drive.'); extensionMgr.onMessage('"' + localTitle + '" has been renamed to "' + file.title + '" on Google Drive.');
} }
// If file content changed // If file content changed
if(fileContentChanged && remoteContentChanged === true) { if(fileContentChanged && remoteContentChanged === true) {
localStorage[fileDesc.fileIndex + ".content"] = file.content; localStorage[fileDesc.fileIndex + ".content"] = file.content;
core.showMessage('"' + file.title + '" has been updated from Google Drive.'); extensionMgr.onMessage('"' + file.title + '" has been updated from Google Drive.');
if(core.fileManager.isCurrentFile(fileDesc)) { if(fileMgr.isCurrentFile(fileDesc)) {
updateFileTitles = false; // Done by next function fileMgr.selectFile(); // Refresh editor
core.fileManager.selectFile(); // Refresh editor
} }
} }
// Update syncAttributes // Update syncAttributes
@ -210,9 +215,6 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
syncAttributes.titleCRC = remoteTitleCRC; syncAttributes.titleCRC = remoteTitleCRC;
localStorage[syncIndex] = utils.serializeAttributes(syncAttributes); localStorage[syncIndex] = utils.serializeAttributes(syncAttributes);
}); });
if(updateFileTitles) {
extensionManager.onTitleChanged();
}
localStorage[PROVIDER_GDRIVE + ".lastChangeId"] = newChangeId; localStorage[PROVIDER_GDRIVE + ".lastChangeId"] = newChangeId;
callback(); callback();
}); });
@ -264,18 +266,18 @@ define(["core", "utils", "extension-manager", "google-helper", "underscore"], fu
localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes); localStorage[syncAttributes.syncIndex] = utils.serializeAttributes(syncAttributes);
var syncLocations = {}; var syncLocations = {};
syncLocations[syncAttributes.syncIndex] = syncAttributes; syncLocations[syncAttributes.syncIndex] = syncAttributes;
var fileDesc = core.fileManager.createFile(file.title, file.content, syncAttributes); var fileDesc = fileMgr.createFile(file.title, file.content, syncAttributes);
core.fileManager.selectFile(fileDesc); fileMgr.selectFile(fileDesc);
core.showMessage('"' + file.title + '" created successfully on Google Drive.'); extensionMgr.onMessage('"' + file.title + '" created successfully on Google Drive.');
}); });
} }
else if (state.action == "open") { else if (state.action == "open") {
var importIds = []; var importIds = [];
_.each(state.ids, function(id) { _.each(state.ids, function(id) {
var syncIndex = createSyncIndex(id); var syncIndex = createSyncIndex(id);
var fileDesc = core.fileManager.getFileFromSyncIndex(syncIndex); var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex);
if(fileDesc !== undefined) { if(fileDesc !== undefined) {
core.fileManager.selectFile(fileDesc); fileMgr.selectFile(fileDesc);
} }
else { else {
importIds.push(id); 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"; 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 connected = undefined;
var github = undefined; var github = undefined;
@ -51,14 +57,14 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
task.chain(); task.chain();
return; 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."; var errorMsg = "Failed to retrieve a token from GitHub.";
// We add time for user to enter his credentials // We add time for user to enter his credentials
task.timeout = ASYNC_TASK_LONG_TIMEOUT; task.timeout = ASYNC_TASK_LONG_TIMEOUT;
var code = undefined; var code = undefined;
function getCode() { function getCode() {
localStorage.removeItem("githubCode"); localStorage.removeItem("githubCode");
authWindow = core.popupWindow( authWindow = utils.popupWindow(
'github-oauth-client.html?client_id=' + GITHUB_CLIENT_ID, 'github-oauth-client.html?client_id=' + GITHUB_CLIENT_ID,
'stackedit-github-oauth', 960, 600); 'stackedit-github-oauth', 960, 600);
authWindow.focus(); authWindow.focus();
@ -106,7 +112,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
} }
githubHelper.upload = function(reponame, branch, path, content, commitMsg, callback) { githubHelper.upload = function(reponame, branch, path, content, commitMsg, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
connect(task); connect(task);
authenticate(task); authenticate(task);
@ -145,7 +150,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}; };
githubHelper.uploadGist = function(gistId, filename, isPublic, title, content, callback) { githubHelper.uploadGist = function(gistId, filename, isPublic, title, content, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
connect(task); connect(task);
authenticate(task); authenticate(task);
@ -184,7 +188,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
}; };
githubHelper.downloadGist = function(gistId, filename, callback) { githubHelper.downloadGist = function(gistId, filename, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
connect(task); connect(task);
// No need for authentication // 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"; var PROVIDER_GITHUB = "github";
@ -9,7 +13,7 @@ define(["core", "utils", "github-helper"], function(core, utils, githubHelper) {
}; };
githubProvider.publish = function(publishAttributes, title, content, callback) { githubProvider.publish = function(publishAttributes, title, content, callback) {
var commitMsg = core.settings.commitMsg; var commitMsg = settings.commitMsg;
githubHelper.upload(publishAttributes.repository, publishAttributes.branch, githubHelper.upload(publishAttributes.repository, publishAttributes.branch,
publishAttributes.path, content, commitMsg, callback); 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 connected = false;
var authenticated = false; var authenticated = false;
@ -44,7 +50,7 @@ define(["jquery", "core", "utils", "async-runner"], function($, core, utils, asy
var immediate = true; var immediate = true;
function localAuthenticate() { function localAuthenticate() {
if (immediate === false) { 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 // If not immediate we add time for user to enter his credentials
task.timeout = ASYNC_TASK_LONG_TIMEOUT; 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) { googleHelper.upload = function(fileId, parentId, title, content, etag, callback) {
callback = callback || core.doNothing;
var result = undefined; var result = undefined;
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
connect(task); connect(task);
@ -151,7 +156,6 @@ define(["jquery", "core", "utils", "async-runner"], function($, core, utils, asy
}; };
googleHelper.checkChanges = function(lastChangeId, callback) { googleHelper.checkChanges = function(lastChangeId, callback) {
callback = callback || core.doNothing;
var changes = []; var changes = [];
var newChangeId = lastChangeId || 0; var newChangeId = lastChangeId || 0;
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
@ -202,7 +206,6 @@ define(["jquery", "core", "utils", "async-runner"], function($, core, utils, asy
}; };
googleHelper.downloadMetadata = function(ids, callback, skipAuth) { googleHelper.downloadMetadata = function(ids, callback, skipAuth) {
callback = callback || core.doNothing;
var result = []; var result = [];
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
connect(task); connect(task);
@ -255,7 +258,6 @@ define(["jquery", "core", "utils", "async-runner"], function($, core, utils, asy
}; };
googleHelper.downloadContent = function(objects, callback, skipAuth) { googleHelper.downloadContent = function(objects, callback, skipAuth) {
callback = callback || core.doNothing;
var result = []; var result = [];
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
// Add some time for user to choose his files // 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) { googleHelper.picker = function(callback) {
callback = callback || core.doNothing;
var ids = []; var ids = [];
var picker = undefined; var picker = undefined;
function hidePicker() { function hidePicker() {

View File

View File

@ -1,5 +1,5 @@
/** vim: et:ts=4:sw=4:sts=4 /** 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. * Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details * see: http://github.com/jrburke/requirejs for details
*/ */
@ -12,7 +12,7 @@ var requirejs, require, define;
(function (global) { (function (global) {
var req, s, head, baseElement, dataMain, src, var req, s, head, baseElement, dataMain, src,
interactiveScript, currentlyAddingScript, mainScript, subPath, interactiveScript, currentlyAddingScript, mainScript, subPath,
version = '2.1.5', version = '2.1.6',
commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
jsSuffixRegExp = /\.js$/, jsSuffixRegExp = /\.js$/,
@ -22,7 +22,7 @@ var requirejs, require, define;
hasOwn = op.hasOwnProperty, hasOwn = op.hasOwnProperty,
ap = Array.prototype, ap = Array.prototype,
apsp = ap.splice, apsp = ap.splice,
isBrowser = !!(typeof window !== 'undefined' && navigator && document), isBrowser = !!(typeof window !== 'undefined' && navigator && window.document),
isWebWorker = !isBrowser && typeof importScripts !== 'undefined', isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
//PS3 indicates loaded and complete, but need to wait for complete //PS3 indicates loaded and complete, but need to wait for complete
//specifically. Sequence is 'loading', 'loaded', execution, //specifically. Sequence is 'loading', 'loaded', execution,
@ -134,6 +134,10 @@ var requirejs, require, define;
return document.getElementsByTagName('script'); return document.getElementsByTagName('script');
} }
function defaultOnError(err) {
throw err;
}
//Allow getting a global that expressed in //Allow getting a global that expressed in
//dot notation, like 'a.b.c'. //dot notation, like 'a.b.c'.
function getGlobal(value) { function getGlobal(value) {
@ -500,7 +504,12 @@ var requirejs, require, define;
fn(defined[id]); fn(defined[id]);
} }
} else { } 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, id: mod.map.id,
uri: mod.map.url, uri: mod.map.url,
config: function () { 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] exports: defined[mod.map.id]
}); });
@ -840,8 +855,13 @@ var requirejs, require, define;
if (this.depCount < 1 && !this.defined) { if (this.depCount < 1 && !this.defined) {
if (isFunction(factory)) { if (isFunction(factory)) {
//If there is an error listener, favor passing //If there is an error listener, favor passing
//to that instead of throwing an error. //to that instead of throwing an error. However,
if (this.events.error) { //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 { try {
exports = context.execCb(id, factory, depExports, exports); exports = context.execCb(id, factory, depExports, exports);
} catch (e) { } catch (e) {
@ -869,8 +889,8 @@ var requirejs, require, define;
if (err) { if (err) {
err.requireMap = this.map; err.requireMap = this.map;
err.requireModules = [this.map.id]; err.requireModules = this.map.isDefine ? [this.map.id] : null;
err.requireType = 'define'; err.requireType = this.map.isDefine ? 'define' : 'require';
return onError((this.error = err)); return onError((this.error = err));
} }
@ -1093,7 +1113,7 @@ var requirejs, require, define;
})); }));
if (this.errback) { 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 * solely to allow the build system to sequence the files in the built
* layer in the right sequence. * layer in the right sequence.
* *
@ -1643,7 +1663,7 @@ var requirejs, require, define;
onScriptError: function (evt) { onScriptError: function (evt) {
var data = getScriptData(evt); var data = getScriptData(evt);
if (!hasPathFallback(data.id)) { 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. * function. Intercept/override it if you want custom error handling.
* @param {Error} err the error object. * @param {Error} err the error object.
*/ */
req.onError = function (err) { req.onError = defaultOnError;
throw err;
};
/** /**
* Does the request to load a module for the browser case. * 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. //baseUrl, if it is not already set.
dataMain = script.getAttribute('data-main'); dataMain = script.getAttribute('data-main');
if (dataMain) { 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. //Set final baseUrl if there is not already an explicit one.
if (!cfg.baseUrl) { if (!cfg.baseUrl) {
//Pull off the directory of data-main for use as the //Pull off the directory of data-main for use as the
//baseUrl. //baseUrl.
src = dataMain.split('/'); src = mainScript.split('/');
mainScript = src.pop(); mainScript = src.pop();
subPath = src.length ? src.join('/') + '/' : './'; subPath = src.length ? src.join('/') + '/' : './';
cfg.baseUrl = subPath; 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. //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. //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; return true;
} }
@ -1951,12 +1976,13 @@ var requirejs, require, define;
//This module may not have dependencies //This module may not have dependencies
if (!isArray(deps)) { if (!isArray(deps)) {
callback = deps; callback = deps;
deps = []; deps = null;
} }
//If no name, and callback is a function, then figure out if it a //If no name, and callback is a function, then figure out if it a
//CommonJS thing with dependencies. //CommonJS thing with dependencies.
if (!deps.length && isFunction(callback)) { if (!deps && isFunction(callback)) {
deps = [];
//Remove comments from the callback string, //Remove comments from the callback string,
//look for require calls, and pull them into the dependencies, //look for require calls, and pull them into the dependencies,
//but only if there are function args. //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({ requirejs.config({
waitSeconds: 0, waitSeconds: 0,
paths: { 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: { shim: {
'jquery-ui': ['jquery'], 'lib/underscore': {
'bootstrap': ['jquery'], exports: '_'
'jgrowl': ['jquery'], },
'layout': ['jquery-ui'], 'lib/jgrowl': {
'Markdown.Extra': ['Markdown.Converter', 'prettify'], deps: ['lib/jquery'],
'Markdown.Editor': ['Markdown.Converter'] 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() { $(function() {
// If browser has detected a new application cache. // If browser has detected a new application cache.
if (window.applicationCache) { if (window.applicationCache) {
@ -25,5 +40,8 @@ require(["jquery", "file-manager", "synchronizer", "publisher"], function($) {
} }
}, false); }, false);
} }
core.setReady();
}); });
}); });

View File

@ -1,8 +1,12 @@
define([ define([
"jquery", "jquery",
"underscore",
"core", "core",
"utils", "utils",
"settings",
"extension-manager", "extension-manager",
"file-system",
"file-manager",
"sharing", "sharing",
"blogger-provider", "blogger-provider",
"dropbox-provider", "dropbox-provider",
@ -11,59 +15,44 @@ define([
"gdrive-provider", "gdrive-provider",
"ssh-provider", "ssh-provider",
"tumblr-provider", "tumblr-provider",
"wordpress-provider", "wordpress-provider"
"underscore" ], function($, _, core, utils, settings, extensionMgr, fileSystem, fileMgr, sharing) {
], function($, core, utils, extensionManager, sharing) {
var publisher = {}; var publisher = {};
// Create a map with providerId: providerObject // Create a map with providerId: providerModule
var providerMap = _.chain(arguments) var providerMap = _.chain(
.map(function(argument) { arguments
).map(function(argument) {
return argument && argument.providerId && [argument.providerId, argument]; return argument && argument.providerId && [argument.providerId, argument];
}).compact().object().value(); }).compact().object().value();
// Used to know if the current file has publications // Retrieve publish locations from localStorage
var hasPublications = false; _.each(fileSystem, function(fileDesc) {
_.chain(
// Allows external modules to update hasPublications flag localStorage[fileDesc.fileIndex + ".publish"].split(";")
publisher.notifyPublish = function() { ).compact().each(function(publishIndex) {
var fileDesc = core.fileManager.getCurrentFile(); var publishAttributes = JSON.parse(localStorage[publishIndex]);
// Store publishIndex
// Check that file has publications publishAttributes.publishIndex = publishIndex;
if(_.size(fileDesc.publishLocations) === 0) { // Replace provider ID by provider module in attributes
hasPublications = false; publishAttributes.provider = providerMap[publishAttributes.provider];
} fileDesc.publishLocations[publishIndex] = publishAttributes;
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);
// Apply template to the current document // Apply template to the current document
publisher.applyTemplate = function(publishAttributes) { publisher.applyTemplate = function(publishAttributes) {
var fileDesc = core.fileManager.getCurrentFile(); var fileDesc = fileMgr.getCurrentFile();
try { try {
return _.template(core.settings.template, { return _.template(settings.template, {
documentTitle: fileDesc.title, documentTitle: fileDesc.title,
documentMarkdown: $("#wmd-input").val(), documentMarkdown: $("#wmd-input").val(),
documentHTML: $("#wmd-preview").html(), documentHTML: $("#wmd-preview").html(),
publishAttributes: publishAttributes publishAttributes: publishAttributes
}); });
} catch(e) { } catch(e) {
core.showError(e); extensionMgr.onError(e);
throw e; throw e;
} }
}; };
@ -105,7 +94,7 @@ define([
if(error !== undefined) { if(error !== undefined) {
var errorMsg = error.toString(); var errorMsg = error.toString();
if(errorMsg.indexOf("|removePublish") !== -1) { if(errorMsg.indexOf("|removePublish") !== -1) {
core.fileManager.removePublish(publishAttributes); fileMgr.removePublish(publishAttributes);
} }
if(errorMsg.indexOf("|stopPublish") !== -1) { if(errorMsg.indexOf("|stopPublish") !== -1) {
callback(error); callback(error);
@ -124,15 +113,15 @@ define([
} }
publishRunning = true; publishRunning = true;
publisher.updatePublishButton(); extensionMgr.onPublishRunning(true);
var fileDesc = fileManager.getCurrentFile(); var fileDesc = fileMgr.getCurrentFile();
publishTitle = fileDesc.title; publishTitle = fileDesc.title;
publishAttributesList = _.values(fileDesc.publishLocations); publishAttributesList = _.values(fileDesc.publishLocations);
publishLocation(function(errorFlag) { publishLocation(function(errorFlag) {
publishRunning = false; publishRunning = false;
publisher.updatePublishButton(); extensionMgr.onPublishRunning(false);
if(errorFlag === undefined) { if(errorFlag === undefined) {
extensionManager.onPublishSuccess(fileDesc); extensionMgr.onPublishSuccess(fileDesc);
} }
}); });
}; };
@ -144,8 +133,8 @@ define([
publishIndex = "publish." + utils.randomString(); publishIndex = "publish." + utils.randomString();
} while(_.has(localStorage, publishIndex)); } while(_.has(localStorage, publishIndex));
publishAttributes.publishIndex = publishIndex; publishAttributes.publishIndex = publishIndex;
localStorage[publishIndex] = JSON.stringify(publishAttributes); localStorage[publishIndex] = utils.serializeAttributes(publishAttributes);
core.fileManager.addPublish(fileDesc, publishAttributes); fileMgr.addPublish(fileDesc, publishAttributes);
} }
// Initialize the "New publication" dialog // Initialize the "New publication" dialog
@ -185,7 +174,7 @@ define([
} }
// Perform provider's publishing // Perform provider's publishing
var fileDesc = core.fileManager.getCurrentFile(); var fileDesc = fileMgr.getCurrentFile();
var title = fileDesc.title; var title = fileDesc.title;
var content = getPublishContent(publishAttributes); var content = getPublishContent(publishAttributes);
provider.publish(publishAttributes, title, content, function(error) { provider.publish(publishAttributes, title, content, function(error) {
@ -193,8 +182,6 @@ define([
publishAttributes.provider = provider.providerId; publishAttributes.provider = provider.providerId;
sharing.createLink(publishAttributes, function() { sharing.createLink(publishAttributes, function() {
createPublishIndex(fileDesc, publishAttributes); createPublishIndex(fileDesc, publishAttributes);
publisher.notifyPublish();
core.fileManager.updateFileTitles();
}); });
} }
}); });
@ -210,9 +197,9 @@ define([
// Retrieve file's publish locations from localStorage // Retrieve file's publish locations from localStorage
publisher.populatePublishLocations = function(fileDesc) { publisher.populatePublishLocations = function(fileDesc) {
_.chain(localStorage[fileDesc.fileIndex + ".publish"].split(";")) _.chain(
.compact() localStorage[fileDesc.fileIndex + ".publish"].split(";")
.each(function(publishIndex) { ).compact().each(function(publishIndex) {
var publishAttributes = JSON.parse(localStorage[publishIndex]); var publishAttributes = JSON.parse(localStorage[publishIndex]);
// Store publishIndex // Store publishIndex
publishAttributes.publishIndex = publishIndex; publishAttributes.publishIndex = publishIndex;
@ -249,8 +236,25 @@ define([
publisher.publish(); 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; 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,9 +1,22 @@
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 = {}; var sharing = {};
// Create a map with providerId: providerObject // Create a map with providerId: providerModule
var providerMap = _.chain(arguments) var providerMap = _.chain(
.map(function(argument) { arguments
).map(function(argument) {
return argument && argument.providerId && [argument.providerId, argument]; return argument && argument.providerId && [argument.providerId, argument];
}).compact().object().value(); }).compact().object().value();
@ -52,11 +65,12 @@ define(["jquery", "core", "utils", "async-runner", "download-provider", "gist-pr
url.push('='); url.push('=');
url.push(encodeURIComponent(attributes[attributeName])); url.push(encodeURIComponent(attributes[attributeName]));
}); });
url = url.join("");
$.getJSON( $.getJSON(
"https://api-ssl.bitly.com/v3/shorten", "https://api-ssl.bitly.com/v3/shorten",
{ {
"access_token": BITLY_ACCESS_TOKEN, "access_token": BITLY_ACCESS_TOKEN,
"longUrl": url.join("") "longUrl": url
}, },
function(response) function(response)
{ {
@ -64,46 +78,22 @@ define(["jquery", "core", "utils", "async-runner", "download-provider", "gist-pr
shortUrl = response.data.url; shortUrl = response.data.url;
attributes.sharingLink = shortUrl; attributes.sharingLink = shortUrl;
} }
else {
extensionMgr.onError("An error occured while creating sharing link.");
attributes.sharingLink = url;
}
task.chain(); task.chain();
} }
); );
}); });
function onFinish() { function onFinish() {
if(shortUrl === undefined) { callback();
localStorage["missingSharingLink"] = true;
}
callback(shortUrl);
} }
task.onSuccess(onFinish); task.onSuccess(onFinish);
task.onError(onFinish); task.onError(onFinish);
asyncRunner.addTask(task); 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() { core.onReady(function() {
if(viewerMode === false) { if(viewerMode === false) {
return; return;
@ -135,8 +125,8 @@ define(["jquery", "core", "utils", "async-runner", "download-provider", "gist-pr
if(error) { if(error) {
return; return;
} }
var fileDesc = core.fileManager.createFile(title, content, undefined, true); var fileDesc = fileMgr.createFile(title, content, undefined, true);
core.fileManager.selectFile(fileDesc); 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 = {}; 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) { sshHelper.upload = function(host, port, username, password, path, title, content, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
connect(task); connect(task);
task.onRun(function() { 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"; var PROVIDER_SSH = "ssh";

View File

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

View File

@ -1,44 +1,37 @@
define([ define([
"jquery", "jquery",
"underscore",
"core", "core",
"utils", "utils",
"extension-manager", "extension-manager",
"file-system",
"file-manager",
"dropbox-provider", "dropbox-provider",
"gdrive-provider", "gdrive-provider"
"underscore" ], function($, _, core, utils, extensionMgr, fileSystem, fileMgr) {
], function($, core, utils, extensionManager) {
var synchronizer = {}; var synchronizer = {};
// Create a map with providerId: providerObject // Create a map with providerId: providerModule
var providerMap = _.chain(arguments) var providerMap = _.chain(
.map(function(argument) { arguments
).map(function(argument) {
return argument && argument.providerId && [argument.providerId, argument]; return argument && argument.providerId && [argument.providerId, argument];
}).compact().object().value(); }).compact().object().value();
// Used to know if user can force synchronization // Retrieve sync locations from localStorage
var uploadPending = false; _.each(fileSystem, function(fileDesc) {
_.chain(
// Allows external modules to update uploadPending flag localStorage[fileDesc.fileIndex + ".sync"].split(";")
synchronizer.notifyChange = function(fileDesc) { ).compact().each(function(syncIndex) {
// Check that file has synchronized locations var syncAttributes = JSON.parse(localStorage[syncIndex]);
if(_.size(fileDesc.syncLocations) !== 0) { // Store syncIndex
uploadPending = true; syncAttributes.syncIndex = syncIndex;
synchronizer.updateSyncButton(); // Replace provider ID by provider module in attributes
} syncAttributes.provider = providerMap[syncAttributes.provider];
}; fileDesc.syncLocations[syncIndex] = syncAttributes;
});
// 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);
// Force the synchronization // Force the synchronization
synchronizer.forceSync = function() { synchronizer.forceSync = function() {
@ -73,8 +66,6 @@ define([
if(uploadFlag === true) { if(uploadFlag === true) {
// If uploadFlag is true, request another upload cycle // If uploadFlag is true, request another upload cycle
uploadCycle = true; uploadCycle = true;
// When page is refreshed, this flag is false but should be true here
uploadPending = true;
} }
if(error) { if(error) {
callback(error); callback(error);
@ -121,7 +112,7 @@ define([
if(uploadCycle === true) { if(uploadCycle === true) {
// New upload cycle // New upload cycle
uploadCycle = false; uploadCycle = false;
uploadFileList = core.fileManager.getFileList(); uploadFileList = fileMgr.getFileList();
fileUp(callback); fileUp(callback);
} }
else { else {
@ -139,7 +130,7 @@ define([
var provider = providerList.pop(); var provider = providerList.pop();
// Check that provider has files to sync // Check that provider has files to sync
if(!core.fileManager.hasSync(provider)) { if(!fileMgr.hasSync(provider)) {
providerDown(callback); providerDown(callback);
return; return;
} }
@ -165,18 +156,18 @@ define([
var lastSync = 0; var lastSync = 0;
synchronizer.sync = function() { synchronizer.sync = function() {
// If sync is already running or timeout is not reached or offline // 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; return;
} }
syncRunning = true; syncRunning = true;
extensionMgr.onSyncRunning(true);
uploadCycle = true; uploadCycle = true;
lastSync = core.currentTime; lastSync = utils.currentTime;
synchronizer.updateSyncButton();
function isError(error) { function isError(error) {
if(error !== undefined) { if(error !== undefined) {
syncRunning = false; syncRunning = false;
synchronizer.updateSyncButton(); extensionMgr.onSyncRunning(false);
return true; return true;
} }
return false; return false;
@ -191,7 +182,8 @@ define([
return; return;
} }
syncRunning = false; syncRunning = false;
uploadPending = false; extensionMgr.onSyncRunning(false);
extensionMgr.onSyncSuccess();
}); });
}); });
}; };
@ -200,20 +192,6 @@ define([
core.addPeriodicCallback(synchronizer.sync); 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 // Initialize the export dialog
function initExportDialog(provider) { function initExportDialog(provider) {
@ -247,14 +225,14 @@ define([
$(".action-sync-export-" + provider.providerId).click(function(event) { $(".action-sync-export-" + provider.providerId).click(function(event) {
// Perform the provider's export // Perform the provider's export
var fileDesc = core.fileManager.getCurrentFile(); var fileDesc = fileMgr.getCurrentFile();
var title = fileDesc.title; var title = fileDesc.title;
var content = localStorage[fileDesc.fileIndex + ".content"]; var content = localStorage[fileDesc.fileIndex + ".content"];
provider.exportFile(event, title, content, function(error, syncAttributes) { provider.exportFile(event, title, content, function(error, syncAttributes) {
if(error) { if(error) {
return; return;
} }
core.fileManager.addSync(fileDesc, syncAttributes); fileMgr.addSync(fileDesc, syncAttributes);
}); });
// Store input values as preferences for next time we open the export dialog // Store input values as preferences for next time we open the export dialog
@ -266,19 +244,18 @@ define([
}); });
// Provider's manual export button // Provider's manual export button
$(".action-sync-manual-" + provider.providerId).click(function(event) { $(".action-sync-manual-" + provider.providerId).click(function(event) {
var fileDesc = core.fileManager.getCurrentFile(); var fileDesc = fileMgr.getCurrentFile();
var title = fileDesc.title; var title = fileDesc.title;
var content = localStorage[fileDesc.fileIndex + ".content"]; var content = localStorage[fileDesc.fileIndex + ".content"];
provider.exportManual(event, title, content, function(error, syncAttributes) { provider.exportManual(event, title, content, function(error, syncAttributes) {
if(error) { if(error) {
return; return;
} }
core.fileManager.addSync(fileDesc, syncAttributes); fileMgr.addSync(fileDesc, syncAttributes);
}); });
}); });
}); });
synchronizer.updateSyncButton();
$(".action-force-sync").click(function() { $(".action-force-sync").click(function() {
if(!$(this).hasClass("disabled")) { if(!$(this).hasClass("disabled")) {
synchronizer.forceSync(); synchronizer.forceSync();
@ -286,6 +263,6 @@ define([
}); });
}); });
extensionManager.onSynchronizerCreated(synchronizer); extensionMgr.onSynchronizerCreated(synchronizer);
return 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; var oauthParams = undefined;
@ -30,7 +36,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
task.chain(); task.chain();
return; 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."; var errorMsg = "Failed to retrieve a token from Tumblr.";
// We add time for user to enter his credentials // We add time for user to enter his credentials
task.timeout = ASYNC_TASK_LONG_TIMEOUT; task.timeout = ASYNC_TASK_LONG_TIMEOUT;
@ -48,7 +54,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
} }
function getVerifier() { function getVerifier() {
localStorage.removeItem("tumblrVerifier"); localStorage.removeItem("tumblrVerifier");
authWindow = core.popupWindow( authWindow = utils.popupWindow(
'tumblr-oauth-client.html?oauth_token=' + oauth_object.oauth_token, 'tumblr-oauth-client.html?oauth_token=' + oauth_object.oauth_token,
'stackedit-tumblr-oauth', 800, 600); 'stackedit-tumblr-oauth', 800, 600);
authWindow.focus(); authWindow.focus();
@ -92,7 +98,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
} }
tumblrHelper.upload = function(blogHostname, postId, tags, format, title, content, callback) { tumblrHelper.upload = function(blogHostname, postId, tags, format, title, content, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
connect(task); connect(task);
authenticate(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"; var PROVIDER_TUMBLR = "tumblr";

View File

@ -1,4 +1,8 @@
define([ "jquery", "underscore" ], function($) { define([
"jquery",
"underscore",
"lib/FileSaver"
], function($, _) {
var utils = {}; var utils = {};
@ -107,6 +111,16 @@ define([ "jquery", "underscore" ], function($) {
return $.trim(str); 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 // Check an URL
utils.checkUrl = function(url, addSlash) { utils.checkUrl = function(url, addSlash) {
if(!url) { if(!url) {
@ -242,11 +256,48 @@ define([ "jquery", "underscore" ], function($) {
return crc.toString(16); 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 // Generates a random string
utils.randomString = function() { utils.randomString = function() {
return _.random(4294967296).toString(36); return _.random(4294967296).toString(36);
}; };
// Time shared by others modules
utils.updateCurrentTime = function() {
utils.currentTime = new Date().getTime();
};
utils.updateCurrentTime();
// Serialize sync/publish attributes // Serialize sync/publish attributes
utils.serializeAttributes = function(attributes) { utils.serializeAttributes = function(attributes) {
// Don't store sync/publish index // 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; var token = undefined;
@ -25,14 +31,14 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
task.chain(); task.chain();
return; 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."; var errorMsg = "Failed to retrieve a token from Wordpress.";
// We add time for user to enter his credentials // We add time for user to enter his credentials
task.timeout = ASYNC_TASK_LONG_TIMEOUT; task.timeout = ASYNC_TASK_LONG_TIMEOUT;
var code = undefined; var code = undefined;
function getCode() { function getCode() {
localStorage.removeItem("wordpressCode"); localStorage.removeItem("wordpressCode");
authWindow = core.popupWindow( authWindow = utils.popupWindow(
'wordpress-oauth-client.html?client_id=' + WORDPRESS_CLIENT_ID, 'wordpress-oauth-client.html?client_id=' + WORDPRESS_CLIENT_ID,
'stackedit-wordpress-oauth', 960, 600); 'stackedit-wordpress-oauth', 960, 600);
authWindow.focus(); authWindow.focus();
@ -76,7 +82,6 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
} }
wordpressHelper.upload = function(site, postId, tags, title, content, callback) { wordpressHelper.upload = function(site, postId, tags, title, content, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask(); var task = asyncRunner.createTask();
connect(task); connect(task);
authenticate(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"; var PROVIDER_WORDPRESS = "wordpress";

View File

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