Support for Dropbox publishing

This commit is contained in:
benweet 2013-04-16 16:02:24 +01:00
parent 7667b91873
commit 51ba5930af
8 changed files with 315 additions and 270 deletions

View File

@ -88,6 +88,8 @@
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#" class="action-publish-blogger"><i <li><a href="#" class="action-publish-blogger"><i
class="icon-blogger"></i> Blogger</a></li> class="icon-blogger"></i> Blogger</a></li>
<li><a href="#" class="action-publish-dropbox"><i
class="icon-dropbox"></i> Dropbox</a></li>
<li><a href="#" class="action-publish-github"><i <li><a href="#" class="action-publish-github"><i
class="icon-github"></i> GitHub</a></li> class="icon-github"></i> GitHub</a></li>
</ul></li> </ul></li>
@ -269,7 +271,7 @@
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" <button type="button" class="close" data-dismiss="modal"
aria-hidden="true">&times;</button> aria-hidden="true">&times;</button>
<h3 class="modal-publish-github">Publish on GitHub</h3> <h3>Publish on <span class="publish-provider-name"></span></h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="form-horizontal"> <div class="form-horizontal">
@ -311,6 +313,13 @@
placeholder="Post ID"> placeholder="Post ID">
</div> </div>
</div> </div>
<div class="control-group modal-publish-dropbox">
<label class="control-label" for="input-publish-dropbox-path">File path</label>
<div class="controls">
<input type="text" id="input-publish-dropbox-path"
placeholder="/path/to/My Document.html">
</div>
</div>
<div class="control-group"> <div class="control-group">
<div class="control-label">Format</div> <div class="control-label">Format</div>
<div class="controls"> <div class="controls">

View File

@ -106,10 +106,16 @@ define(["underscore"], function() {
asyncTaskRunner.runTask(); asyncTaskRunner.runTask();
}; };
// Change current task timeout
asyncTaskRunner.setCurrentTaskTimeout = function(timeout) {
if(currentTask !== undefined) {
currentTask.timeout = timeout;
}
};
asyncTaskRunner.init = function(coreModule) { asyncTaskRunner.init = function(coreModule) {
core = coreModule; core = coreModule;
}; };
return asyncTaskRunner; return asyncTaskRunner;
}); });

View File

@ -15,8 +15,9 @@ var USER_IDLE_THRESHOLD = 300000;
var SYNC_PROVIDER_GDRIVE = "sync.gdrive."; var SYNC_PROVIDER_GDRIVE = "sync.gdrive.";
var SYNC_PROVIDER_DROPBOX = "sync.dropbox."; var SYNC_PROVIDER_DROPBOX = "sync.dropbox.";
var PROVIDER_TYPE_PUBLISH_FLAG = 1; var PROVIDER_TYPE_PUBLISH_FLAG = 1;
var PROVIDER_GITHUB = "github";
var PROVIDER_BLOGGER = "blogger"; var PROVIDER_BLOGGER = "blogger";
var PROVIDER_DROPBOX = "dropbox";
var PROVIDER_GITHUB = "github";
// Use by Google's client.js // Use by Google's client.js
var delayedFunction = undefined; var delayedFunction = undefined;

View File

