From 394d3eb0cd7448be3c7efc42c4012ecfdf99e654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Macias?= Date: Thu, 12 Nov 2015 13:40:28 +0100 Subject: [PATCH] First working approach to show mount status --- apps/files_external/js/app.js | 132 +++-- apps/files_external/js/rollingqueue.js | 137 ++++++ apps/files_external/js/statusmanager.js | 486 +++++++++++++++++++ apps/files_external/js/statusmanagerutils.js | 158 ++++++ apps/files_external/lib/api.php | 6 +- apps/files_external/list.php | 5 + 6 files changed, 874 insertions(+), 50 deletions(-) create mode 100644 apps/files_external/js/rollingqueue.js create mode 100644 apps/files_external/js/statusmanager.js create mode 100644 apps/files_external/js/statusmanagerutils.js diff --git a/apps/files_external/js/app.js b/apps/files_external/js/app.js index bf853f926d..411d5fc343 100644 --- a/apps/files_external/js/app.js +++ b/apps/files_external/js/app.js @@ -9,69 +9,105 @@ */ if (!OCA.External) { - /** - * @namespace - */ - OCA.External = {}; + /** + * @namespace + */ + OCA.External = {}; } /** * @namespace */ OCA.External.App = { - fileList: null, + fileList: null, - initList: function($el) { - if (this.fileList) { - return this.fileList; - } + initList: function($el) { + if (this.fileList) { + return this.fileList; + } - this.fileList = new OCA.External.FileList( - $el, - { - scrollContainer: $('#app-content'), - fileActions: this._createFileActions() - } - ); + this.fileList = new OCA.External.FileList( + $el, + { + scrollContainer: $('#app-content'), + fileActions: this._createFileActions() + } + ); - this._extendFileList(this.fileList); - this.fileList.appName = t('files_external', 'External storage'); - return this.fileList; - }, + this._extendFileList(this.fileList); + this.fileList.appName = t('files_external', 'External storage'); + return this.fileList; + }, - removeList: function() { - if (this.fileList) { - this.fileList.$fileList.empty(); - } - }, + removeList: function() { + if (this.fileList) { + this.fileList.$fileList.empty(); + } + }, - _createFileActions: function() { - // inherit file actions from the files app - var fileActions = new OCA.Files.FileActions(); - fileActions.registerDefaultActions(); + _createFileActions: function() { + // inherit file actions from the files app + var fileActions = new OCA.Files.FileActions(); + fileActions.registerDefaultActions(); - // when the user clicks on a folder, redirect to the corresponding - // folder in the files app instead of opening it directly - fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) { - OCA.Files.App.setActiveView('files', {silent: true}); - OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true); - }); - fileActions.setDefault('dir', 'Open'); - return fileActions; - }, + // when the user clicks on a folder, redirect to the corresponding + // folder in the files app instead of opening it directly + fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) { + OCA.Files.App.setActiveView('files', {silent: true}); + OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true); + }); + fileActions.setDefault('dir', 'Open'); + return fileActions; + }, - _extendFileList: function(fileList) { - // remove size column from summary - fileList.fileSummary.$el.find('.filesize').remove(); - } + _extendFileList: function(fileList) { + // remove size column from summary + fileList.fileSummary.$el.find('.filesize').remove(); + } }; $(document).ready(function() { - $('#app-content-extstoragemounts').on('show', function(e) { - OCA.External.App.initList($(e.target)); - }); - $('#app-content-extstoragemounts').on('hide', function() { - OCA.External.App.removeList(); - }); + $('#app-content-extstoragemounts').on('show', function(e) { + OCA.External.App.initList($(e.target)); + }); + $('#app-content-extstoragemounts').on('hide', function() { + OCA.External.App.removeList(); + }); + + /* Status Manager */ + if ($('#filesApp').val()) { + + $('#app-content-files') + .add('#app-content-extstoragemounts') + .on('changeDirectory', function(e){ + if (e.dir === '/') { + var mount_point = e.previousDir.split('/', 2)[1]; + // make sure we have a mount point list + OCA.External.StatusManager.getMountPointList(function() { + OCA.External.StatusManager.recheckConnectivityForMount([mount_point], true, true); + }); + } + }) + .on('fileActionsReady', function(e){ + if ($.isArray(e.$files)) { + if (OCA.External.StatusManager.mountStatus === null || + OCA.External.StatusManager.mountPointList === null || + _.size(OCA.External.StatusManager.mountStatus) !== _.size(OCA.External.StatusManager.mountPointList)) { + // we don't have the data cached, so we'll get it one by one + OCA.External.StatusManager.launchFullConnectivityCheckOneByOne(); + } else { + // make sure we have a mount point list + OCA.External.StatusManager.getMountPointList(function(){ + var fileNames = []; + $.each(e.$files, function(key, value){ + fileNames.push(value.attr('data-file')); + }); + OCA.External.StatusManager.recheckConnectivityForMount(fileNames, false, false); + }); + } + } + }); + } + /* End Status Manager */ }); diff --git a/apps/files_external/js/rollingqueue.js b/apps/files_external/js/rollingqueue.js new file mode 100644 index 0000000000..7e6570a2a7 --- /dev/null +++ b/apps/files_external/js/rollingqueue.js @@ -0,0 +1,137 @@ +/** + * ownCloud + * + * @author Juan Pablo Villafañez Ramos + * @author Jesus Macias Portela + * @copyright (C) 2014 ownCloud, Inc. + * + * This code is covered by the ownCloud Commercial License. + * + * You should have received a copy of the ownCloud Commercial License + * along with this program. If not, see . + * + */ + +(function(){ +/** + * Launch several functions at thee same time. The number of functions + * running at the same time is controlled by the queueWindow param + * + * The function list come in the following format: + * + * var flist = [ + * { + * funcName: function () { + * var d = $.Deferred(); + * setTimeout(function(){d.resolve();}, 1000); + * return d; + * } + * }, + * { + * funcName: $.get, + * funcArgs: [ + * OC.filePath('files_external', 'ajax', 'connectivityCheck.php'), + * {}, + * function () { + * console.log('titoooo'); + * } + * ] + * }, + * { + * funcName: $.get, + * funcArgs: [ + * OC.filePath('files_external', 'ajax', 'connectivityCheck.php') + * ], + * done: function () { + * console.log('yuupi'); + * }, + * always: function () { + * console.log('always done'); + * } + * } + *]; + * + * functions MUST implement the deferred interface + * + * @param functionList list of functions that the queue will run + * (check example above for the expected format) + * @param queueWindow specify the number of functions that will + * be executed at the same time + */ +var RollingQueue = function (functionList, queueWindow, callback) { + this.queueWindow = queueWindow || 1; + this.functionList = functionList; + this.callback = callback; + this.counter = 0; + this.runQueue = function() { + this.callbackCalled = false; + this.deferredsList = []; + if (!$.isArray(this.functionList)) { + throw "functionList must be an array"; + } + + for (i = 0; i < this.queueWindow; i++) { + this.launchNext(); + } + }; + + this.hasNext = function() { + return (this.counter in this.functionList); + }; + + this.launchNext = function() { + var currentCounter = this.counter++; + if (currentCounter in this.functionList) { + var funcData = this.functionList[currentCounter]; + if ($.isFunction(funcData.funcName)) { + var defObj = funcData.funcName.apply(funcData.funcName, funcData.funcArgs); + this.deferredsList.push(defObj); + if ($.isFunction(funcData.done)) { + defObj.done(funcData.done); + } + + if ($.isFunction(funcData.fail)) { + defObj.fail(funcData.fail); + } + + if ($.isFunction(funcData.always)) { + defObj.always(funcData.always); + } + + if (this.hasNext()) { + var self = this; + defObj.always(function(){ + _.defer($.proxy(function(){ + self.launchNext(); + }, self)); + }); + } else { + if (!this.callbackCalled) { + this.callbackCalled = true; + if ($.isFunction(this.callback)) { + $.when.apply($, this.deferredsList) + .always($.proxy(function(){ + this.callback(); + }, this) + ); + } + } + } + return defObj; + } + } + return false; + }; +}; + +if (!OCA.External) { + OCA.External = {}; +} + +if (!OCA.External.StatusManager) { + OCA.External.StatusManager = {}; +} + +OCA.External.StatusManager.RollingQueue = RollingQueue; + +})(); \ No newline at end of file diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js new file mode 100644 index 0000000000..f3e0832ad6 --- /dev/null +++ b/apps/files_external/js/statusmanager.js @@ -0,0 +1,486 @@ +/** + * ownCloud + * + * @author Juan Pablo Villafañez Ramos + * @author Jesus Macias Portela + * @copyright (C) 2014 ownCloud, Inc. + * + * This code is covered by the ownCloud Commercial License. + * + * You should have received a copy of the ownCloud Commercial License + * along with this program. If not, see . + * + */ + +if (!OCA.External) { + OCA.External = {}; +} + +OCA.External.StatusManager = { + mountStatus : null, + mountPointList : null, + + getMountStatus : function(afterCallback) { + var self = this; + if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) { + return; + } + + if (self.mountStatus) { + afterCallback(self.mountStatus); + } else { + self.isGetMountStatusRunning = true; + $.ajax({ + type : 'GET', + url : OC.filePath('files_external', 'ajax', 'connectivityCheck.php'), + success : function(response) { + self.mountStatus = response.data; + afterCallback(self.mountStatus); + }, + error : function(jqxhr, state, error) { + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the status of the external mounts: {type}', {type : error})); + if (!self.mountStatus) { + self.mountStatus = {}; + } + $.each(self.mountPointList, function(name, value){ + if (!self.mountStatus[value.mount_point]) { + self.mountStatus[value.mount_point] = {}; + } + self.mountStatus[value.mount_point].status = 'ok'; + OCA.External.StatusManager.Utils.restoreFolder(value); + OCA.External.StatusManager.Utils.toggleLink(value.mount_point, true, true); + }); + }, + complete : function() { + self.isGetMountStatusRunning = false; + } + }); + } + }, + + getMountPointListElement : function(mount_point) { + var element; + $.each(this.mountPointList, function(key, value){ + if (value.mount_point === mount_point) { + element = value; + return false; + } + }); + return element; + }, + + getMountStatusForMount : function(mountData, afterCallback) { + var self = this; + if (typeof afterCallback !== 'function' || self.isGetMountStatusRunning) { + return $.Deferred().resolve(); + } + + var defObj; + if (self.mountStatus[mountData.mount_point]) { + defObj = $.Deferred(); + afterCallback(mountData.mount_point, self.mountStatus[mountData.mount_point]); + defObj.resolve(); // not really useful, but it'll keep the same behaviour + } else { + defObj = $.ajax({ + type : 'GET', + url: OC.webroot + '/index.php/apps/files_external/globalstorages/' + mountData.id, + success : function(response) { + if (response && response.status === 0) { + self.mountStatus[mountData.mount_point] = response; + } else { + if (response && response.data) { + // failure response with error message + self.mountStatus[mountData.mount_point] = {code: 'GE', + status: 'fail', + error: response.data.message}; + } else { + self.mountStatus[mountData.mount_point] = {code: 'GE', + status: 'fail', + error: t('files_external', 'Empty response from the server')}; + } + } + afterCallback(mountData.mount_point, self.mountStatus[mountData.mount_point]); + }, + error : function(jqxhr, state, error) { + var message; + if(mountData.location === 3){ + // In this case the error is because mount point use Login credentials and don't exist in the session + message = t('files_external', 'Couldn\'t access. Please logout and login to activate this mount point'); + } else { + message = t('files_external', 'Couldn\'t get the information from the ownCloud server: {code} {type}', {code: jqxhr.status, type: error}); + } + self.mountStatus[mountData.mount_point] = {code: 'GE', + status: 'fail', + location: mountData.location, + error: message}; + afterCallback(mountData.mount_point, self.mountStatus[mountData.mount_point]); + } + }); + } + return defObj; + }, + + getMountPointList : function(afterCallback) { + var self = this; + if (typeof afterCallback !== 'function' || self.isGetMountPointListRunning) { + return; + } + + + if (self.mountPointList) { + afterCallback(self.mountPointList); + } else { + self.isGetMountPointListRunning = true; + $.ajax({ + type : 'GET', + url : OC.linkToOCS('apps/files_external/api/v1') + 'mounts?format=json', + success : function(response) { + self.mountPointList = []; + _.each(response.ocs.data, function(mount){ + var element = {}; + element.mount_point = mount.name; + element.type = mount.scope; + element.location = ""; + element.id = mount.id; + element.backend = mount.backend; + element.class = mount.class; + + self.mountPointList.push(element); + }); + afterCallback(self.mountPointList); + }, + error : function(jqxhr, state, error) { + self.mountPointList = []; + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the list of external mount points: {type}', {type : error})); + }, + complete : function() { + self.isGetMountPointListRunning = false; + } + }); + } + }, + + setMountPointAsGood : function(mountPoint) { + OCA.External.StatusManager.Utils.restoreFolder(mountPoint); + OCA.External.StatusManager.Utils.toggleLink(mountPoint, true, true); + delete this.mountStatus[mountPoint].code; + delete this.mountStatus[mountPoint].error; + this.mountStatus[mountPoint].status = 'ok'; + }, + + manageMountPointError : function(name) { + var self = this; + this.getMountStatus($.proxy(function(allMountStatus) { + if (typeof allMountStatus[name] !== 'undefined' || allMountStatus[name].status === 'fail') { + var mountData = allMountStatus[name]; + if ((mountData.code === 'CNP' || mountData.code === 'AD') && mountData.type === 'global' && mountData.location === 1) { + // admin set up mount point and let users use their credentials. Credentials + // aren't stored yet or are wrong (handled by the same ajax request) + this.showCredentialsDialog(name, mountData, null, 'saveCredential.php', + null, this.setMountPointAsGood, this); + + } else if (mountData.code === 'AD' && mountData.type === 'personal' && mountData.location === 0) { + // personal set up mount point and let users use their credentials. + // Credentials are wrong so they need to be updated + // the "type 0" is a required parameter in the target ajax call + this.showCredentialsDialog(name, mountData, {type: 0}, 'updatePersonalMountPoint.php', + null, this.setMountPointAsGood, this); + + } else if (mountData.code === 'AD' && mountData.type === 'personal' && mountData.location === 2) { + this.showCredentialsDialog(name, mountData, null, 'saveGlobalCredentials.php', + t('files_external', 'WARNING: This mount point uses global credentials.\n\nChanging the credentials might affect to other mount points'), + function() { + this.recheckConnectivityForMount([name], true, true); + }, + this); + + } else if (mountData.code === 'AD' && mountData.type === 'global' && (mountData.location === 0 || mountData.location === 2)) { + OC.dialogs.message(t('files_external', 'The credentials for this mount point are wrong. This mount point was set by the administrator, please contact him / her to provide suitable credentials'), t('files_external', 'Credentials error')); + + } else if ((mountData.code === 'CE' || mountData.code === 'IH')) { + OC.dialogs.message(mountData.error, t('files_external', 'Connectivity error')); + + } else if ((mountData.code === 'GE' && mountData.location === 3)) { + OC.dialogs.message(mountData.error, t('files_external', 'Login credentials error')); + + } else { + OC.dialogs.message(mountData.error, t('files_external', 'Unknown error')); + } + } + }, this)); + }, + + showCredentialsDialog : function(mountPoint, mountData, extraParams, target, extraInfo, successCallback, callbackCtx) { + var self = this; + var baseParams = {target: target, + m: mountData.mid, + name: mountPoint, + url: mountData.url, + share: mountData.share, + extra: extraInfo}; + var sendParams = ($.isPlainObject(extraParams)) ? $.extend(baseParams, extraParams) : baseParams; + $.get(OC.filePath('files_external', 'ajax', 'dialog.php'), + sendParams, + function(data) { + if (typeof data.status !== 'undefined' && data.status === 'success') { + $('body').append(data.form); + var wnd_send_button_click_func = function () { + $('.oc-dialog-close').hide(); + var dataToSend = {}; + $('#wnd_div_form').find('input').each(function(){ + var thisElement = $(this); + if (thisElement.is('[type="checkbox"]')) { + dataToSend[thisElement.attr('name')] = thisElement.prop('checked'); + } else { + dataToSend[thisElement.attr('name')] = thisElement.val(); + } + }); + $.ajax({type: 'POST', + url: $('#wnd_div_form form').attr('action'), + data: dataToSend, + success: function (data) { + var dialog = $('#wnd_div_form'); + if (typeof(data.status) !== 'undefined' && data.status === 'success') { + dialog.ocdialog('close'); + + if (successCallback && $.isFunction(successCallback)) { + successCallback.call(callbackCtx || this, mountPoint); + } + } else { + $('.oc-dialog-close').show(); + dialog.ocdialog('option', 'title', 'Windows Network Drive credentials validation failed'); + var title = $('.oc-dialog-title'); + var color = title.css('background-color'); + title.css('background-color', 'red'); + title.animate({backgroundColor: color}, 5000); + } + }, + error: function (){ + $('.oc-dialog-close').show(); + }}); + }; + + var buttonList = [{text : t('files_external', 'Save'), + click : wnd_send_button_click_func, + closeOnEscape : true}]; + + var ocdialogParams = {modal: true, buttons : buttonList, + closeOnExcape : true}; + $('#wnd_div_form').ocdialog(ocdialogParams) + .bind('ocdialogclose', function(){ + $('#wnd_div_form').ocdialog('destroy').remove(); + }); + } + }); + }, + + processMountStatus : function(mounts) { + var hasErrors = false; + var self = this; + $.each(mounts, function(mountPoint, values){ + hasErrors = !self.processMountStatusIndividual(mountPoint, values) || hasErrors; + }); + + if (!this.notificationHasShown) { + this.notificationHasShown = true; + if (hasErrors) { + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Some of the configured Windows network drive(s) are not connected. Please click on the red row(s) for more information')); + } + } + }, + + processMountStatusIndividual : function(mountPoint, mountData) { + if (mountData.status === 'fail') { + var errorImage = 'folder-windows'; + if (mountData.code === 'AD' || mountData.code === 'CNP') { + errorImage += '-credentials'; + } else if (mountData.code === 'IH' || mountData.code === 'CE') { + errorImage += '-timeout'; + } else { + errorImage += '-error'; + } + if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + OCA.External.StatusManager.Utils.showIconError(mountPoint, $.proxy(OCA.External.StatusManager.manageMountPointError, OCA.External.StatusManager), OC.imagePath('files_external', errorImage)); + } + return false; + } else { + if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + OCA.External.StatusManager.Utils.restoreFolder(mountPoint); + OCA.External.StatusManager.Utils.toggleLink(mountPoint, true, true); + } + return true; + } + }, + + processMountList : function(mountList) { + var elementList = null; + $.each(mountList, function(name, value){ + var trElement = $('#fileList tr[data-file=\"' + OCA.External.StatusManager.Utils.jqSelEscape(value.mount_point) + '\"]'); + if (elementList) { + elementList = elementList.add(trElement); + } else { + elementList = trElement; + } + }); + + if (elementList instanceof $) { + if (OCA.External.StatusManager.Utils.isCorrectViewAndRootFolder()) { + // Put their custom icon + // OCA.External.StatusManager.Utils.changeFolderIcon(elementList.find('td:first-child div.thumbnail'), "url(" + OC.imagePath('windows_network_drive', 'folder-windows') + ")"); + // Save default view + OCA.External.StatusManager.Utils.storeDefaultFolderIconAndBgcolor(elementList); + // Disable row until check status + elementList.css('background-color', '#CCC'); + OCA.External.StatusManager.Utils.toggleLink(elementList.find('a.name'), false, false); + } + } + }, + + launchFullConnectivityCheck : function() { + var self = this; + this.getMountPointList(function(list){ + // check if we have a list first + if (list === undefined && !self.emptyWarningShown) { + self.emptyWarningShown = true; + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the list of Windows network drive mount points: empty response from the server')); + return; + } + if (list && list.length > 0) { + self.processMountList(list); + self.getMountStatus(function(mountStatus){ + if (mountStatus === undefined && !self.notificationNoProcessListDone) { + self.notificationNoProcessListDone = true; + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the status of the Windows network drive mounts: empty response from the server')); + if (!self.mountStatus) { + self.mountStatus = {}; + } + $.each(list, function(name, value){ + if (!self.mountStatus[value.mount_point]) { + self.mountStatus[value.mount_point] = {}; + } + self.mountStatus[value.mount_point].status = 'ok'; + OCA.External.StatusManager.Utils.restoreFolder(value.mount_point); + OCA.External.StatusManager.Utils.toggleLink(value.mount_point, true, true); + }); + return; + } + self.processMountStatus(mountStatus); + }); + } + }); + }, + + launchFullConnectivityCheckOneByOne : function() { + var self = this; + this.getMountPointList(function(list){ + // check if we have a list first + if (list === undefined && !self.emptyWarningShown) { + self.emptyWarningShown = true; + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Couldn\'t get the list of Windows network drive mount points: empty response from the server')); + return; + } + if (list && list.length > 0) { + self.processMountList(list); + + if (!self.mountStatus) { + self.mountStatus = {}; + } + + var ajaxQueue = []; + $.each(list, function(key, value){ + var queueElement = {funcName: $.proxy(self.getMountStatusForMount, self), + funcArgs: [value, + $.proxy(self.processMountStatusIndividual, self)]}; + ajaxQueue.push(queueElement); + }); + + var rolQueue = new OCA.External.StatusManager.RollingQueue(ajaxQueue, 4, function(){ + if (!self.notificationHasShown) { + var showNotification = false; + $.each(self.mountStatus, function(key, value){ + if (value.status === 'fail') { + self.notificationHasShown = true; + showNotification = true; + } + }); + if (showNotification) { + OCA.External.StatusManager.Utils.showAlert(t('files_external', 'Some of the configured Windows network drive(s) are not connected. Please click on the red row(s) for more information')); + } + } + }); + rolQueue.runQueue(); + } + }); + }, + + launchPartialConnectivityCheck : function(mountListData, recheck) { + if (mountListData.length === 0) { + return; + } + + var self = this; + var ajaxQueue = []; + $.each(mountListData, function(key, value){ + if (recheck && value.mount_point in self.mountStatus) { + delete self.mountStatus[value.mount_point]; + } + var queueElement = {funcName: $.proxy(self.getMountStatusForMount, self), + funcArgs: [value, + $.proxy(self.processMountStatusIndividual, self)]}; + ajaxQueue.push(queueElement); + }); + new OCA.External.StatusManager.RollingQueue(ajaxQueue, 4).runQueue(); + }, + + recheckConnectivityForMount : function(mountListNames, recheck, checkGlobal) { + if (mountListNames.length === 0) { + return; + } + + var self = this; + var mountListData = []; + var recheckPersonalGlobal = false; + var recheckAdminGlobal = false; + + if (!self.mountStatus) { + self.mountStatus = {}; + } + + $.each(mountListNames, function(key, value){ + var mountData = self.getMountPointListElement(value); + if (mountData) { + if (mountData.type === 'personal' && mountData.location === 2) { + recheckPersonalGlobal = true; + } + if (mountData.type === 'admin' && mountData.location === 2) { + recheckAdminGlobal = true; + } + mountListData.push(mountData); + } + }); + + // we might need to check more mounts if a personal mount with global credentials is affected + if (checkGlobal && (recheckPersonalGlobal || recheckAdminGlobal)) { + $.each(self.mountPointList, function(key, value){ + if (((recheckPersonalGlobal && value.type === 'personal') || (recheckAdminGlobal && value.type === 'admin')) && + value.location === 2 && + $.inArray(value, mountListData) === -1) { + // personal mount using global credentials, not present in the mountListData + mountListData.push(value); + } + }); + } + + // for all mounts in the list, delete the cached status values + if (recheck) { + $.each(mountListData, function(key, value){ + if (value.mount_point in self.mountStatus) { + delete self.mountStatus[value.mount_point]; + } + }); + } + + self.processMountList(mountListData); + self.launchPartialConnectivityCheck(mountListData, recheck); + } +}; diff --git a/apps/files_external/js/statusmanagerutils.js b/apps/files_external/js/statusmanagerutils.js new file mode 100644 index 0000000000..e8e8265f9e --- /dev/null +++ b/apps/files_external/js/statusmanagerutils.js @@ -0,0 +1,158 @@ +/** + * ownCloud + * + * @author Juan Pablo Villafañez Ramos + * @author Jesus Macias Portela + * @copyright (C) 2014 ownCloud, Inc. + * + * This code is covered by the ownCloud Commercial License. + * + * You should have received a copy of the ownCloud Commercial License + * along with this program. If not, see . + * + */ + +if (!OCA.External) { + OCA.External = {}; +} + +if (!OCA.External.StatusManager) { + OCA.External.StatusManager = {}; +} + +OCA.External.StatusManager.Utils = { + + showAlert: function(message){ + if (!OC.Notification.isHidden()) { + OC.Notification.hide(); + OC.Notification.showHtml(message); + } else { + OC.Notification.showHtml(message); + } + setTimeout(function() { + if ($("#notification").text() === message) { + OC.Notification.hide(); + } + }, 10000); + }, + + showIconError: function(folder, clickAction, errorImageUrl) { + var bgColor = '#F2DEDE'; + var imageUrl = "url(" + errorImageUrl + ")"; + var trFolder = $('#fileList tr[data-file=\"' + this.jqSelEscape(folder) + '\"]'); + this.changeFolderIcon(folder, imageUrl); + this.toggleLink(folder, false, clickAction); + trFolder.css('background-color', bgColor); + }, + + /** + * @param folder string with the folder or jQuery element pointing to the tr element + */ + storeDefaultFolderIconAndBgcolor: function(folder) { + var trFolder; + if (folder instanceof $) { + trFolder = folder; + } else { + trFolder = $('#fileList tr[data-file=\"' + this.jqSelEscape(folder) + '\"]'); + } + trFolder.each(function(){ + var thisElement = $(this); + if (thisElement.data('oldbgcolor') === undefined) { + thisElement.data('oldbgcolor', thisElement.css('background-color')); + } + }); + + var icon = trFolder.find('td:first-child div.thumbnail'); + icon.each(function(){ + var thisElement = $(this); + if (thisElement.data('oldImage') === undefined) { + thisElement.data('oldImage', thisElement.css('background-image')); + } + }); + }, + + /** + * @param folder string with the folder or jQuery element pointing to the tr element + */ + restoreFolder: function(folder) { + var trFolder; + if (folder instanceof $) { + trFolder = folder; + } else { + trFolder = $('#fileList tr[data-file=\"' + this.jqSelEscape(folder) + '\"]'); + } + trFolder.css('background-color', ''); + tdChilds = trFolder.find("td:first-child div.thumbnail"); + tdChilds.each(function(){ + var thisElement = $(this); + thisElement.css('background-image', thisElement.data('oldImage')); + }); + }, + + /** + * @param folder string with the folder or jQuery element pointing to the first td element + * of the tr matching the folder name + */ + changeFolderIcon: function(filename, route) { + var file; + if (filename instanceof $) { + file = filename; + } else { + file = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td:first-child div.thumbnail"); + } + file.css('background-image', route).hide().show(0); + // previous line is required in Chrome to force the css update so the image url + // is stored correctly later + //file.css('background-image', route).height(); + }, + + toggleLink: function(filename, active, action) { + var link; + if (filename instanceof $) { + link = filename; + } else { + link = $("#fileList tr[data-file=\"" + this.jqSelEscape(filename) + "\"] > td:first-child a.name"); + } + if (active) { + link.off('click.connectivity'); + OCA.Files.App.fileList.fileActions.display(link.parent(), true, OCA.Files.App.fileList); + } else { + link.find('.fileactions, .nametext .action').remove(); // from files/js/fileactions (display) + link.off('click.connectivity'); + link.on('click.connectivity', function(e){ + if (action && $.isFunction(action)) { + action(filename); + } + e.preventDefault(); + return false; + }); + } + }, + + isCorrectViewAndRootFolder: function() { + // correct views = files & extstoragemounts + if (OCA.Files.App.getActiveView() === 'files' || OCA.Files.App.getActiveView() === 'extstoragemounts') { + return OCA.Files.App.getCurrentAppContainer().find('#dir').val() === '/'; + } + return false; + }, + + /* escape a selector expression for jQuery */ + jqSelEscape: function(expression) { + return expression.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&'); + }, + + /* Copied from http://stackoverflow.com/questions/2631001/javascript-test-for-existence-of-nested-object-key */ + checkNested: function(cobj /*, level1, level2, ... levelN*/) { + var args = Array.prototype.slice.call(arguments), + obj = args.shift(); + + for (var i = 0; i < args.length; i++) { + if (!obj || !obj.hasOwnProperty(args[i])) { + return false; + } + obj = obj[args[i]]; + } + return true; + } +}; diff --git a/apps/files_external/lib/api.php b/apps/files_external/lib/api.php index af9b802e52..f0c9e568c9 100644 --- a/apps/files_external/lib/api.php +++ b/apps/files_external/lib/api.php @@ -28,7 +28,7 @@ class Api { /** * Formats the given mount config to a mount entry. - * + * * @param string $mountPoint mount point name, relative to the data dir * @param array $mountConfig mount config to format * @@ -59,7 +59,9 @@ class Api { 'type' => 'dir', 'backend' => $mountConfig['backend'], 'scope' => ( $isSystemMount ? 'system' : 'personal' ), - 'permissions' => $permissions + 'permissions' => $permissions, + 'id' => $mountConfig['id'], + 'class' => $mountConfig['class'] ); return $entry; } diff --git a/apps/files_external/list.php b/apps/files_external/list.php index b98db79de8..831107c9c3 100644 --- a/apps/files_external/list.php +++ b/apps/files_external/list.php @@ -23,6 +23,11 @@ OCP\User::checkLoggedIn(); $tmpl = new OCP\Template('files_external', 'list', ''); +/* Load Status Manager */ +\OCP\Util::addScript('files_external', 'statusmanager'); +\OCP\Util::addScript('files_external', 'statusmanagerutils'); +\OCP\Util::addScript('files_external', 'rollingqueue'); + OCP\Util::addScript('files_external', 'app'); OCP\Util::addScript('files_external', 'mountsfilelist');