From 194b018cd252f5e2519e271c715a88ec39c4ac80 Mon Sep 17 00:00:00 2001 From: benweet Date: Thu, 18 Jul 2013 01:07:22 +0100 Subject: [PATCH] Integration of Google Drive Realtime API --- js/core.js | 5 +++++ js/extensionMgr.js | 10 ++++++++-- js/fileMgr.js | 5 +++-- js/helpers/googleHelper.js | 30 ++++++++++++++++++++++++++++++ js/providers/gdriveProvider.js | 27 +++++++++++++++++++++++++++ js/synchronizer.js | 19 +++++++++++++++++++ 6 files changed, 92 insertions(+), 4 deletions(-) diff --git a/js/core.js b/js/core.js index 474dc332..3da0423a 100644 --- a/js/core.js +++ b/js/core.js @@ -214,6 +214,9 @@ define([ var documentContent = undefined; var undoManager = undefined; core.initEditor = function(fileDescParam) { + if(fileDesc !== undefined) { + extensionMgr.onFileClosed(fileDesc); + } fileDesc = fileDescParam; documentContent = undefined; var initDocumentContent = fileDesc.content; @@ -223,6 +226,7 @@ define([ // If the editor is already created undoManager.reinit(initDocumentContent, fileDesc.editorStart, fileDesc.editorEnd, fileDesc.editorScrollTop); editor.refreshPreview(); + extensionMgr.onFileOpen(fileDesc); return; } var previewContainerElt = $(".preview-container"); @@ -308,6 +312,7 @@ define([ editor.hooks.chain("onPreviewRefresh", extensionMgr.onAsyncPreview); undoManager = editor.run(previewWrapper); undoManager.reinit(initDocumentContent, fileDesc.editorStart, fileDesc.editorEnd, fileDesc.editorScrollTop); + extensionMgr.onFileOpen(fileDesc); // Hide default buttons $(".wmd-button-row").addClass("btn-group").find("li:not(.wmd-spacer)").addClass("btn").css("left", 0).find("span").hide(); diff --git a/js/extensionMgr.js b/js/extensionMgr.js index 0d412181..b201211f 100644 --- a/js/extensionMgr.js +++ b/js/extensionMgr.js @@ -46,14 +46,15 @@ define([ } // Return a function that calls every callbacks with the specified name from all extensions + var hookCallbackList = {}; function createHook(hookName, noLog) { - var callbackList = getExtensionCallbackList(hookName); + hookCallbackList[hookName] = getExtensionCallbackList(hookName); return function() { if(!noLog) { logger.log(hookName, arguments); } var callbackArguments = arguments; - _.each(callbackList, function(callback) { + _.each(hookCallbackList[hookName], function(callback) { // In case user custom callback contains error try { callback.apply(null, callbackArguments); @@ -64,6 +65,9 @@ define([ }); }; } + extensionMgr.addHookCallback = function(hookName, callback) { + hookCallbackList[hookName].push(callback); + }; // Add a Hook to the extensionMgr function addHook(hookName, noLog) { @@ -116,6 +120,8 @@ define([ addHook("onFileCreated"); addHook("onFileDeleted"); addHook("onFileSelected"); + addHook("onFileOpen"); + addHook("onFileClosed"); addHook("onContentChanged"); addHook("onTitleChanged"); diff --git a/js/fileMgr.js b/js/fileMgr.js index a35d291e..c9d924e8 100644 --- a/js/fileMgr.js +++ b/js/fileMgr.js @@ -15,6 +15,7 @@ define([ // Defines the current file fileMgr.currentFile = undefined; + // Set the current file and refresh the editor fileMgr.selectFile = function(fileDesc) { fileDesc = fileDesc || fileMgr.currentFile; @@ -47,8 +48,8 @@ define([ $(".action-edit-document").addClass("hide"); } } - - // Refresh the editor + + // Refresh the editor (even if it's the same file) core.initEditor(fileDesc); }; diff --git a/js/helpers/googleHelper.js b/js/helpers/googleHelper.js index 35367f28..a5b8af76 100644 --- a/js/helpers/googleHelper.js +++ b/js/helpers/googleHelper.js @@ -408,6 +408,36 @@ define([ }); task.enqueue(); }; + + googleHelper.loadRealtime = function(fileId, content, callback) { + var doc = undefined; + var task = new AsyncTask(); + connect(task); + authenticate(task); + task.onRun(function() { + gapi.drive.realtime.load(fileId, function(result) { + // onFileLoaded + doc = result; + task.chain(); + }, function(model) { + // initializeModel + var string = model.createString(content); + model.getRoot().set('content', string); + }, function(err) { + // handleErrors + handleError({ + code: err.type + }, task); + }); + task.onSuccess(function() { + callback(undefined, doc); + }); + }); + task.onError(function(error) { + callback(error); + }); + task.enqueue(); + }; function handleError(error, task) { var errorMsg = undefined; diff --git a/js/providers/gdriveProvider.js b/js/providers/gdriveProvider.js index 59022e4e..b2cd088e 100644 --- a/js/providers/gdriveProvider.js +++ b/js/providers/gdriveProvider.js @@ -243,6 +243,33 @@ define([ return publishAttributes; }; + var editor = undefined; + extensionMgr.addHookCallback("onEditorConfigure", function(editorParam) { + editor = editorParam; + }); + var binding = undefined; + gdriveProvider.onSyncStart = function(fileDesc, syncAttributes) { + console.log("onSyncStart"); + console.log(syncAttributes); + googleHelper.loadRealtime(syncAttributes.id, fileDesc.content, function(err, doc) { + if(err || !doc) { + return; + } + var string = doc.getModel().getRoot().get('content'); + binding = gapi.drive.realtime.databinding.bindString(string, $("#wmd-input")[0]); + var debouncedRefreshPreview = _.debounce(editor.refreshPreview, 100); + string.addEventListener(gapi.drive.realtime.EventType.TEXT_INSERTED, debouncedRefreshPreview); + string.addEventListener(gapi.drive.realtime.EventType.TEXT_DELETED, debouncedRefreshPreview); + }); + }; + + gdriveProvider.onSyncStop = function(syncAttributes) { + console.log("onSyncStop"); + if(binding !== undefined) { + binding.unbind(); + } + }; + core.onReady(function() { var state = utils.retrieveIgnoreError(PROVIDER_GDRIVE + ".state"); if(state === undefined) { diff --git a/js/synchronizer.js b/js/synchronizer.js index 546c874f..18d7c47f 100644 --- a/js/synchronizer.js +++ b/js/synchronizer.js @@ -187,6 +187,23 @@ define([ }); return true; }; + + function onFileOpen(fileDesc) { + _.each(fileDesc.syncLocations, function(syncAttributes) { + if(_.isFunction(syncAttributes.provider.onSyncStart)) { + syncAttributes.provider.onSyncStart(fileDesc, syncAttributes); + } + }); + } + + function onFileClosed(fileDesc) { + _.each(fileDesc.syncLocations, function(syncAttributes) { + if(_.isFunction(syncAttributes.provider.onSyncStop)) { + syncAttributes.provider.onSyncStop(syncAttributes); + } + }); + } + // Initialize the export dialog function initExportDialog(provider) { @@ -251,6 +268,8 @@ define([ }); }); + extensionMgr.addHookCallback("onFileOpen", onFileOpen); + extensionMgr.addHookCallback("onFileClosed", onFileClosed); extensionMgr.onSynchronizerCreated(synchronizer); return synchronizer; });