periodic down synchronization

This commit is contained in:
benweet 2013-04-01 02:06:52 +01:00
parent dffc6e8829
commit fef879fe50
5 changed files with 470 additions and 188 deletions

View File

@ -1 +1 @@
CACHE MANIFEST # v4 CACHE: index.html css/bootstrap.css css/jgrowl.css css/main.css js/async-runner.js js/base64.js js/bootstrap.js js/gdrive.js js/jquery.jgrowl.js js/jquery.js js/jquery.layout.js js/jquery-ui.custom.js js/main.js js/Markdown.Converter.js js/Markdown.Editor.js js/Markdown.Sanitizer.js img/ajax-loader.gif img/gdrive.png img/glyphicons-halflings.png img/glyphicons-halflings-white.png img/stackedit-16.png img/stackedit-32.ico NETWORK: *
CACHE MANIFEST # v5 CACHE: index.html css/bootstrap.css css/jgrowl.css css/main.css js/async-runner.js js/base64.js js/bootstrap.js js/gdrive.js js/jquery.jgrowl.js js/jquery.js js/jquery.layout.js js/jquery-ui.custom.js js/main.js js/Markdown.Converter.js js/Markdown.Editor.js js/Markdown.Sanitizer.js img/ajax-loader.gif img/gdrive.png img/glyphicons-halflings.png img/glyphicons-halflings-white.png img/stackedit-16.png img/stackedit-32.ico NETWORK: *

View File

@ -100,7 +100,7 @@
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">&times;</button>
<h3>Remove file</h3>
<h3>Remove</h3>
</div>
<div class="modal-body">
<p>Are you sure you want to remove "<span class="file-title"></span>"?

View File

