New synchronize pattern
This commit is contained in:
parent
2177785ca5
commit
717eb5c3e9
@ -4,7 +4,6 @@ define(["jquery", "google-helper"], function($, googleHelper) {
|
|||||||
var core = undefined;
|
var core = undefined;
|
||||||
|
|
||||||
var bloggerProvider = {
|
var bloggerProvider = {
|
||||||
providerType: PROVIDER_TYPE_PUBLISH_FLAG,
|
|
||||||
providerId: PROVIDER_BLOGGER,
|
providerId: PROVIDER_BLOGGER,
|
||||||
providerName: "Blogger",
|
providerName: "Blogger",
|
||||||
defaultPublishFormat: "html"
|
defaultPublishFormat: "html"
|
||||||
|
@ -12,10 +12,6 @@ var ASYNC_TASK_DEFAULT_TIMEOUT = 30000;
|
|||||||
var ASYNC_TASK_LONG_TIMEOUT = 90000;
|
var ASYNC_TASK_LONG_TIMEOUT = 90000;
|
||||||
var SYNC_PERIOD = 180000;
|
var SYNC_PERIOD = 180000;
|
||||||
var USER_IDLE_THRESHOLD = 300000;
|
var USER_IDLE_THRESHOLD = 300000;
|
||||||
var SYNC_PROVIDER_GDRIVE = "sync.gdrive.";
|
|
||||||
var SYNC_PROVIDER_DROPBOX = "sync.dropbox.";
|
|
||||||
var PROVIDER_TYPE_SYNC_FLAG = 1;
|
|
||||||
var PROVIDER_TYPE_PUBLISH_FLAG = 2;
|
|
||||||
var PROVIDER_BLOGGER = "blogger";
|
var PROVIDER_BLOGGER = "blogger";
|
||||||
var PROVIDER_DROPBOX = "dropbox";
|
var PROVIDER_DROPBOX = "dropbox";
|
||||||
var PROVIDER_GDRIVE = "gdrive";
|
var PROVIDER_GDRIVE = "gdrive";
|
||||||
|
@ -177,7 +177,7 @@ define(
|
|||||||
|
|
||||||
// Setting management
|
// Setting management
|
||||||
core.settings = {
|
core.settings = {
|
||||||
converterType : "markdown-extra",
|
converterType : "markdown-extra-prettify",
|
||||||
layoutOrientation : "horizontal",
|
layoutOrientation : "horizontal",
|
||||||
editorFontSize : 14,
|
editorFontSize : 14,
|
||||||
commitMsg : "Published by StackEdit.",
|
commitMsg : "Published by StackEdit.",
|
||||||
@ -502,6 +502,12 @@ define(
|
|||||||
|
|
||||||
// from v1 to v2
|
// from v1 to v2
|
||||||
if(version == "v1") {
|
if(version == "v1") {
|
||||||
|
var gdriveLastChangeId = localStorage["sync.gdrive.lastChangeId"];
|
||||||
|
localStorage["gdrive.lastChangeId"] = gdriveLastChangeId;
|
||||||
|
localStorage.removeItem("sync.gdrive.lastChangeId");
|
||||||
|
var dropboxLastChangeId = localStorage["sync.dropbox.lastChangeId"];
|
||||||
|
localStorage["dropbox.lastChangeId"] = dropboxLastChangeId;
|
||||||
|
localStorage.removeItem("sync.dropbox.lastChangeId");
|
||||||
|
|
||||||
var SYNC_PROVIDER_GDRIVE = "sync." + PROVIDER_GDRIVE + ".";
|
var SYNC_PROVIDER_GDRIVE = "sync." + PROVIDER_GDRIVE + ".";
|
||||||
var SYNC_PROVIDER_DROPBOX = "sync." + PROVIDER_DROPBOX + ".";
|
var SYNC_PROVIDER_DROPBOX = "sync." + PROVIDER_DROPBOX + ".";
|
||||||
|
@ -108,7 +108,7 @@ define(["jquery", "async-runner"], function($, asyncRunner) {
|
|||||||
asyncRunner.addTask(task);
|
asyncRunner.addTask(task);
|
||||||
};
|
};
|
||||||
|
|
||||||
dropboxHelper.checkUpdates = function(lastChangeId, callback) {
|
dropboxHelper.checkChanges = function(lastChangeId, callback) {
|
||||||
callback = callback || core.doNothing;
|
callback = callback || core.doNothing;
|
||||||
var changes = [];
|
var changes = [];
|
||||||
var newChangeId = lastChangeId || 0;
|
var newChangeId = lastChangeId || 0;
|
||||||
@ -125,14 +125,7 @@ define(["jquery", "async-runner"], function($, asyncRunner) {
|
|||||||
// Retrieve success
|
// Retrieve success
|
||||||
newChangeId = pullChanges.cursor();
|
newChangeId = pullChanges.cursor();
|
||||||
if(pullChanges.changes !== undefined) {
|
if(pullChanges.changes !== undefined) {
|
||||||
for(var i=0; i<pullChanges.changes.length; i++) {
|
changes = changes.concat(pullChanges.changes);
|
||||||
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) {
|
if (pullChanges.shouldPullAgain) {
|
||||||
task.chain(retrievePageOfChanges);
|
task.chain(retrievePageOfChanges);
|
||||||
|
@ -5,10 +5,10 @@ define(["jquery", "dropbox-helper"], function($, dropboxHelper) {
|
|||||||
var fileManager = undefined;
|
var fileManager = undefined;
|
||||||
|
|
||||||
var dropboxProvider = {
|
var dropboxProvider = {
|
||||||
providerType: PROVIDER_TYPE_SYNC_FLAG | PROVIDER_TYPE_PUBLISH_FLAG,
|
|
||||||
providerId: PROVIDER_DROPBOX,
|
providerId: PROVIDER_DROPBOX,
|
||||||
providerName: "Dropbox",
|
providerName: "Dropbox",
|
||||||
defaultPublishFormat: "template"
|
defaultPublishFormat: "template",
|
||||||
|
useSync: false
|
||||||
};
|
};
|
||||||
|
|
||||||
function checkPath(path) {
|
function checkPath(path) {
|
||||||
@ -110,6 +110,113 @@ define(["jquery", "dropbox-helper"], function($, dropboxHelper) {
|
|||||||
exportFileToPath(path);
|
exportFileToPath(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dropboxProvider.syncUp = function(uploadContent, uploadContentCRC, uploadTitle, uploadTitleCRC, syncAttributes, callback) {
|
||||||
|
var syncContentCRC = syncAttributes.contentCRC;
|
||||||
|
// Skip if CRC has not changed
|
||||||
|
if(uploadContentCRC == syncContentCRC) {
|
||||||
|
callback(undefined, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dropboxHelper.upload(syncAttributes.path, uploadContent, function(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
syncAttributes.version = result.versionTag;
|
||||||
|
syncAttributes.contentCRC = uploadContentCRC;
|
||||||
|
callback(undefined, true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function syncDown(callback) {
|
||||||
|
if (dropboxProvider.useSync === false) {
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var lastChangeId = parseInt(localStorage[PROVIDER_DROPBOX + ".lastChangeId"]);
|
||||||
|
dropboxHelper.checkChanges(lastChangeId, function(error, changes, newChangeId) {
|
||||||
|
if (error) {
|
||||||
|
callback(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var interestingChanges = [];
|
||||||
|
_.each(changes, function(change) {
|
||||||
|
var syncIndex = "sync." + PROVIDER_DROPBOX + "." + encodeURIComponent(file.path.toLowerCase());
|
||||||
|
var serializedAttributes = localStorage[syncIndex];
|
||||||
|
if(serializedAttributes === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Store syncIndex to avoid 2 times formating
|
||||||
|
change.syncIndex = syncIndex;
|
||||||
|
// Delete
|
||||||
|
if(change.wasRemoved === true) {
|
||||||
|
interestingChanges.push(change);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Modify
|
||||||
|
var syncAttributes = JSON.parse(serializedAttributes);
|
||||||
|
if(syncAttributes.version != change.stat.versionTag) {
|
||||||
|
interestingChanges.push(change);
|
||||||
|
// Store syncAttributes to avoid 2 times parsing
|
||||||
|
change.syncAttributes = syncAttributes;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dropboxHelper.downloadContent(changes, function(error, changes) {
|
||||||
|
if (error) {
|
||||||
|
callback(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var updateFileTitles = false;
|
||||||
|
_.each(changes, function(change) {
|
||||||
|
var syncIndex = change.syncIndex;
|
||||||
|
var fileIndex = fileManager.getFileIndexFromSync(syncIndex);
|
||||||
|
// No file corresponding (file may have been deleted locally)
|
||||||
|
if(fileIndex === undefined) {
|
||||||
|
fileManager.removeSync(syncIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var localTitle = localStorage[fileIndex + ".title"];
|
||||||
|
// File deleted
|
||||||
|
if (change.wasRemoved === true) {
|
||||||
|
fileManager.removeSync(syncIndex);
|
||||||
|
updateFileTitles = true;
|
||||||
|
core.showMessage('"' + localTitle + '" has been removed from Dropbox.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var syncAttributes = change.syncAttributes;
|
||||||
|
var localContent = localStorage[fileIndex + ".content"];
|
||||||
|
var localContentChanged = syncAttributes.contentCRC != core.crc32(localContent);
|
||||||
|
var file = change.stat;
|
||||||
|
var fileContentChanged = localContent != file.content;
|
||||||
|
// Conflict detection
|
||||||
|
if (fileContentChanged === true && localContentChanged === true) {
|
||||||
|
fileManager.createFile(localTitle + " (backup)", localContent);
|
||||||
|
updateFileTitles = true;
|
||||||
|
core.showMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.');
|
||||||
|
}
|
||||||
|
// If file content changed
|
||||||
|
if(fileContentChanged) {
|
||||||
|
localStorage[fileIndex + ".content"] = file.content;
|
||||||
|
core.showMessage('"' + localTitle + '" has been updated from Dropbox.');
|
||||||
|
if(fileManager.isCurrentFileIndex(fileIndex)) {
|
||||||
|
updateFileTitles = false; // Done by next function
|
||||||
|
fileManager.selectFile(); // Refresh editor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update syncAttributes
|
||||||
|
syncAttributes.version = file.versionTag;
|
||||||
|
syncAttributes.contentCRC = core.crc32(file.content);
|
||||||
|
localStorage[syncIndex] = JSON.stringify(syncAttributes);
|
||||||
|
});
|
||||||
|
if(updateFileTitles) {
|
||||||
|
fileManager.updateFileTitles();
|
||||||
|
}
|
||||||
|
localStorage[PROVIDER_DROPBOX + ".lastChangeId"] = newChangeId;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
dropboxProvider.publish = function(publishAttributes, title, content, callback) {
|
dropboxProvider.publish = function(publishAttributes, title, content, callback) {
|
||||||
var path = checkPath(publishAttributes.path);
|
var path = checkPath(publishAttributes.path);
|
||||||
if(path === undefined) {
|
if(path === undefined) {
|
||||||
|
@ -136,19 +136,13 @@ define(["jquery", "google-helper", "dropbox-helper", "github-helper", "synchroni
|
|||||||
fileManager.setCurrentFileIndex(fileIndex);
|
fileManager.setCurrentFileIndex(fileIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
var useGoogleDrive = false;
|
synchronizer.resetSyncFlags();
|
||||||
var useDropbox = false;
|
|
||||||
function composeTitle(fileIndex) {
|
function composeTitle(fileIndex) {
|
||||||
var result = " " + localStorage[fileIndex + ".title"];
|
var result = " " + localStorage[fileIndex + ".title"];
|
||||||
var sync = localStorage[fileIndex + ".sync"];
|
var providerIdList = synchronizer.getSyncProvidersFromFile(fileIndex);
|
||||||
if (sync.indexOf(";" + SYNC_PROVIDER_DROPBOX) !== -1) {
|
_.each(providerIdList, function(providerId) {
|
||||||
useDropbox = true;
|
result = '<i class="icon-' + providerId '"></i>' + result;
|
||||||
result = '<i class="icon-dropbox"></i>' + result;
|
});
|
||||||
}
|
|
||||||
if (sync.indexOf(";" + SYNC_PROVIDER_GDRIVE) !== -1) {
|
|
||||||
useGoogleDrive = true;
|
|
||||||
result = '<i class="icon-gdrive"></i>' + result;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,8 +169,6 @@ define(["jquery", "google-helper", "dropbox-helper", "github-helper", "synchroni
|
|||||||
}
|
}
|
||||||
$("#file-selector").append(li);
|
$("#file-selector").append(li);
|
||||||
});
|
});
|
||||||
synchronizer.useGoogleDrive = useGoogleDrive;
|
|
||||||
synchronizer.useDropbox = useDropbox;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove a syncIndex (synchronized location)
|
// Remove a syncIndex (synchronized location)
|
||||||
|
@ -5,10 +5,10 @@ define(["jquery", "google-helper", "underscore"], function($, googleHelper) {
|
|||||||
var fileManager = undefined;
|
var fileManager = undefined;
|
||||||
|
|
||||||
var gdriveProvider = {
|
var gdriveProvider = {
|
||||||
providerType: PROVIDER_TYPE_SYNC_FLAG | PROVIDER_TYPE_PUBLISH_FLAG,
|
|
||||||
providerId: PROVIDER_GDRIVE,
|
providerId: PROVIDER_GDRIVE,
|
||||||
providerName: "Gdrive",
|
providerName: "Gdrive",
|
||||||
defaultPublishFormat: "template"
|
defaultPublishFormat: "template",
|
||||||
|
useSync: false
|
||||||
};
|
};
|
||||||
|
|
||||||
function createSyncAttributes(id, etag, content, title) {
|
function createSyncAttributes(id, etag, content, title) {
|
||||||
@ -63,7 +63,7 @@ define(["jquery", "google-helper", "underscore"], function($, googleHelper) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
gdriveProvider.exportFile = function(event, title, content, callback) {
|
gdriveProvider.exportFile = function(event, title, content, callback) {
|
||||||
googleHelper.upload(undefined, undefined, title, content, function(error, result) {
|
googleHelper.upload(undefined, undefined, title, content, undefined, function(error, result) {
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
return;
|
return;
|
||||||
@ -87,7 +87,7 @@ define(["jquery", "google-helper", "underscore"], function($, googleHelper) {
|
|||||||
callback(true);
|
callback(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
googleHelper.upload(id, undefined, title, content, function(error, result) {
|
googleHelper.upload(id, undefined, title, content, undefined, function(error, result) {
|
||||||
if (error) {
|
if (error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
return;
|
return;
|
||||||
@ -97,8 +97,127 @@ define(["jquery", "google-helper", "underscore"], function($, googleHelper) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
gdriveProvider.syncUp = function(uploadContent, uploadContentCRC, uploadTitle, uploadTitleCRC, syncAttributes, callback) {
|
||||||
|
var syncContentCRC = syncAttributes.contentCRC;
|
||||||
|
var syncTitleCRC = syncAttributes.titleCRC;
|
||||||
|
// Skip if CRC has not changed
|
||||||
|
if(uploadContentCRC == syncContentCRC && uploadTitleCRC == syncTitleCRC) {
|
||||||
|
callback(undefined, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
googleHelper.upload(syncAttributes.id, undefined, uploadTitle, uploadContent, syncAttributes.etag, function(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
syncAttributes.etag = result.etag;
|
||||||
|
syncAttributes.contentCRC = uploadContentCRC;
|
||||||
|
syncAttributes.titleCRC = uploadTitleCRC;
|
||||||
|
callback(undefined, true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function syncDown(callback) {
|
||||||
|
if (gdriveProvider.useSync === false) {
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var lastChangeId = parseInt(localStorage[PROVIDER_GDRIVE + ".lastChangeId"]);
|
||||||
|
googleHelper.checkChanges(lastChangeId, function(error, changes, newChangeId) {
|
||||||
|
if (error) {
|
||||||
|
callback(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var interestingChanges = [];
|
||||||
|
_.each(changes, function(change) {
|
||||||
|
var syncIndex = "sync." + PROVIDER_GDRIVE + "." + file.id;
|
||||||
|
var serializedAttributes = localStorage[syncIndex];
|
||||||
|
if(serializedAttributes === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Store syncIndex to avoid 2 times formating
|
||||||
|
change.syncIndex = syncIndex;
|
||||||
|
// Delete
|
||||||
|
if(change.deleted === true) {
|
||||||
|
interestingChanges.push(change);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Modify
|
||||||
|
var syncAttributes = JSON.parse(serializedAttributes);
|
||||||
|
if(syncAttributes.etag != change.file.etag) {
|
||||||
|
interestingChanges.push(change);
|
||||||
|
// Store syncAttributes to avoid 2 times parsing
|
||||||
|
change.syncAttributes = syncAttributes;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
googleHelper.downloadContent(changes, function(error, changes) {
|
||||||
|
if (error) {
|
||||||
|
callback(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var updateFileTitles = false;
|
||||||
|
_.each(changes, function(change) {
|
||||||
|
var syncIndex = change.syncIndex;
|
||||||
|
var fileIndex = fileManager.getFileIndexFromSync(syncIndex);
|
||||||
|
// No file corresponding (file may have been deleted locally)
|
||||||
|
if(fileIndex === undefined) {
|
||||||
|
fileManager.removeSync(syncIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var localTitle = localStorage[fileIndex + ".title"];
|
||||||
|
// File deleted
|
||||||
|
if (change.deleted === true) {
|
||||||
|
fileManager.removeSync(syncIndex);
|
||||||
|
updateFileTitles = true;
|
||||||
|
core.showMessage('"' + localTitle + '" has been removed from Google Drive.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var syncAttributes = change.syncAttributes;
|
||||||
|
var localTitleChanged = syncAttributes.titleCRC != core.crc32(localTitle);
|
||||||
|
var localContent = localStorage[fileIndex + ".content"];
|
||||||
|
var localContentChanged = syncAttributes.contentCRC != core.crc32(localContent);
|
||||||
|
var file = change.file;
|
||||||
|
var fileTitleChanged = localTitle != file.title;
|
||||||
|
var fileContentChanged = localContent != file.content;
|
||||||
|
// Conflict detection
|
||||||
|
if ((fileTitleChanged === true && localTitleChanged === true)
|
||||||
|
|| (fileContentChanged === true && localContentChanged === true)) {
|
||||||
|
fileManager.createFile(localTitle + " (backup)", localContent);
|
||||||
|
updateFileTitles = true;
|
||||||
|
core.showMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.');
|
||||||
|
}
|
||||||
|
// If file title changed
|
||||||
|
if(fileTitleChanged) {
|
||||||
|
localStorage[fileIndex + ".title"] = file.title;
|
||||||
|
updateFileTitles = true;
|
||||||
|
core.showMessage('"' + localTitle + '" has been renamed to "' + file.title + '" on Google Drive.');
|
||||||
|
}
|
||||||
|
// If file content changed
|
||||||
|
if(fileContentChanged) {
|
||||||
|
localStorage[fileIndex + ".content"] = file.content;
|
||||||
|
core.showMessage('"' + file.title + '" has been updated from Google Drive.');
|
||||||
|
if(fileManager.isCurrentFileIndex(fileIndex)) {
|
||||||
|
updateFileTitles = false; // Done by next function
|
||||||
|
fileManager.selectFile(); // Refresh editor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update syncAttributes
|
||||||
|
syncAttributes.etag = file.etag;
|
||||||
|
syncAttributes.contentCRC = core.crc32(file.content);
|
||||||
|
syncAttributes.titleCRC = core.crc32(file.title);
|
||||||
|
localStorage[syncIndex] = JSON.stringify(syncAttributes);
|
||||||
|
});
|
||||||
|
if(updateFileTitles) {
|
||||||
|
fileManager.updateFileTitles();
|
||||||
|
}
|
||||||
|
localStorage[PROVIDER_GDRIVE + ".lastChangeId"] = newChangeId;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
gdriveProvider.publish = function(publishAttributes, title, content, callback) {
|
gdriveProvider.publish = function(publishAttributes, title, content, callback) {
|
||||||
googleHelper.upload(publishAttributes.fileId, undefined, title, content, callback);
|
googleHelper.upload(publishAttributes.fileId, undefined, title, content, undefined, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
gdriveProvider.newPublishAttributes = function(event) {
|
gdriveProvider.newPublishAttributes = function(event) {
|
||||||
@ -122,7 +241,7 @@ define(["jquery", "google-helper", "underscore"], function($, googleHelper) {
|
|||||||
state = JSON.parse(state);
|
state = JSON.parse(state);
|
||||||
if (state.action == "create") {
|
if (state.action == "create") {
|
||||||
googleHelper.upload(undefined, state.folderId, GDRIVE_DEFAULT_FILE_TITLE,
|
googleHelper.upload(undefined, state.folderId, GDRIVE_DEFAULT_FILE_TITLE,
|
||||||
"", function(error, file) {
|
"", undefined, function(error, file) {
|
||||||
if(error) {
|
if(error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ define(["jquery", "github-helper"], function($, githubHelper) {
|
|||||||
var core = undefined;
|
var core = undefined;
|
||||||
|
|
||||||
var githubProvider = {
|
var githubProvider = {
|
||||||
providerType: PROVIDER_TYPE_PUBLISH_FLAG,
|
|
||||||
providerId: PROVIDER_GITHUB,
|
providerId: PROVIDER_GITHUB,
|
||||||
providerName: "GitHub"
|
providerName: "GitHub"
|
||||||
};
|
};
|
||||||
|
@ -76,7 +76,7 @@ define(["jquery", "async-runner"], function($, asyncRunner) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
googleHelper.upload = function(fileId, parentId, title, content, callback) {
|
googleHelper.upload = function(fileId, parentId, title, content, etag, callback) {
|
||||||
callback = callback || core.doNothing;
|
callback = callback || core.doNothing;
|
||||||
var result = undefined;
|
var result = undefined;
|
||||||
var task = asyncRunner.createTask();
|
var task = asyncRunner.createTask();
|
||||||
@ -95,13 +95,10 @@ define(["jquery", "async-runner"], function($, asyncRunner) {
|
|||||||
}
|
}
|
||||||
var path = '/upload/drive/v2/files';
|
var path = '/upload/drive/v2/files';
|
||||||
var method = 'POST';
|
var method = 'POST';
|
||||||
var etag = undefined;
|
|
||||||
if (fileId !== undefined) {
|
if (fileId !== undefined) {
|
||||||
// If it's an update
|
// If it's an update
|
||||||
path += "/" + fileId;
|
path += "/" + fileId;
|
||||||
method = 'PUT';
|
method = 'PUT';
|
||||||
etag = localStorage[SYNC_PROVIDER_GDRIVE
|
|
||||||
+ fileId + ".etag"];
|
|
||||||
}
|
}
|
||||||
var headers = { 'Content-Type' : 'multipart/mixed; boundary="'
|
var headers = { 'Content-Type' : 'multipart/mixed; boundary="'
|
||||||
+ boundary + '"', };
|
+ boundary + '"', };
|
||||||
@ -155,7 +152,7 @@ define(["jquery", "async-runner"], function($, asyncRunner) {
|
|||||||
asyncRunner.addTask(task);
|
asyncRunner.addTask(task);
|
||||||
};
|
};
|
||||||
|
|
||||||
googleHelper.checkUpdates = function(lastChangeId, callback) {
|
googleHelper.checkChanges = function(lastChangeId, callback) {
|
||||||
callback = callback || core.doNothing;
|
callback = callback || core.doNothing;
|
||||||
var changes = [];
|
var changes = [];
|
||||||
var newChangeId = lastChangeId || 0;
|
var newChangeId = lastChangeId || 0;
|
||||||
@ -185,15 +182,7 @@ define(["jquery", "async-runner"], function($, asyncRunner) {
|
|||||||
newChangeId = response.largestChangeId;
|
newChangeId = response.largestChangeId;
|
||||||
nextPageToken = response.nextPageToken;
|
nextPageToken = response.nextPageToken;
|
||||||
if (response.items !== undefined) {
|
if (response.items !== undefined) {
|
||||||
for ( var i = 0; i < response.items.length; i++) {
|
changes = changes.concat(response.items);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (nextPageToken !== undefined) {
|
if (nextPageToken !== undefined) {
|
||||||
task.chain(retrievePageOfChanges);
|
task.chain(retrievePageOfChanges);
|
||||||
|
@ -9,7 +9,7 @@ define(["jquery", "github-provider", "blogger-provider", "dropbox-provider", "gd
|
|||||||
// Create a map with providerName: providerObject
|
// Create a map with providerName: providerObject
|
||||||
var providerMap = _.chain(arguments)
|
var providerMap = _.chain(arguments)
|
||||||
.map(function(argument) {
|
.map(function(argument) {
|
||||||
return argument && argument.providerType & PROVIDER_TYPE_PUBLISH_FLAG && [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
|
// Used to know if the current file has publications
|
||||||
|
@ -8,7 +8,7 @@ define(["jquery", "google-helper", "dropbox-helper", "dropbox-provider", "gdrive
|
|||||||
// Create a map with providerName: providerObject
|
// Create a map with providerName: providerObject
|
||||||
var providerMap = _.chain(arguments)
|
var providerMap = _.chain(arguments)
|
||||||
.map(function(argument) {
|
.map(function(argument) {
|
||||||
return argument && argument.providerType & PROVIDER_TYPE_SYNC_FLAG && [argument.providerId, argument];
|
return argument && argument.providerId && [argument.providerId, argument];
|
||||||
}).compact().object().value();
|
}).compact().object().value();
|
||||||
|
|
||||||
// Used to know the providers we are connected to
|
// Used to know the providers we are connected to
|
||||||
@ -59,51 +59,32 @@ define(["jquery", "google-helper", "dropbox-helper", "dropbox-provider", "gdrive
|
|||||||
|
|
||||||
// Dequeue a synchronized location
|
// Dequeue a synchronized location
|
||||||
var syncIndex = uploadFileSyncIndexList.pop();
|
var syncIndex = uploadFileSyncIndexList.pop();
|
||||||
var syncAttributes = JSON.parse(localStorage[fileSyncIndex]);
|
var syncAttributes = JSON.parse(localStorage[syncIndex]);
|
||||||
=
|
// Use the specified provider to perform the upload
|
||||||
var syncContentCRC = localStorage[fileSyncIndex + ".contentCRC"];
|
providerMap[syncAttributes.provider].syncUp(
|
||||||
var syncTitleCRC = localStorage[fileSyncIndex + ".titleCRC"];
|
uploadContent,
|
||||||
// Skip if CRC has not changed
|
uploadContentCRC,
|
||||||
if(uploadContentCRC == syncContentCRC && (syncTitleCRC === undefined || uploadTitleCRC == syncTitleCRC)) {
|
uploadTitle,
|
||||||
locationUp(callback);
|
uploadTitleCRC,
|
||||||
return;
|
syncAttributes,
|
||||||
}
|
function(error, uploadFlag) {
|
||||||
|
if(uploadFlag === true) {
|
||||||
// If upload is going to run, go for an other upload cycle at the end
|
// 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
|
// When page is refreshed, this flag is false but should be true
|
||||||
uploadPending = true;
|
uploadPending = true;
|
||||||
|
}
|
||||||
// Try to find the provider
|
|
||||||
if (fileSyncIndex.indexOf(SYNC_PROVIDER_GDRIVE) === 0) {
|
|
||||||
var id = fileSyncIndex.substring(SYNC_PROVIDER_GDRIVE.length);
|
|
||||||
googleHelper.upload(id, undefined, uploadTitle, uploadContent, function(error, result) {
|
|
||||||
if(error) {
|
if(error) {
|
||||||
// If error we abort the synchronization (retry later)
|
|
||||||
callback(error);
|
callback(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
localStorage[fileSyncIndex + ".contentCRC"] = uploadContentCRC;
|
if(uploadFlag) {
|
||||||
localStorage[fileSyncIndex + ".titleCRC"] = uploadTitleCRC;
|
// Update syncAttributes in localStorage
|
||||||
locationUp(callback);
|
localStorage[syncIndex] = JSON.stringify(syncAttributes);
|
||||||
});
|
|
||||||
} else if (fileSyncIndex.indexOf(SYNC_PROVIDER_DROPBOX) === 0) {
|
|
||||||
var path = fileSyncIndex.substring(SYNC_PROVIDER_DROPBOX.length);
|
|
||||||
path = decodeURIComponent(path);
|
|
||||||
dropboxHelper.upload(path, uploadContent, function(error, result) {
|
|
||||||
if (error) {
|
|
||||||
// If error we abort the synchronization (retry later)
|
|
||||||
callback(error);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
localStorage[fileSyncIndex + ".contentCRC"] = uploadContentCRC;
|
|
||||||
locationUp(callback);
|
locationUp(callback);
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// This should never happen
|
|
||||||
console.error("Invalid fileSyncIndex: " + fileSyncIndex);
|
|
||||||
callback("error");
|
|
||||||
}
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursive function to upload multiple files
|
// Recursive function to upload multiple files
|
||||||
@ -119,7 +100,7 @@ define(["jquery", "google-helper", "dropbox-helper", "dropbox-provider", "gdrive
|
|||||||
// Dequeue a fileIndex
|
// Dequeue a fileIndex
|
||||||
var fileIndex = uploadFileIndexList.pop();
|
var fileIndex = uploadFileIndexList.pop();
|
||||||
var fileSyncIndexes = localStorage[fileIndex + ".sync"];
|
var fileSyncIndexes = localStorage[fileIndex + ".sync"];
|
||||||
if(!fileIndex || fileSyncIndexes.length === 1) {
|
if(fileSyncIndexes.length === 1) {
|
||||||
fileUp(callback);
|
fileUp(callback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -141,7 +122,7 @@ define(["jquery", "google-helper", "dropbox-helper", "dropbox-provider", "gdrive
|
|||||||
if(uploadCycle === true) {
|
if(uploadCycle === true) {
|
||||||
// New upload cycle
|
// New upload cycle
|
||||||
uploadCycle = false;
|
uploadCycle = false;
|
||||||
uploadFileIndexList = localStorage["file.list"].split(";");
|
uploadFileIndexList = _.compact(localStorage["file.list"].split(";"));
|
||||||
fileUp(callback);
|
fileUp(callback);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -149,157 +130,25 @@ define(["jquery", "google-helper", "dropbox-helper", "dropbox-provider", "gdrive
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to download file changes from Google Drive
|
// Recursive function to download changes from multiple providers
|
||||||
function syncDownGdrive(callback) {
|
var providerList = [];
|
||||||
if (synchronizer.useGoogleDrive === false) {
|
function providerDown(callback) {
|
||||||
|
if(providerList.length === 0) {
|
||||||
callback();
|
callback();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
var lastChangeId = parseInt(localStorage[SYNC_PROVIDER_GDRIVE
|
var provider = providerList.pop();
|
||||||
+ "lastChangeId"]);
|
provider.syncDown(function(error) {
|
||||||
googleHelper.checkUpdates(lastChangeId, function(error, changes, newChangeId) {
|
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
googleHelper.downloadContent(changes, function(error, changes) {
|
providerDown(callback);
|
||||||
if (error) {
|
|
||||||
callback(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var updateFileTitles = false;
|
|
||||||
for ( var i = 0; i < changes.length; i++) {
|
|
||||||
var change = changes[i];
|
|
||||||
var fileSyncIndex = SYNC_PROVIDER_GDRIVE + change.fileId;
|
|
||||||
var fileIndex = fileManager.getFileIndexFromSync(fileSyncIndex);
|
|
||||||
// No file corresponding (file may have been deleted locally)
|
|
||||||
if(fileIndex === undefined) {
|
|
||||||
fileManager.removeSync(fileSyncIndex);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var localTitle = localStorage[fileIndex + ".title"];
|
|
||||||
// File deleted
|
|
||||||
if (change.deleted === true) {
|
|
||||||
fileManager.removeSync(fileSyncIndex);
|
|
||||||
updateFileTitles = true;
|
|
||||||
core.showMessage('"' + localTitle + '" has been removed from Google Drive.');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var localTitleChanged = localStorage[fileSyncIndex + ".titleCRC"] != core.crc32(localTitle);
|
|
||||||
var localContent = localStorage[fileIndex + ".content"];
|
|
||||||
var localContentChanged = localStorage[fileSyncIndex + ".contentCRC"] != core.crc32(localContent);
|
|
||||||
var file = change.file;
|
|
||||||
var fileTitleChanged = localTitle != file.title;
|
|
||||||
var fileContentChanged = localContent != file.content;
|
|
||||||
// Conflict detection
|
|
||||||
if ((fileTitleChanged === true && localTitleChanged === true)
|
|
||||||
|| (fileContentChanged === true && localContentChanged === true)) {
|
|
||||||
fileManager.createFile(localTitle + " (backup)", localContent);
|
|
||||||
updateFileTitles = true;
|
|
||||||
core.showMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.');
|
|
||||||
}
|
|
||||||
// If file title changed
|
|
||||||
if(fileTitleChanged) {
|
|
||||||
localStorage[fileIndex + ".title"] = file.title;
|
|
||||||
updateFileTitles = true;
|
|
||||||
core.showMessage('"' + localTitle + '" has been renamed to "' + file.title + '" on Google Drive.');
|
|
||||||
}
|
|
||||||
// If file content changed
|
|
||||||
if(fileContentChanged) {
|
|
||||||
localStorage[fileIndex + ".content"] = file.content;
|
|
||||||
core.showMessage('"' + file.title + '" has been updated from Google Drive.');
|
|
||||||
if(fileManager.isCurrentFileIndex(fileIndex)) {
|
|
||||||
updateFileTitles = false; // Done by next function
|
|
||||||
fileManager.selectFile(); // Refresh editor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update file etag and CRCs
|
|
||||||
localStorage[fileSyncIndex + ".etag"] = file.etag;
|
|
||||||
localStorage[fileSyncIndex + ".contentCRC"] = core.crc32(file.content);
|
|
||||||
localStorage[fileSyncIndex + ".titleCRC"] = core.crc32(file.title);
|
|
||||||
}
|
|
||||||
if(updateFileTitles) {
|
|
||||||
fileManager.updateFileTitles();
|
|
||||||
}
|
|
||||||
localStorage[SYNC_PROVIDER_GDRIVE
|
|
||||||
+ "lastChangeId"] = newChangeId;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to download file changes from Dropbox
|
|
||||||
function syncDownDropbox(callback) {
|
|
||||||
if (synchronizer.useDropbox === false) {
|
|
||||||
callback();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var lastChangeId = localStorage[SYNC_PROVIDER_DROPBOX + "lastChangeId"];
|
|
||||||
dropboxHelper.checkUpdates(lastChangeId, function(error, changes, newChangeId) {
|
|
||||||
if (error) {
|
|
||||||
callback(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dropboxHelper.downloadContent(changes, function(error, changes) {
|
|
||||||
if (error) {
|
|
||||||
callback(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var updateFileTitles = false;
|
|
||||||
for ( var i = 0; i < changes.length; i++) {
|
|
||||||
var change = changes[i];
|
|
||||||
var fileSyncIndex = SYNC_PROVIDER_DROPBOX + encodeURIComponent(change.path.toLowerCase());
|
|
||||||
var fileIndex = fileManager.getFileIndexFromSync(fileSyncIndex);
|
|
||||||
// No file corresponding (file may have been deleted locally)
|
|
||||||
if(fileIndex === undefined) {
|
|
||||||
fileManager.removeSync(fileSyncIndex);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var localTitle = localStorage[fileIndex + ".title"];
|
|
||||||
// File deleted
|
|
||||||
if (change.wasRemoved === true) {
|
|
||||||
fileManager.removeSync(fileSyncIndex);
|
|
||||||
updateFileTitles = true;
|
|
||||||
core.showMessage('"' + localTitle + '" has been removed from Dropbox.');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var localContent = localStorage[fileIndex + ".content"];
|
|
||||||
var localContentChanged = localStorage[fileSyncIndex + ".contentCRC"] != core.crc32(localContent);
|
|
||||||
var file = change.stat;
|
|
||||||
var fileContentChanged = localContent != file.content;
|
|
||||||
// Conflict detection
|
|
||||||
if (fileContentChanged === true && localContentChanged === true) {
|
|
||||||
fileManager.createFile(localTitle + " (backup)", localContent);
|
|
||||||
updateFileTitles = true;
|
|
||||||
core.showMessage('Conflict detected on "' + localTitle + '". A backup has been created locally.');
|
|
||||||
}
|
|
||||||
// If file content changed
|
|
||||||
if(fileContentChanged) {
|
|
||||||
localStorage[fileIndex + ".content"] = file.content;
|
|
||||||
core.showMessage('"' + localTitle + '" has been updated from Dropbox.');
|
|
||||||
if(fileManager.isCurrentFileIndex(fileIndex)) {
|
|
||||||
updateFileTitles = false; // Done by next function
|
|
||||||
fileManager.selectFile(); // Refresh editor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update file version and CRC
|
|
||||||
localStorage[fileSyncIndex + ".version"] = file.versionTag;
|
|
||||||
localStorage[fileSyncIndex + ".contentCRC"] = core.crc32(file.content);
|
|
||||||
}
|
|
||||||
if(updateFileTitles) {
|
|
||||||
fileManager.updateFileTitles();
|
|
||||||
}
|
|
||||||
localStorage[SYNC_PROVIDER_DROPBOX
|
|
||||||
+ "lastChangeId"] = newChangeId;
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncDown(callback) {
|
function syncDown(callback) {
|
||||||
syncDownGdrive(function() {
|
providerList = _.values(providerMap);
|
||||||
syncDownDropbox(callback);
|
providerDown(callback);
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var syncRunning = false;
|
var syncRunning = false;
|
||||||
@ -316,6 +165,7 @@ define(["jquery", "google-helper", "dropbox-helper", "dropbox-provider", "gdrive
|
|||||||
|
|
||||||
function isError(error) {
|
function isError(error) {
|
||||||
if(error !== undefined) {
|
if(error !== undefined) {
|
||||||
|
console.error(error);
|
||||||
syncRunning = false;
|
syncRunning = false;
|
||||||
synchronizer.updateSyncButton();
|
synchronizer.updateSyncButton();
|
||||||
return true;
|
return true;
|
||||||
@ -369,6 +219,24 @@ define(["jquery", "google-helper", "dropbox-helper", "dropbox-provider", "gdrive
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
synchronizer.resetSyncFlags = function() {
|
||||||
|
_.each(providerMap, function(provider) {
|
||||||
|
provider.useSync = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
synchronizer.getSyncProvidersFromFile = function(fileIndex) {
|
||||||
|
var sync = localStorage[fileIndex + ".sync"];
|
||||||
|
var providerIdList = [];
|
||||||
|
_.each(providerMap, function(provider) {
|
||||||
|
if (sync.indexOf(";sync." + provider.providerId + ".") !== -1) {
|
||||||
|
provider.useSync = true;
|
||||||
|
providerIdList.push(provider.providerId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return providerIdList;
|
||||||
|
};
|
||||||
|
|
||||||
synchronizer.init = function(coreModule, fileManagerModule) {
|
synchronizer.init = function(coreModule, fileManagerModule) {
|
||||||
core = coreModule;
|
core = coreModule;
|
||||||
fileManager = fileManagerModule;
|
fileManager = fileManagerModule;
|
||||||
|
Loading…
Reference in New Issue
Block a user