@ -12,28 +12,20 @@ define(["jquery", "async-runner"], function($, asyncTaskRunner) {
// Try to connect dropbox by downloading client.js // Try to connect dropbox by downloading client.js
function connect(callback) { function connect(callback) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
var asyncTask = {}; if(core.isOffline === true) {
asyncTask.run = function() { client = undefined;
if(core.isOffline === true) { core.showMessage("Operation not available in offline mode.");
client = undefined; callback(true);
core.showMessage("Operation not available in offline mode."); return;
asyncTask.error(); }
return; if (client !== undefined) {
} callback();
if (client !== undefined) { return;
asyncTask.success(); }
return; $.ajax({
} url : "lib/dropbox.min.js",
$.ajax({ dataType : "script", timeout : AJAX_TIMEOUT
url : "lib/dropbox.min.js", }).done(function() {
dataType : "script", timeout : AJAX_TIMEOUT
}).done(function() {
asyncTask.success();
}).fail(function() {
asyncTask.error();
});
};
asyncTask.onSuccess = function() {
client = new Dropbox.Client({ client = new Dropbox.Client({
key: DROPBOX_APP_KEY, key: DROPBOX_APP_KEY,
secret: DROPBOX_APP_SECRET secret: DROPBOX_APP_SECRET
@ -43,12 +35,10 @@ define(["jquery", "async-runner"], function($, asyncTaskRunner) {
rememberUser: true rememberUser: true
})); }));
callback(); callback();
}; }).fail(function() {
asyncTask.onError = function() {
core.setOffline(); core.setOffline();
callback(); callback(true);
}; });
asyncTaskRunner.addTask(asyncTask);
} }
// Try to authenticate with Oauth // Try to authenticate with Oauth
@ -57,61 +47,51 @@ define(["jquery", "async-runner"], function($, asyncTaskRunner) {
if (immediate === undefined) { if (immediate === undefined) {
immediate = true; immediate = true;
} }
connect(function() { connect(function(error) {
if (client === undefined) { if (error) {
callback(error);
return;
}
if (authenticated === true) {
callback(); callback();
return; return;
} }
if (immediate === false) {
var asyncTask = {}; core.showMessage("Please make sure the Dropbox authorization popup is not blocked by your browser.");
asyncTask.run = function() { asyncTaskRunner.setCurrentTaskTimeout(AUTH_POPUP_TIMEOUT);
if (authenticated === true) { }
asyncTask.success(); client.authenticate({interactive: !immediate}, function(error, client) {
if (client.authState === Dropbox.Client.DONE) {
callback();
return; return;
} }
if (immediate === false) {
core.showMessage("Please make sure the Dropbox authorization popup is not blocked by your browser.");
}
client.authenticate({interactive: !immediate}, function(error, client) {
if (client.authState !== Dropbox.Client.DONE) {
// Handle error
asyncTask.error();
return;
}
asyncTask.success();
});
};
asyncTask.onSuccess = function() {
callback();
};
asyncTask.onError = function() {
// If immediate did not work retry without immediate flag // If immediate did not work retry without immediate flag
if (client !== undefined && immediate === true) { if (client !== undefined && immediate === true) {
authenticate(callback, false); authenticate(callback, false);
return; return;
} }
callback(); // Notify error
}; callback(true);
asyncTaskRunner.addTask(asyncTask); });
}); });
} }
dropboxHelper.upload = function(path, content, callback) { dropboxHelper.upload = function(path, content, callback) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
authenticate(function() { var syncIndex = undefined;
if (client === undefined) { var asyncTask = {};
callback(); asyncTask.run = function() {
return; authenticate(function(error) {
} if (error) {
handleError(error, asyncTask, callback);
return;
}
var fileSyncIndex = undefined;
var asyncTask = {};
asyncTask.run = function() {
client.writeFile(path, content, function(error, stat) { client.writeFile(path, content, function(error, stat) {
if (!error) { if (!error) {
fileSyncIndex = SYNC_PROVIDER_DROPBOX + encodeURIComponent(stat.path.toLowerCase()); syncIndex = SYNC_PROVIDER_DROPBOX + encodeURIComponent(stat.path.toLowerCase());
localStorage[fileSyncIndex + ".version"] = stat.versionTag; localStorage[syncIndex + ".version"] = stat.versionTag;
asyncTask.success(); asyncTask.success();
return; return;
} }
@ -121,154 +101,168 @@ define(["jquery", "async-runner"], function($, asyncTaskRunner) {
} }
handleError(error, asyncTask, callback); handleError(error, asyncTask, callback);
}); });
}; });
asyncTask.onSuccess = function() { };
callback(fileSyncIndex); asyncTask.onSuccess = function() {
}; callback(undefined, syncIndex);
asyncTask.onError = function() { };
callback(); asyncTask.onError = function() {
}; callback(true);
asyncTaskRunner.addTask(asyncTask); };
}); asyncTaskRunner.addTask(asyncTask);
}; };
dropboxHelper.checkUpdates = function(lastChangeId, callback) { dropboxHelper.checkUpdates = function(lastChangeId, callback) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
authenticate(function() { var changes = [];
if (client === undefined) { var newChangeId = lastChangeId || 0;
callback(); var asyncTask = {};
return; asyncTask.run = function() {
}
var changes = [];
var newChangeId = lastChangeId || 0;
function retrievePageOfChanges(changeId) { function retrievePageOfChanges(changeId) {
var shouldPullAgain = false; if(asyncTask.finished === true) {
var asyncTask = {}; return;
asyncTask.run = function() { }
client.pullChanges(changeId, function(error, pullChanges) { authenticate(function(error) {
if (pullChanges && pullChanges.cursorTag) { if (error) {
// Retrieve success
newChangeId = pullChanges.cursor();
shouldPullAgain = pullChanges.shouldPullAgain;
if(pullChanges.changes !== undefined) {
for(var i=0; i<pullChanges.changes.length; i++) {
var item = pullChanges.changes[i];
var version = localStorage[SYNC_PROVIDER_DROPBOX
+ encodeURIComponent(item.path.toLowerCase()) + ".version"];
if(version && (item.wasRemoved || item.stat.versionTag != version)) {
changes.push(item);
}
}
}
asyncTask.success();
return;
}
// Handle error
handleError(error, asyncTask, callback); handleError(error, asyncTask, callback);
});
};
asyncTask.onSuccess = function() {
if (shouldPullAgain === true) {
retrievePageOfChanges(newChangeId);
} else {
callback(changes, newChangeId);
}
};
asyncTask.onError = function() {
callback();
};
asyncTaskRunner.addTask(asyncTask);
}
retrievePageOfChanges(newChangeId);
});
};
dropboxHelper.downloadMetadata = function(paths, callback, result) {
callback = callback || core.doNothing;
result = result || [];
if(paths.length === 0) {
callback(result);
return;
}
authenticate(function() {
if (client === undefined) {
callback();
return;
}
var path = paths.pop();
var asyncTask = {};
asyncTask.run = function() {
client.stat(path, function(error, stat) {
if(stat) {
result.push(stat);
asyncTask.success();
return; return;
} }
handleError(error, asyncTask, callback);
client.pullChanges(changeId, function(error, pullChanges) {
if (error) {
handleError(error, asyncTask, callback);
return;
}
// Retrieve success
newChangeId = pullChanges.cursor();
if(pullChanges.changes !== undefined) {
for(var i=0; i<pullChanges.changes.length; i++) {
var item = pullChanges.changes[i];
var version = localStorage[SYNC_PROVIDER_DROPBOX
+ encodeURIComponent(item.path.toLowerCase()) + ".version"];
if(version && (item.wasRemoved || item.stat.versionTag != version)) {
changes.push(item);
}
}
}
if (pullChanges.shouldPullAgain) {
retrievePageOfChanges(newChangeId);
} else {
asyncTask.success();
}
});
}); });
}; }
asyncTask.onSuccess = function() { retrievePageOfChanges(newChangeId);
dropboxHelper.downloadMetadata(paths, callback, result); };
}; asyncTask.onSuccess = function() {
asyncTask.onError = function() { callback(undefined, changes, newChangeId);
callback(); };
}; asyncTask.onError = function() {
asyncTaskRunner.addTask(asyncTask); callback(true);
}); };
asyncTaskRunner.addTask(asyncTask);
};
dropboxHelper.downloadMetadata = function(paths, callback) {
callback = callback || core.doNothing;
result = result || [];
var path = paths.pop();
var asyncTask = {};
asyncTask.run = function() {
function recursiveDownloadMetadata() {
if(asyncTask.finished === true) {
return;
}
if(paths.length === 0) {
asyncTask.success();
return;
}
authenticate(function(error) {
if (error) {
handleError(error, asyncTask, callback);
return;
}
client.stat(path, function(error, stat) {
if(stat) {
result.push(stat);
recursiveDownloadMetadata();
return;
}
handleError(error, asyncTask, callback);
});
});
}
recursiveDownloadMetadata();
};
asyncTask.onSuccess = function() {
callback(undefined, result);
};
asyncTask.onError = function() {
callback(true);
};
asyncTaskRunner.addTask(asyncTask);
}; };
dropboxHelper.downloadContent = function(objects, callback, result) { dropboxHelper.downloadContent = function(objects, callback, result) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
result = result || []; result = result || [];
if(objects.length === 0) {
callback(result);
return;
}
var object = objects.pop(); var asyncTask = {};
result.push(object); asyncTask.run = function() {
var file = undefined;
// object may be a file
if(object.isFile === true) {
file = object;
}
// object may be a change
else if(object.wasRemoved !== undefined) {
file = object.stat;
}
if(!file) {
this.downloadContent(objects, callback, result);
return;
}
authenticate(function() {
if (client === undefined) {
callback();
return;
}
var asyncTask = {}; function recursiveDownloadContent() {
asyncTask.run = function() { if(asyncTask.finished === true) {
client.readFile(file.path, function(error, data) { return;
if(data) { }
file.content = data; if(objects.length === 0) {
asyncTask.success(); asyncTask.success();
return;
}
var object = objects.pop();
result.push(object);
var file = undefined;
// object may be a file
if(object.isFile === true) {
file = object;
}
// object may be a change
else if(object.wasRemoved !== undefined) {
file = object.stat;
}
if(!file) {
recursiveDownloadContent();
return;
}
authenticate(function(error) {
if (error) {
handleError(error, asyncTask, callback);
return; return;
} }
handleError(error, asyncTask, callback);
client.readFile(file.path, function(error, data) {
if(data) {
file.content = data;
recursiveDownloadContent();
return;
}
handleError(error, asyncTask, callback);
});
}); });
}; }
asyncTask.onSuccess = function() { recursiveDownloadContent();
dropboxHelper.downloadContent(objects, callback, result); };
}; asyncTask.onSuccess = function() {
asyncTask.onError = function() { callback(undefined, result);
callback(); };
}; asyncTask.onError = function() {
asyncTaskRunner.addTask(asyncTask); callback(true);
}); };
asyncTaskRunner.addTask(asyncTask);
}; };
function handleError(error, asyncTask, callback) { function handleError(error, asyncTask, callback) {
@ -277,7 +271,7 @@ define(["jquery", "async-runner"], function($, asyncTaskRunner) {
if (errorMsg !== undefined) { if (errorMsg !== undefined) {
core.showError(errorMsg); core.showError(errorMsg);
} }
callback(); callback(errorMsg);
}; };
if (error) { if (error) {
console.error(error); console.error(error);
@ -302,83 +296,83 @@ define(["jquery", "async-runner"], function($, asyncTaskRunner) {
var pickerLoaded = false; var pickerLoaded = false;
function loadPicker(callback) { function loadPicker(callback) {
connect(function() { if (pickerLoaded === true) {
if (client === undefined) { callback();
return;
}
connect(function(error) {
if (error) {
pickerLoaded = false; pickerLoaded = false;
callback(); callback(error);
return; return;
} }
var asyncTask = {}; $.ajax({
asyncTask.run = function() { url : "https://www.dropbox.com/static/api/1/dropbox.js",
if (pickerLoaded === true) { dataType : "script", timeout : AJAX_TIMEOUT
asyncTask.success(); }).done(function() {
return;
}
$.ajax({
url : "https://www.dropbox.com/static/api/1/dropbox.js",
dataType : "script", timeout : AJAX_TIMEOUT
}).done(function() {
asyncTask.success();
}).fail(function() {
asyncTask.error();
});
};
asyncTask.onSuccess = function() {
pickerLoaded = true; pickerLoaded = true;
callback(); callback();
}; }).fail(function() {
asyncTask.onError = function() { callback(true);
core.setOffline(); });
callback();
};
asyncTaskRunner.addTask(asyncTask);
}); });
} }
dropboxHelper.picker = function(callback) { dropboxHelper.picker = function(callback) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
loadPicker(function() { var paths = [];
if (pickerLoaded === false) {
callback(); var asyncTask = {};
return; asyncTask.run = function() {
} loadPicker(function(error) {
var options = {}; if (error) {
options.multiselect = true; handleError(error, asyncTask, callback);
options.linkType = "direct"; return;
options.success = function(files) {
var paths = [];
for(var i=0; i<files.length; i++) {
var path = files[i].link;
path = path.replace(/.*\/view\/[^\/]*/, "");
paths.push(decodeURI(path));
} }
callback(paths); var options = {};
}; options.multiselect = true;
options.cancel = function() { options.linkType = "direct";
callback(); options.success = function(files) {
}; for(var i=0; i<files.length; i++) {
Dropbox.choose(options); var path = files[i].link;
core.showMessage("Please make sure the Dropbox chooser popup is not blocked by your browser."); path = path.replace(/.*\/view\/[^\/]*/, "");
}); paths.push(decodeURI(path));
}
asyncTask.success();
};
options.cancel = function() {
asyncTask.error();
};
Dropbox.choose(options);
core.showMessage("Please make sure the Dropbox chooser popup is not blocked by your browser.");
});
};
asyncTask.onSuccess = function() {
callback(undefined, paths);
};
asyncTask.onError = function() {
callback(true);
};
asyncTaskRunner.addTask(asyncTask);
}; };
dropboxHelper.importFiles = function(paths) { dropboxHelper.importFiles = function(paths) {
dropboxHelper.downloadMetadata(paths, function(result) { dropboxHelper.downloadMetadata(paths, function(error, result) {
if(result === undefined) { if(error) {
return; return;
} }
dropboxHelper.downloadContent(result, function(result) { dropboxHelper.downloadContent(result, function(error, result) {
if(result === undefined) { if(error) {
return; return;
} }
for(var i=0; i<result.length; i++) { for(var i=0; i<result.length; i++) {
var file = result[i]; var file = result[i];
fileSyncIndex = SYNC_PROVIDER_DROPBOX + encodeURIComponent(file.path.toLowerCase()); syncIndex = SYNC_PROVIDER_DROPBOX + encodeURIComponent(file.path.toLowerCase());
localStorage[fileSyncIndex + ".version"] = file.versionTag; localStorage[syncIndex + ".version"] = file.versionTag;
var contentCRC = core.crc32(file.content); var contentCRC = core.crc32(file.content);
localStorage[fileSyncIndex + ".contentCRC"] = contentCRC; localStorage[syncIndex + ".contentCRC"] = contentCRC;
var fileIndex = fileManager.createFile(file.name, file.content, [fileSyncIndex]); var fileIndex = fileManager.createFile(file.name, file.content, [syncIndex]);
fileManager.selectFile(fileIndex); fileManager.selectFile(fileIndex);
core.showMessage('"' + file.name + '" imported successfully from Dropbox.'); core.showMessage('"' + file.name + '" imported successfully from Dropbox.');
} }

36
js/dropbox-provider.js Normal file
View File

@ -0,0 +1,36 @@
define(["jquery", "dropbox-helper"], function($, dropboxHelper) {
// Dependencies
var core = undefined;
var dropboxProvider = {
providerType: PROVIDER_TYPE_PUBLISH_FLAG,
providerId: PROVIDER_DROPBOX,
providerName: "Dropbox",
defaultPublishFormat: "template"
};
dropboxProvider.publish = function(publishAttributes, title, content, callback) {
var path = dropboxHelper.checkPath(publishAttributes.path);
if(path === undefined) {
callback(true);
return;
}
dropboxHelper.upload(path, content, callback);
};
dropboxProvider.newPublishAttributes = function(event) {
var publishAttributes = {};
publishAttributes.path = core.getInputValue($("#input-publish-dropbox-path"), event);
if(event.isPropagationStopped()) {
return undefined;
}
return publishAttributes;
};
dropboxProvider.init = function(coreModule) {
core = coreModule;
};
return dropboxProvider;
});

View File

@ -301,8 +301,8 @@ define(["jquery", "google-helper", "dropbox-helper", "github-helper", "synchroni
var fileIndex = fileManager.getCurrentFileIndex(); var fileIndex = fileManager.getCurrentFileIndex();
var content = localStorage[fileIndex + ".content"]; var content = localStorage[fileIndex + ".content"];
var title = localStorage[fileIndex + ".title"]; var title = localStorage[fileIndex + ".title"];
dropboxHelper.upload(path, content, function(syncIndex) { dropboxHelper.upload(path, content, function(error, syncIndex) {
if (syncIndex === undefined) { if (error) {
return; return;
} }
var contentCRC = core.crc32(content); var contentCRC = core.crc32(content);
@ -315,8 +315,8 @@ define(["jquery", "google-helper", "dropbox-helper", "github-helper", "synchroni
}); });
} }
function importDropbox(paths) { function importDropbox(error, paths) {
if(paths === undefined) { if(error) {
return; return;
} }
var importPaths = []; var importPaths = [];

View File

@ -1,4 +1,4 @@
define(["jquery", "github-provider", "blogger-provider", "underscore"], function($) { define(["jquery", "github-provider", "blogger-provider", "dropbox-provider", "underscore"], function($) {
// Dependencies // Dependencies
var core = undefined; var core = undefined;
@ -131,6 +131,7 @@ define(["jquery", "github-provider", "blogger-provider", "underscore"], function
function initNewLocation(provider) { function initNewLocation(provider) {
var defaultPublishFormat = provider.defaultPublishFormat || "markdown"; var defaultPublishFormat = provider.defaultPublishFormat || "markdown";
newLocationProvider = provider; newLocationProvider = provider;
$(".publish-provider-name").text(provider.providerName);
// Show/hide controls depending on provider // Show/hide controls depending on provider
$('div[class*=" modal-publish-"]').hide().filter(".modal-publish-" + provider.providerId).show(); $('div[class*=" modal-publish-"]').hide().filter(".modal-publish-" + provider.providerId).show();

View File

@ -89,16 +89,14 @@ define(["jquery", "google-helper", "dropbox-helper"], function($, googleHelper,
} else if (fileSyncIndex.indexOf(SYNC_PROVIDER_DROPBOX) === 0) { } else if (fileSyncIndex.indexOf(SYNC_PROVIDER_DROPBOX) === 0) {
var path = fileSyncIndex.substring(SYNC_PROVIDER_DROPBOX.length); var path = fileSyncIndex.substring(SYNC_PROVIDER_DROPBOX.length);
path = decodeURIComponent(path); path = decodeURIComponent(path);
dropboxHelper.upload(path, uploadContent, function(result) { dropboxHelper.upload(path, uploadContent, function(error, result) {
if (result !== undefined) { if (error) {
localStorage[fileSyncIndex + ".contentCRC"] = uploadContentCRC; // If error we abort the synchronization (retry later)
locationUp(callback); callback(error);
return; return;
} }
localStorage[fileSyncIndex + ".contentCRC"] = uploadContentCRC;
// If error we abort the synchronization (retry later) locationUp(callback);
callback("abort");
return;
}); });
} else { } else {
// This should never happen // This should never happen
@ -236,14 +234,14 @@ define(["jquery", "google-helper", "dropbox-helper"], function($, googleHelper,
return; return;
} }
var lastChangeId = localStorage[SYNC_PROVIDER_DROPBOX + "lastChangeId"]; var lastChangeId = localStorage[SYNC_PROVIDER_DROPBOX + "lastChangeId"];
dropboxHelper.checkUpdates(lastChangeId, function(changes, newChangeId) { dropboxHelper.checkUpdates(lastChangeId, function(error, changes, newChangeId) {
if (changes === undefined) { if (error) {
callback("error"); callback(error);
return; return;
} }
dropboxHelper.downloadContent(changes, function(changes) { dropboxHelper.downloadContent(changes, function(error, changes) {
if (changes === undefined) { if (error) {
callback("error"); callback(error);
return; return;
} }
var updateFileTitles = false; var updateFileTitles = false;