@ -1,66 +1,101 @@
var ASYNC_TASK_DEFAULT_TIMEOUT = 30000;
/**
* Used to run any asynchronous tasks sequentially (ajax mainly)
* An asynchronous task must be created with:
* - a required run() function that may call success() or error()
* - a required run() function that may call success(), error() or retry()
* - an optional onSuccess() function
* - an optional onError() function
* - an optional timeout property
* - an optional timeout field (default is 30000)
*/
var asyncTaskRunner = (function() {
var asyncTaskRunner = {};
var asyncTaskQueue = [];
var currentTask = undefined;
var currentTaskStartTime = new Date().getTime();
var currentTaskRunning = false;
var currentTaskStartTime = currentTime;
// Run the next task in the queue if any and no other is running
asyncTaskRunner.runTask = function() {
// If there is a task currently running
if(currentTask !== undefined) {
if(currentTaskRunning !== false) {
// If the current task takes too long
var timeout = currentTask.timeout || 30000;
var timeout = currentTask.timeout || ASYNC_TASK_DEFAULT_TIMEOUT;
if(currentTaskStartTime + timeout < currentTime) {
currentTask.error();
}
return;
}
// If no task in the queue
if(asyncTaskQueue.length === 0) {
return;
if(currentTask === undefined) {
// If no task in the queue
if(asyncTaskQueue.length === 0) {
return;
}
// Dequeue an enqueued task
currentTask = asyncTaskQueue.shift();
currentTaskStartTime = currentTime;
showWorkingIndicator(true);
// Set task attributes and functions
currentTask.finished = false;
currentTask.retryCounter = 0;
currentTask.finish = function() {
this.finished = true;
showWorkingIndicator(false);
currentTask = undefined;
currentTaskRunning = false;
asyncTaskRunner.runTask();
};
currentTask.success = function() {
if(this.finished === true) {
return;
}
try {
if(this.onSuccess) {
this.onSuccess();
}
} finally {
this.finish();
}
};
currentTask.error = function() {
if(this.finished === true) {
return;
}
try {
if(this.onError) {
this.onError();
}
} finally {
this.finish();
}
};
currentTask.retry = function() {
if(this.finished === true) {
return;
}
if(currentTask.retryCounter === 5) {
this.error();
return;
}
// Implement an exponential backoff
var delay = (Math.pow(2, currentTask.retryCounter++) + Math.random()) * 1000;
console.log(delay);
currentTaskStartTime = currentTime + delay;
currentTaskRunning = false;
asyncTaskRunner.runTask();
};
}
currentTask = asyncTaskQueue.shift();
currentTaskStartTime = currentTime;
showWorkingIndicator(true);
// Set task attributes and functions
currentTask.finished = false;
currentTask.finish = function() {
this.finished = true;
showWorkingIndicator(false);
currentTask = undefined;
asyncTaskRunner.runTask();
};
currentTask.success = function() {
if(this.finished === true) {
return;
}
if(this.onSuccess) {
this.onSuccess();
}
this.finish();
};
currentTask.error = function() {
if(this.finished === true) {
return;
}
if(this.onError) {
this.onError();
}
this.finish();
};
currentTask.run();
// Run the task
if(currentTaskStartTime <= currentTime) {
currentTaskRunning = true;
currentTask.run();
}
};
// Add a task in the queue

View File

@ -1,10 +1,11 @@
var GOOGLE_CLIENT_ID = '241271498917-jpto9lls9fqnem1e4h6ppds9uob8rpvu.apps.googleusercontent.com';
var SCOPES = [ 'https://www.googleapis.com/auth/drive.install',
'https://www.googleapis.com/auth/drive.file' ];
var AUTH_POPUP_TIMEOUT = 90000;
var gdriveDelayedFunction = undefined;
function runGdriveDelayedFunction() {
if(gdriveDelayedFunction !== undefined) {
if (gdriveDelayedFunction !== undefined) {
gdriveDelayedFunction();
}
}
@ -13,30 +14,31 @@ var gdrive = (function($) {
var connected = false;
var authenticated = false;
var doNothing = function() {};
var doNothing = function() {
};
var gdrive = {};
// Try to connect Gdrive by downloading client.js
function connect(callback) {
callback = callback || doNothing;
var asyncTask = {};
asyncTask.run = function() {
if(connected === true) {
if (connected === true) {
asyncTask.success();
return;
}
gdriveDelayedFunction = function() {
asyncTask.success();
};
$.ajax({
url: "https://apis.google.com/js/client.js?onload=runGdriveDelayedFunction",
dataType: "script",
timeout: 5000
})
.fail(function() {
asyncTask.error();
});
$
.ajax(
{
url : "https://apis.google.com/js/client.js?onload=runGdriveDelayedFunction",
dataType : "script", timeout : AJAX_TIMEOUT }).fail(
function() {
asyncTask.error();
});
};
asyncTask.onSuccess = function() {
gdriveDelayedFunction = undefined;
@ -50,31 +52,35 @@ var gdrive = (function($) {
};
asyncTaskRunner.addTask(asyncTask);
}
// Try to authenticate with Oauth
function authenticate(callback, immediate) {
callback = callback || doNothing;
if(immediate === undefined) {
if (immediate === undefined) {
immediate = true;
}
connect(function() {
if(connected === false) {
if (connected === false) {
callback();
return;
}
var asyncTask = {};
// If not immediate we add time for user to enter his credentials
if(immediate === false) {
asyncTask.timeout = 90000;
if (immediate === false) {
asyncTask.timeout = AUTH_POPUP_TIMEOUT;
}
asyncTask.run = function() {
if(authenticated === true) {
if (authenticated === true) {
asyncTask.success();
return;
}
gapi.auth.authorize({ 'client_id' : GOOGLE_CLIENT_ID, 'scope' : SCOPES,
'immediate' : immediate }, function(authResult) {
if (immediate === false) {
showMessage("Please make sure the Google authorization popup is not blocked by your browser...");
}
gapi.auth.authorize({ 'client_id' : GOOGLE_CLIENT_ID,
'scope' : SCOPES, 'immediate' : immediate }, function(
authResult) {
if (!authResult || authResult.error) {
asyncTask.error();
return;
@ -90,7 +96,7 @@ var gdrive = (function($) {
};
asyncTask.onError = function() {
// If immediate did not work retry without immediate flag
if(connected === true && immediate === true) {
if (connected === true && immediate === true) {
authenticate(callback, false);
return;
}
@ -100,14 +106,45 @@ var gdrive = (function($) {
});
}
function handleError(response, asyncTask, callback) {
var errorMsg = undefined;
if (response && response.error) {
var error = response.error;
// Try to analyze the error
if (error.code >= 500 && error.code < 600) {
errorMsg = "Google Drive is not accessible.";
// Retry as described in Google's best practices
asyncTask.retry();
return;
} else if (error.code === 401) {
authenticated = false;
errorMsg = "Access to Google Drive is not authorized.";
} else if (error.code === -1) {
connected = false;
authenticated = false;
onOffline();
} else {
errorMsg = "Google Drive error (" + error.code + ": "
+ error.message + ").";
}
}
asyncTask.onError = function() {
if (errorMsg !== undefined) {
showError(errorMsg);
}
callback();
};
asyncTask.error();
}
function upload(fileId, parentId, title, content, callback) {
callback = callback || doNothing;
authenticate(function() {
if(connected === false) {
if (connected === false) {
callback();
return;
}
var fileIndex = undefined;
var asyncTask = {};
asyncTask.run = function() {
@ -117,13 +154,14 @@ var gdrive = (function($) {
var contentType = 'text/x-markdown';
var metadata = { title : title, mimeType : contentType };
if (parentId) {
if (parentId !== undefined) {
// Specify the directory
metadata.parents = [ { kind : 'drive#fileLink', id : parentId } ];
metadata.parents = [ { kind : 'drive#fileLink',
id : parentId } ];
}
var path = '/upload/drive/v2/files';
var method = 'POST';
if (fileId) {
if (fileId !== undefined) {
// If it's an update
path += "/" + fileId;
method = 'PUT';
@ -133,59 +171,151 @@ var gdrive = (function($) {
var multipartRequestBody = delimiter
+ 'Content-Type: application/json\r\n\r\n'
+ JSON.stringify(metadata) + delimiter + 'Content-Type: '
+ contentType + '\r\n' + 'Content-Transfer-Encoding: base64\r\n'
+ '\r\n' + base64Data + close_delim;
+ contentType + '\r\n'
+ 'Content-Transfer-Encoding: base64\r\n' + '\r\n'
+ base64Data + close_delim;
var request = gapi.client.request({
'path' : path,
'method' : method,
'params' : { 'uploadType' : 'multipart', },
'headers' : { 'Content-Type' : 'multipart/mixed; boundary="'
+ boundary + '"', }, 'body' : multipartRequestBody, });
request.execute(function(file) {
if(file.id) {
var request = gapi.client
.request({
'path' : path,
'method' : method,
'params' : { 'uploadType' : 'multipart', },
'headers' : { 'Content-Type' : 'multipart/mixed; boundary="'
+ boundary + '"', }, 'body' : multipartRequestBody, });
request.execute(function(response) {
if (response && response.id) {
// Upload success
fileIndex = SYNC_PROVIDER_GDRIVE + file.id;
localStorage[fileIndex + ".etag"] = file.etag;
fileIndex = SYNC_PROVIDER_GDRIVE + response.id;
localStorage[fileIndex + ".etag"] = response.etag;
asyncTask.success();
return
return;
}
// Upload failed, try to analyse
if(file.error.code === 401) {
showError("Google Drive is not accessible.");
// If file has been removed from Google Drive
if(fileId !== undefined && response.error.code === 404) {
showMessage('"' + title + '" has been removed from Google Drive.');
fileManager.removeSync(SYNC_PROVIDER_GDRIVE + fileId);
fileManager.updateFileTitles();
// Avoid error analyzed by handleError
response = undefined;
}
else {
connected = false;
authenticated = false;
onOffline();
}
asyncTask.error();
// Handle error
handleError(response, asyncTask, callback);
});
};
asyncTask.onSuccess = function() {
callback(fileIndex);
};
asyncTask.onError = function() {
asyncTaskRunner.addTask(asyncTask);
});
}
gdrive.checkUpdates = function(lastChangeId, callback) {
callback = callback || doNothing;
authenticate(function() {
if (connected === false) {
callback();
return;
}
var changes = [];
var newChangeId = lastChangeId || 0;
function retrievePageOfChanges(request) {
var nextPageToken = undefined;
var asyncTask = {};
asyncTask.run = function() {
request
.execute(function(response) {
if (response && response.largestChangeId) {
// Retrieve success
newChangeId = response.largestChangeId;
nextPageToken = response.nextPageToken;
if (response.items !== undefined) {
for ( var i = 0; i < response.items.length; i++) {
var item = response.items[i];
var etag = localStorage[SYNC_PROVIDER_GDRIVE
+ item.fileId + ".etag"];
if (etag
&& (item.deleted === true || item.file.etag != etag)) {
changes.push(item);
}
}
}
asyncTask.success();
return;
}
// Handle error
handleError(response, asyncTask, callback);
});
};
asyncTask.onSuccess = function() {
if (nextPageToken !== undefined) {
request = gapi.client.drive.changes
.list({ 'pageToken' : nextPageToken });
retrievePageOfChanges(request);
} else {
callback(changes, newChangeId);
}
};
asyncTaskRunner.addTask(asyncTask);
}
var initialRequest = gapi.client.drive.changes
.list({ 'startChangeId' : newChangeId + 1 });
retrievePageOfChanges(initialRequest);
});
};
gdrive.downloadContent = function(objects, callback, result) {
callback = callback || doNothing;
result = result || [];
if(objects.length === 0) {
callback(result);
return;
}
var object = objects.pop();
result.push(object);
var file = undefined;
// object may be a file
if(object.kind == "drive#file") {
file = object;
}
// object may be a change
else if(object.kind == "drive#change") {
file = object.file;
}
if(file === undefined) {
this.downloadContent(objects, callback, result);
return;
}
authenticate(function() {
if (connected === false) {
callback();
return;
}
var asyncTask = {};
asyncTask.run = function() {
var accessToken = gapi.auth.getToken().access_token;
$
.ajax(
{
url : file.downloadUrl,
headers : { "Authorization" : "Bearer "
+ accessToken }, dataType : "text",
timeout : AJAX_TIMEOUT }).done(
function(data, textStatus, jqXHR) {
file.content = data;
asyncTask.success();
}).fail(function() {
asyncTask.error();
});
};
asyncTask.onSuccess = function() {
gdrive.downloadContent(objects, callback, result);
};
asyncTaskRunner.addTask(asyncTask);
});
}
;
gdrive.init = function() {
try {
var state = JSON.parse(decodeURI((/state=(.+?)(&|$)/
.exec(location.search) || [ , null ])[1]));
if (state.action == 'create') {
upload(undefined, state.folderId,
fileManager.currentFile, fileManager.content, function(
fileIndex) {
console.log(fileIndex);
});
}
} catch (e) {
}
});
};
gdrive.createFile = function(title, content, callback) {
@ -195,6 +325,20 @@ var gdrive = (function($) {
gdrive.updateFile = function(id, title, content, callback) {
upload(id, undefined, title, content, callback);
};
gdrive.init = function() {
try {
var state = JSON.parse(decodeURI((/state=(.+?)(&|$)/
.exec(location.search) || [ , null ])[1]));
if (state.action == 'create') {
upload(undefined, state.folderId, fileManager.currentFile,
fileManager.content, function(fileIndex) {
console.log(fileIndex);
});
}
} catch (e) {
}
};
return gdrive;
})(jQuery);

View File

@ -18,6 +18,8 @@ function showWorkingIndicator(show) {
}
}
var AJAX_TIMEOUT = 5000;
var CHECK_ONLINE_PERIOD = 60000;
var offline = false;
var offlineTime = currentTime;
function onOffline() {
@ -36,21 +38,24 @@ function onOnline() {
'jGrowl.beforeClose');
}
function autoClean() {
function checkOnline() {
// Try to reconnect if we are offline but we have some network
if (offline === true && navigator.onLine === true
&& offlineTime + 60000 < currentTime) {
&& offlineTime + CHECK_ONLINE_PERIOD < currentTime) {
offlineTime = currentTime;
// Try to download anything to test the connection
$.ajax(
{ url : "https://apis.google.com/js/client.js", timeout : 5000,
dataType : "script" }).done(function() {
{ url : "https://apis.google.com/js/client.js",
timeout : AJAX_TIMEOUT, dataType : "script" }).done(function() {
onOnline();
});
}
}
var SYNC_DOWN_PERIOD = 60000;
var SYNC_PROVIDER_GDRIVE = "sync.gdrive.";
var syncGoogleDrive = false;
var synchronizer = (function($) {
var synchronizer = {};
@ -76,14 +81,13 @@ var synchronizer = (function($) {
}
};
// Recursive function to run synchronization of a single file on multiple
// locations
function sync(fileSyncIndexList, content, title) {
// Recursive function to upload a single file on multiple locations
function fileUp(fileSyncIndexList, content, title) {
if (fileSyncIndexList.length === 0) {
localStorage.removeItem("sync.current");
running = false;
uploadRunning = false;
// run the next file synchronization
synchronizer.run();
synchronizer.syncUp();
return;
}
var fileSyncIndex = fileSyncIndexList.pop();
@ -92,28 +96,28 @@ var synchronizer = (function($) {
if (fileSyncIndex.indexOf(SYNC_PROVIDER_GDRIVE) === 0) {
var id = fileSyncIndex.substring(SYNC_PROVIDER_GDRIVE.length);
gdrive.updateFile(id, title, content, function(result) {
if (!result && offline) {
if (result === undefined && offline === true) {
// If we detect offline mode we put the fileIndex back in
// the queue
synchronizer.addFile(localStorage["sync.current"]);
localStorage.removeItem("sync.current");
running = false;
uploadRunning = false;
return;
}
sync(fileSyncIndexList, content, title);
fileUp(fileSyncIndexList, content, title);
});
} else {
sync(fileSyncIndexList, content, title);
fileUp(fileSyncIndexList, content, title);
}
}
var running = false;
synchronizer.run = function() {
// If synchronization is already running or nothing to synchronize
if (running || syncQueue.length === 1 || offline) {
var uploadRunning = false;
synchronizer.syncUp = function() {
// If syncUp is already running or nothing to synchronize or offline
if (uploadRunning || syncQueue.length === 1 || offline) {
return;
}
running = true;
uploadRunning = true;
// Dequeue the fileIndex
var separatorPos = syncQueue.indexOf(";", 1);
@ -127,7 +131,101 @@ var synchronizer = (function($) {
// Parse the list of synchronized locations associated to the file
var fileSyncIndexList = localStorage[fileIndex + ".sync"].split(";");
sync(fileSyncIndexList, content, title);
fileUp(fileSyncIndexList, content, title);
};
function syncDownGdrive(callback) {
if (syncGoogleDrive === false) {
callback();
return;
}
var lastChangeId = parseInt(localStorage[SYNC_PROVIDER_GDRIVE
+ "lastChangeId"]);
gdrive.checkUpdates(lastChangeId, function(changes, newChangeId) {
if (changes === undefined) {
callback();
return;
}
gdrive.downloadContent(changes, function(changes) {
if (changes === undefined) {
callback();
return;
}
var updateFileTitles = false;
for ( var i = 0; i < changes.length; i++) {
var change = changes[i];
var fileSyncIndex = SYNC_PROVIDER_GDRIVE + change.fileId;
var fileIndexList = localStorage["file.list"].split(";");
var fileIndex = undefined;
// Look for local file associated to this synchronized location
for ( var i = 1; i < fileIndexList.length - 1; i++) {
var tempFileIndex = fileIndexList[i];
var sync = localStorage[tempFileIndex + ".sync"];
if (sync.indexOf(";" + fileSyncIndex + ";") !== -1) {
fileIndex = tempFileIndex;
break;
}
}
// No file corresponding (this should never happen...)
if(fileIndex === undefined) {
// We can remove the stored etag
localStorage.removeItem(fileSyncIndex + ".etag");
continue;
}
var title = localStorage[fileIndex + ".title"];
// File deleted
if (change.deleted === true) {
fileManager.removeSync(fileSyncIndex);
updateFileTitles = true;
showMessage('"' + title + '" has been removed from Google Drive.');
continue;
}
var content = localStorage[fileIndex + ".content"];
var file = change.file;
// File title changed
if(title != file.title) {
localStorage[fileIndex + ".title"] = file.title;
updateFileTitles = true;
showMessage('"' + title + '" has been renamed to "' + file.title + '" on Google Drive.');
}
// File content changed
if(content != file.content) {
localStorage[fileIndex + ".content"] = file.content;
showMessage('"' + file.title + '" has been updated from Google Drive.');
if(fileIndex == localStorage["file.current"]) {
updateFileTitles = false; // Done by next function
fileManager.selectFile();
}
}
// Update file etag
localStorage[fileSyncIndex + ".etag"] = file.etag;
// Synchronize file to others locations
synchronizer.addFile(fileIndex);
}
if(updateFileTitles) {
fileManager.updateFileTitles();
}
localStorage[SYNC_PROVIDER_GDRIVE
+ "lastChangeId"] = newChangeId;
callback();
});
});
}
var downloadRunning = false;
var lastSyncDown = 0;
synchronizer.syncDown = function() {
// If syncDown is already running or timeout is not reached or offline
if (downloadRunning || lastSyncDown + SYNC_DOWN_PERIOD > currentTime
|| offline) {
return;
}
downloadRunning = true;
lastSyncDown = currentTime;
syncDownGdrive(function() {
downloadRunning = false;
});
};
return synchronizer;
@ -143,19 +241,21 @@ var fileManager = (function($) {
synchronizer.init();
fileManager.selectFile();
// Save file automatically and synchronize
// Do periodic stuff
window.setInterval(function() {
currentTime = new Date().getTime();
fileManager.saveFile();
synchronizer.run();
synchronizer.syncDown();
synchronizer.syncUp();
asyncTaskRunner.runTask();
autoClean();
checkOnline();
}, 1000);
$(".action-create-file").click(function() {
fileManager.saveFile();
fileManager.createFile();
fileManager.selectFile();
$("#file-title").click();
});
$(".action-remove-file").click(function() {
fileManager.deleteFile();
@ -172,8 +272,7 @@ var fileManager = (function($) {
var fileIndexTitle = localStorage["file.current"] + ".title";
if (title != localStorage[fileIndexTitle]) {
localStorage[fileIndexTitle] = title;
updateFileDescList();
updateFileTitleUI();
fileManager.updateFileTitles();
save = true;
}
}
@ -205,23 +304,18 @@ var fileManager = (function($) {
localStorage["file.counter"] = 0;
localStorage["file.list"] = ";";
}
updateFileDescList();
// If no file create one
if (fileDescList.length === 0) {
if (localStorage["file.list"].length === 1) {
this.createFile();
updateFileDescList();
}
// If no default file take first one
if (!localStorage["file.current"]) {
localStorage["file.current"] = fileDescList[0].index;
}
// Update the editor and the file title
// Update the file titles
this.updateFileTitles();
// Update the editor
var fileIndex = localStorage["file.current"];
$("#wmd-input").val(localStorage[fileIndex + ".content"]);
core.createEditor(function() {
save = true;
});
updateFileTitleUI();
};
fileManager.createFile = function(title) {
@ -242,18 +336,18 @@ var fileManager = (function($) {
fileManager.deleteFile = function() {
var fileIndex = localStorage["file.current"];
// Remove synchronized locations
var fileSyncIndexList = localStorage[fileIndex + ".sync"].split(";");
for ( var i = 1; i < fileSyncIndexList.length - 1; i++) {
var sync = fileSyncIndexList[i];
fileManager.removeSync(sync);
}
var fileSyncIndex = fileSyncIndexList[i];
fileManager.removeSync(fileSyncIndex);
}
localStorage.removeItem(fileIndex + ".sync");
localStorage.removeItem("file.current");
localStorage["file.list"] = localStorage["file.list"].replace(";"
+ fileIndex + ";", ";");
+ fileIndex + ";", ";");
localStorage.removeItem(fileIndex + ".title");
localStorage.removeItem(fileIndex + ".content");
};
@ -267,34 +361,8 @@ var fileManager = (function($) {
save = false;
}
};
// Remove a synchronization location associated to the file
fileManager.removeSync = function(sync) {
var fileIndexSync = localStorage["file.current"] + ".sync";
localStorage[fileIndexSync] = localStorage[fileIndexSync].replace(";"
+ sync + ";", ";");
localStorage.removeItem(sync + ".etag");
};
function uploadGdrive() {
$(".file-sync-indicator").removeClass("hide");
var fileIndex = localStorage["file.current"];
var content = localStorage[fileIndex + ".content"];
var title = localStorage[fileIndex + ".title"];
gdrive.createFile(title, content, function(fileSyncIndex) {
if (fileSyncIndex) {
localStorage[fileIndex + ".sync"] += fileSyncIndex + ";";
updateFileTitleUI();
showMessage('The file "' + title
+ '" will now be synchronized on Google Drive.');
} else {
showError("Error while creating file on Google Drive.");
}
});
}
function updateFileDescList() {
fileManager.updateFileTitles = function() {
fileDescList = [];
$("#file-selector").empty();
var fileIndexList = localStorage["file.list"].split(";");
@ -310,20 +378,24 @@ var fileManager = (function($) {
return 1;
return 0;
});
}
;
function updateFileTitleUI() {
// If no default file take first one
if (!localStorage["file.current"]) {
localStorage["file.current"] = fileDescList[0].index;
}
syncGoogleDrive = false;
function composeTitle(fileIndex) {
var result = localStorage[fileIndex + ".title"];
var sync = localStorage[fileIndex + ".sync"];
if (sync.indexOf(SYNC_PROVIDER_GDRIVE) !== -1) {
if (sync.indexOf(";" + SYNC_PROVIDER_GDRIVE) !== -1) {
syncGoogleDrive = true;
result = '<i class="icon-gdrive"></i> ' + result;
}
return result;
}
// Update the editor and the file title
// Update the the file title and the file selector
var fileIndex = localStorage["file.current"];
var title = localStorage[fileIndex + ".title"];
document.title = "StackEdit - " + title;
@ -348,8 +420,37 @@ var fileManager = (function($) {
}
$("#file-selector").append(li);
}
};
// Remove a synchronized location
fileManager.removeSync = function(fileSyncIndex) {
var fileIndexList = localStorage["file.list"].split(";");
// Look for local files associated to this synchronized location
for ( var i = 1; i < fileIndexList.length - 1; i++) {
var fileIndexSync = fileIndexList[i] + ".sync";
localStorage[fileIndexSync] = localStorage[fileIndexSync].replace(";"
+ fileSyncIndex + ";", ";");
}
// Remove etag
localStorage.removeItem(fileSyncIndex + ".etag");
};
function uploadGdrive() {
$(".file-sync-indicator").removeClass("hide");
var fileIndex = localStorage["file.current"];
var content = localStorage[fileIndex + ".content"];
var title = localStorage[fileIndex + ".title"];
gdrive.createFile(title, content, function(fileSyncIndex) {
if (fileSyncIndex) {
localStorage[fileIndex + ".sync"] += fileSyncIndex + ";";
fileManager.updateFileTitles();
showMessage('The file "' + title
+ '" will now be synchronized on Google Drive.');
} else {
showError("Error while creating file on Google Drive.");
}
});
}
;
function refreshManageSync() {
var fileIndex = localStorage["file.current"];
@ -362,23 +463,24 @@ var fileManager = (function($) {
$(".msg-no-sync").removeClass("hide");
}
for ( var i = 1; i < fileSyncIndexList.length - 1; i++) {
var sync = fileSyncIndexList[i];
(function(sync) {
var fileSyncIndex = fileSyncIndexList[i];
(function(fileSyncIndex) {
var line = $("<div>").addClass("input-append");
if (sync.indexOf(SYNC_PROVIDER_GDRIVE) === 0) {
if (fileSyncIndex.indexOf(SYNC_PROVIDER_GDRIVE) === 0) {
line.append($("<input>").prop("type", "text").prop(
"disabled", true).addClass("span5").val(
"Google Drive, FileID="
+ sync.substring(SYNC_PROVIDER_GDRIVE.length)));
+ fileSyncIndex.substring(SYNC_PROVIDER_GDRIVE.length)));
line.append($("<a>").addClass("btn").html(
'<i class="icon-trash"></i>').prop("title", "Remove this synchronized location").click(function() {
fileManager.removeSync(sync);
updateFileTitleUI();
'<i class="icon-trash"></i>').prop("title",
"Remove this synchronized location").click(function() {
fileManager.removeSync(fileSyncIndex);
fileManager.updateFileTitles();
refreshManageSync();
}));
}
$("#manage-sync-list").append(line);
})(sync);
})(fileSyncIndex);
}
}
@ -493,6 +595,7 @@ var core = (function($) {
$(function() {
$.jGrowl.defaults.life = 5000;
$.jGrowl.defaults.closer = false;
$.jGrowl.defaults.closeTemplate = '';
$.jGrowl.defaults.position = 'bottom-right';