Repaired sync down

This commit is contained in:
benweet 2013-04-03 23:52:29 +01:00
parent 6fae74a18e
commit ec9d93e64c
7 changed files with 187 additions and 105 deletions

View File

@ -10,3 +10,4 @@ RequireJS - http://requirejs.org/
PageDown - https://code.google.com/p/pagedown/ PageDown - https://code.google.com/p/pagedown/
UI Layout - http://layout.jquery-dev.net/ UI Layout - http://layout.jquery-dev.net/
jGrowl - https://github.com/stanlemon/jGrowl/ jGrowl - https://github.com/stanlemon/jGrowl/
GLYPHICONS - http://glyphicons.com/

View File

@ -5,6 +5,10 @@ body {
background-color: #f5f5f5; background-color: #f5f5f5;
} }
.working {
cursor: progress;
}
.btn { .btn {
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
@ -25,12 +29,23 @@ div, span, a, ul, li, textarea, input, button {
text-shadow: none !important; text-shadow: none !important;
} }
.btn, .navbar-inner, .ui-layout-east, .ui-layout-south, textarea, input, .input-append .add-on { .btn, .navbar-inner, .ui-layout-east, .ui-layout-south, textarea, input, .add-on {
border: none !important; border: none !important;
} }
.border, .dropdown-menu { .dropdown-menu {
border: 1px solid #ddd !important; border: 1px solid #e2e2e2 !important;
}
.input-prepend input,
.input-prepend .btn,
.input-prepend .add-on
{
border: 1px solid #ebebeb !important;
}
input.error {
border-color: #ee5f5b !important;
} }
.navbar-inner .btn { .navbar-inner .btn {

View File

@ -22,15 +22,15 @@
<i class="icon-refresh"></i> <i class="icon-refresh"></i>
</button></li> </button></li>
<li class="btn-group"><button class="btn action-create-file" <li class="btn-group"><button class="btn action-create-file"
title="New local file"> title="New local document">
<i class="icon-file"></i> <i class="icon-file"></i>
</button> </button>
<button class="btn" title="Delete local file" <button class="btn" title="Delete local document"
data-toggle="modal" data-target="#modal-remove-file-confirm"> data-toggle="modal" data-target="#modal-remove-file-confirm">
<i class="icon-trash"></i> <i class="icon-trash"></i>
</button> </button>
<button class="btn dropdown-toggle" data-toggle="dropdown" <button class="btn dropdown-toggle" data-toggle="dropdown"
title="Open local file"> title="Open local document">
<i class="icon-folder-open"></i> <i class="icon-folder-open"></i>
</button> </button>
<ul id="file-selector" class="dropdown-menu"> <ul id="file-selector" class="dropdown-menu">
@ -47,27 +47,27 @@
<li class="dropdown-submenu"><a href="#"><i <li class="dropdown-submenu"><a href="#"><i
class="icon-gdrive"></i> Google Drive</a> class="icon-gdrive"></i> Google Drive</a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a class="action-upload-gdrive" href="#">Export <li><a href="#" class="action-upload-gdrive">Export to
to Google Drive</a></li> Google Drive</a></li>
<li><a href="#" data-toggle="modal" data-target="#modal-download-gdrive">Import <li><a href="#" data-toggle="modal"
from Google Drive</a></li> data-target="#modal-download-gdrive">Import from Google
Drive</a></li>
</ul></li> </ul></li>
<li class="dropdown-submenu"><a href="#"><i <li class="dropdown-submenu"><a href="#"><i
class="icon-dropbox"></i> Dropbox</a> class="icon-dropbox"></i> Dropbox</a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a class="action-upload-dropbox" href="#">Export <li><a class="action-upload-dropbox" href="#">Export to
to Dropbox</a></li> Dropbox</a></li>
<li><a class="action-download-dropbox" href="#">Import <li><a class="action-download-dropbox" href="#">Import
from Dropbox</a></li> from Dropbox</a></li>
</ul></li> </ul></li>
<li><a href="#" <li><a href="#" data-toggle="modal"
data-toggle="modal" data-target="#modal-manage-sync"><i data-target="#modal-manage-sync"><i class="icon-refresh"></i>
class="icon-refresh"></i> Manage synchronization</a></li> Manage synchronization</a></li>
<li class="divider"></li> <li class="divider"></li>
<li><a href="#" <li><a href="#" data-toggle="modal"
data-toggle="modal" data-target="#modal-settings" data-target="#modal-settings" class="action-load-settings"><i
class="action-load-settings"><i class="icon-cog"></i> class="icon-cog"></i> Settings</a></li>
Settings</a></li>
<li><a href="#" data-toggle="modal" <li><a href="#" data-toggle="modal"
data-target="#modal-about"><i class="icon-question-sign"></i> data-target="#modal-about"><i class="icon-question-sign"></i>
About</a></li> About</a></li>
@ -76,9 +76,9 @@
<ul class="nav pull-right"> <ul class="nav pull-right">
<li><i class="working-indicator icon-spinner hide"></i></li> <li><i class="working-indicator icon-spinner hide"></i></li>
<li><a class="brand" id="file-title" href="#" <li><a class="brand" id="file-title" href="#"
title="Rename current file"> </a></li> title="Rename current document"> </a></li>
<li class="navbar-form"><input id="file-title-input" <li class="navbar-form"><input id="file-title-input"
type="text" class="span3 hide" placeholder="File title" /></li> type="text" class="span3 hide" placeholder="Document title" /></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -111,9 +111,13 @@
<h3>Import</h3> <h3>Import</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<p>Please provide a Google Drive file ID: <p>Please provide a Google Drive file ID:</p>
</p> <div class="input-prepend">
<p><input type="text" class="border span6 gdrive-fileid" placeholder="File ID"></input></p> <span class="add-on"><i class="icon-gdrive"></i></span><input
id="download-gdrive-fileid" type="text" class="span5" placeholder="Google Drive file ID"></input>
</div>
<p class="muted"><b>NOTE:</b> This will create a local copy of your Google Drive document
and keep it synchronized.</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<a href="#" class="btn" data-dismiss="modal">Cancel</a> <a href="#" <a href="#" class="btn" data-dismiss="modal">Cancel</a> <a href="#"
@ -133,14 +137,20 @@
is synchronized with these locations: is synchronized with these locations:
</p> </p>
</div> </div>
<br class="msg-sync-list hide" />
<p class="msg-sync-list hide muted"><b>NOTE:</b> Removing a <p class="msg-sync-list hide muted"><b>NOTE:</b> Removing a
synchronized location will not delete any file.</p> synchronized location will not delete any file.</p>
<p class="msg-no-sync hide">"<span class="file-title"></span>" is <p class="msg-no-sync hide">"<span class="file-title"></span>" is
not synchronized. not synchronized.
</p> </p>
<p class="msg-no-sync hide muted"><b>NOTE:</b> You can add <p>Add a synchronized location manually:</p>
synchronized locations using the top-right menu.</p> <div class="input-prepend input-append">
<span class="add-on"><i class="icon-gdrive"></i></span><input
id="manual-gdrive-fileid" type="text" class="span5" placeholder="Google Drive file ID"></input>
<a class="btn action-manual-gdrive" data-dismiss="modal"><i class="icon-ok"></i></a>
</div>
<p class="muted"><b>NOTE:</b> Adding a synchronized location will
first upload the local document and overwrite the existing file on the
server.</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<a href="#" class="btn btn-primary" data-dismiss="modal">Close</a> <a href="#" class="btn btn-primary" data-dismiss="modal">Close</a>
@ -178,69 +188,73 @@
aria-hidden="true">&times;</button> aria-hidden="true">&times;</button>
<img src="img/stackedit-promo.png" /> <img src="img/stackedit-promo.png" />
</div> </div>
<div class="modal-body"> <div class="modal-body">
<dl> <dl>
<dt>About:</dt> <dt>About:</dt>
<dd> <dd>
<a target="_blank" href="https://github.com/benweet/stackedit/">GitHub <a target="_blank" href="https://github.com/benweet/stackedit/">GitHub
page</a> page</a>
</dd> </dd>
<dd> <dd>
<a target="_blank" <a target="_blank"
href="https://chrome.google.com/webstore/detail/stackedit/iiooodelglhkcpgbajoejffhijaclcdg">Chrome href="https://chrome.google.com/webstore/detail/stackedit/iiooodelglhkcpgbajoejffhijaclcdg">Chrome
app</a> app</a>
</dd> </dd>
<dd> <dd>
<a target="_blank" href="https://twitter.com/stackedit/">Follow <a target="_blank" href="https://twitter.com/stackedit/">Follow
on Twitter</a> on Twitter</a>
</dd> </dd>
<dd> <dd>
<a target="_blank" href="https://www.facebook.com/stackedit/">Follow <a target="_blank" href="https://www.facebook.com/stackedit/">Follow
on Facebook</a> on Facebook</a>
</dd> </dd>
<dd> <dd>
<a target="_blank" <a target="_blank"
href="https://plus.google.com/b/110816046787593496375/110816046787593496375">Follow href="https://plus.google.com/b/110816046787593496375/110816046787593496375">Follow
on Google+</a> on Google+</a>
</dd> </dd>
</dl> </dl>
<dl> <dl>
<dt>Developer:</dt> <dt>Developer:</dt>
<dd> <dd>
<a target="_blank" href="http://www.benoitschweblin.com">Benoit <a target="_blank" href="http://www.benoitschweblin.com">Benoit
Schweblin</a> Schweblin</a>
<dd> <dd>
</dl> </dl>
<dl> <dl>
<dt>Credits:</dt> <dt>Credit:</dt>
<dd>
<a target="_blank" href="http://jquery.com/">jQuery</a>
</dd>
<dd> <dd>
<a target="_blank" href="http://twitter.github.com/bootstrap/">Bootstrap</a> <a target="_blank" href="http://twitter.github.com/bootstrap/">Bootstrap</a>
</dd> </dd>
<dd> <dd>
<a target="_blank" href="http://requirejs.org/">RequireJS</a> <a target="_blank" href="http://glyphicons.com/">GLYPHICONS</a>
</dd>
<dd>
<a target="_blank" href="https://code.google.com/p/pagedown/">PageDown</a>
</dd>
<dd>
<a target="_blank" href="http://layout.jquery-dev.net/">UI
Layout</a>
</dd> </dd>
<dd> <dd>
<a target="_blank" href="https://github.com/stanlemon/jGrowl/">jGrowl</a> <a target="_blank" href="https://github.com/stanlemon/jGrowl/">jGrowl</a>
</dd> </dd>
</dl> <dd>
<p>Copyright 2013 <a target="_blank" <a target="_blank" href="http://jquery.com/">jQuery</a>
href="http://www.benoitschweblin.com">Benoit Schweblin</a><br /> </dd>
Licensed under an <a target="_blank" <dd>
href="http://www.apache.org/licenses/LICENSE-2.0">Apache License</a></p> <a target="_blank" href="http://layout.jquery-dev.net/">jQuery UI
</div> Layout</a>
</dd>
<dd>
<a target="_blank" href="https://code.google.com/p/pagedown/">PageDown</a>
</dd>
<dd>
<a target="_blank" href="http://requirejs.org/">RequireJS</a>
</dd>
</dl>
<p>Copyright 2013 <a target="_blank"
href="http://www.benoitschweblin.com">Benoit Schweblin</a><br />
Licensed under an <a target="_blank"
href="http://www.apache.org/licenses/LICENSE-2.0">Apache License</a></p>
</div>
<div class="modal-footer"> <div class="modal-footer">
<a href="#" class="btn btn-primary" data-dismiss="modal">Close</a> <a href="#" class="btn btn-primary" data-dismiss="modal">Close</a>
</div> </div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -3,7 +3,7 @@ var GOOGLE_SCOPES = [ 'https://www.googleapis.com/auth/drive.install',
var DEFAULT_FILE_TITLE = "Title"; var DEFAULT_FILE_TITLE = "Title";
var GDRIVE_DEFAULT_FILE_TITLE = "New Markdown document"; var GDRIVE_DEFAULT_FILE_TITLE = "New Markdown document";
var CHECK_ONLINE_PERIOD = 60000; var CHECK_ONLINE_PERIOD = 60000;
var AJAX_TIMEOUT = 5000; var AJAX_TIMEOUT = 10000;
var ASYNC_TASK_DEFAULT_TIMEOUT = 30000; var ASYNC_TASK_DEFAULT_TIMEOUT = 30000;
var AUTH_POPUP_TIMEOUT = 90000; var AUTH_POPUP_TIMEOUT = 90000;
var SYNC_PERIOD = 60000; var SYNC_PERIOD = 60000;

View File

@ -10,13 +10,32 @@ define(["jquery", "bootstrap", "jgrowl", "layout", "Markdown.Editor"], function(
// Usage: callback = callback || core.doNothing; // Usage: callback = callback || core.doNothing;
core.doNothing = function() {}; core.doNothing = function() {};
// Useful function
core.getInputValue = function(element, event) {
var value = element.val();
if (value !== undefined) {
value = value.replace(/^\s+|\s+$/g, '');
element.val(undefined);
}
if (value === undefined || value.length === 0) {
element.stop(true, true).addClass("error").delay(400)
.switchClass("error");
event.stopPropagation();
return undefined;
}
return value;
};
// Used by asyncTaskRunner // Used by asyncTaskRunner
core.showWorkingIndicator = function(show) { core.showWorkingIndicator = function(show) {
if (show === false) { if (show === false) {
$(".working-indicator").addClass("hide"); $(".working-indicator").addClass("hide");
$("body").removeClass("working");
} else { } else {
$(".working-indicator").removeClass("hide"); $(".working-indicator").removeClass("hide");
$("body").addClass("working");
} }
}; };
@ -58,7 +77,7 @@ define(["jquery", "bootstrap", "jgrowl", "layout", "Markdown.Editor"], function(
}; };
core.setOnline = function() { core.setOnline = function() {
if(offline === true) { if(core.isOffline === true) {
$(".msg-offline").parents(".jGrowl-notification").trigger( $(".msg-offline").parents(".jGrowl-notification").trigger(
'jGrowl.beforeClose'); 'jGrowl.beforeClose');
core.isOffline = false; core.isOffline = false;
@ -117,8 +136,6 @@ define(["jquery", "bootstrap", "jgrowl", "layout", "Markdown.Editor"], function(
spacing_closed : 15, spacing_closed : 15,
togglerLength_open : 90, togglerLength_open : 90,
togglerLength_closed : 90, togglerLength_closed : 90,
center__minWidth : 100,
center__minHeight : 100,
stateManagement__enabled : false stateManagement__enabled : false
}; };
if (settings.layoutOrientation == "horizontal") { if (settings.layoutOrientation == "horizontal") {
@ -184,7 +201,6 @@ define(["jquery", "bootstrap", "jgrowl", "layout", "Markdown.Editor"], function(
$("#wmd-redo-button").append($("<i>").addClass("icon-share-alt")); $("#wmd-redo-button").append($("<i>").addClass("icon-share-alt"));
}; };
// Base64 conversion // Base64 conversion
core.encodeBase64 = function(str) { core.encodeBase64 = function(str) {
if (str.length === 0) { if (str.length === 0) {

View File

@ -76,10 +76,15 @@ define(["jquery", "core", "gdrive", "synchronizer", "async-runner"], function($,
window.open(uriContent, 'file'); window.open(uriContent, 'file');
}); });
$(".action-upload-gdrive").click(uploadGdrive); $(".action-upload-gdrive").click(uploadGdrive);
$(".action-download-gdrive").click(function() { $(".action-download-gdrive").click(function(event) {
var fileId = $(".gdrive-fileid").val(); var fileId = core.getInputValue($("#download-gdrive-fileid"), event);
$(".gdrive-fileid").val(""); if(checkGdriveFileId(fileId) === true) {
downloadGdrive(fileId); gdrive.importFiles([fileId]);
}
});
$(".action-manual-gdrive").click(function(event) {
var fileId = core.getInputValue($("#manual-gdrive-fileid"), event);
manualGdrive(fileId);
}); });
$(".action-download-dropbox").click(function() { $(".action-download-dropbox").click(function() {
core.showMessage("Sorry, Dropbox synchronization is not yet available."); core.showMessage("Sorry, Dropbox synchronization is not yet available.");
@ -216,7 +221,6 @@ define(["jquery", "core", "gdrive", "synchronizer", "async-runner"], function($,
} }
return result; return result;
} }
synchronizer.useGoogleDrive = useGoogleDrive;
// Update the file title // Update the file title
var title = localStorage[fileIndex + ".title"]; var title = localStorage[fileIndex + ".title"];
@ -243,6 +247,7 @@ define(["jquery", "core", "gdrive", "synchronizer", "async-runner"], function($,
} }
$("#file-selector").append(li); $("#file-selector").append(li);
} }
synchronizer.useGoogleDrive = useGoogleDrive;
}; };
// Remove a synchronized location // Remove a synchronized location
@ -280,22 +285,54 @@ define(["jquery", "core", "gdrive", "synchronizer", "async-runner"], function($,
var content = localStorage[fileIndex + ".content"]; var content = localStorage[fileIndex + ".content"];
var title = localStorage[fileIndex + ".title"]; var title = localStorage[fileIndex + ".title"];
gdrive.createFile(title, content, function(fileSyncIndex) { gdrive.createFile(title, content, function(fileSyncIndex) {
if (fileSyncIndex) { if (fileSyncIndex === undefined) {
localStorage[fileIndex + ".sync"] += fileSyncIndex + ";"; return;
refreshManageSync();
fileManager.updateFileTitles();
core.showMessage('"' + title
+ '" will now be synchronized on Google Drive.');
} }
localStorage[fileIndex + ".sync"] += fileSyncIndex + ";";
refreshManageSync();
fileManager.updateFileTitles();
core.showMessage('"' + title
+ '" will now be synchronized on Google Drive.');
}); });
} }
function checkGdriveFileId(fileId) {
if(!fileId) {
return false;
}
// Check that file is not synchronized with an other one
var fileSyncIndex = SYNC_PROVIDER_GDRIVE + fileId;
var fileIndex = fileManager.getFileIndexFromSync(fileSyncIndex);
if(fileIndex !== undefined) {
var title = localStorage[fileIndex + ".title"];
core.showError('Google Drive file is already synchronized with "' + title + '"');
return false;
}
return true;
}
function downloadGdrive(fileId) { function manualGdrive(fileId) {
fileId = fileId.trim(); if(checkGdriveFileId(fileId) === false) {
if(fileId.length === 0) {
return; return;
} }
gdrive.importFiles([fileId]); var fileIndex = localStorage["file.current"];
var title = localStorage[fileIndex + ".title"];
gdrive.downloadMetadata([fileId], function(result) {
if(result === undefined || result.length === 0) {
return;
}
var file = result[0];
var fileSyncIndex = SYNC_PROVIDER_GDRIVE + file.id;
localStorage[fileSyncIndex + ".etag"] = file.etag;
localStorage[fileIndex + ".sync"] += fileSyncIndex + ";";
refreshManageSync();
fileManager.updateFileTitles();
core.showMessage('"' + title
+ '" will now be synchronized on Google Drive.');
// Force synchronization
synchronizer.addFileForUpload(fileIndex);
synchronizer.forceSync();
});
} }
function refreshManageSync() { function refreshManageSync() {
@ -317,7 +354,7 @@ define(["jquery", "core", "gdrive", "synchronizer", "async-runner"], function($,
'<i class="icon-gdrive"></i>')); '<i class="icon-gdrive"></i>'));
line.append($("<input>").prop("type", "text").prop( line.append($("<input>").prop("type", "text").prop(
"disabled", true).addClass("span5").val( "disabled", true).addClass("span5").val(
"FileID=" "ID="
+ fileSyncIndex.substring(SYNC_PROVIDER_GDRIVE.length))); + fileSyncIndex.substring(SYNC_PROVIDER_GDRIVE.length)));
} }
line.append($("<a>").addClass("btn").html( line.append($("<a>").addClass("btn").html(

View File

@ -254,7 +254,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
message: jqXHR.statusText message: jqXHR.statusText
}; };
// Handle error // Handle error
if(error.code === 403 || error.code === 404) { if(error.code === 404) {
error = "File is not available."; error = "File is not available.";
} }
handleError(error, asyncTask, callback); handleError(error, asyncTask, callback);
@ -337,8 +337,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
if (typeof error === "string") { if (typeof error === "string") {
errorMsg = error; errorMsg = error;
} }
else if ((error.code >= 500 && error.code < 600) || else if (error.code >= 500 && error.code < 600) {
(error.code === 401 && error.message == "Login Required")) { // Sometimes we have this 401 error
errorMsg = "Google Drive is not accessible."; errorMsg = "Google Drive is not accessible.";
// Retry as described in Google's best practices // Retry as described in Google's best practices
asyncTask.retry(); asyncTask.retry();