/* * Copyright 2007-2017 Charles du Jeu - Abstrium SAS * This file is part of Pydio. * * Pydio is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Pydio is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Pydio. If not, see . * * The latest code can be found at . */ import Observable from '../lang/Observable' import LangUtils from '../util/LangUtils' import ResourcesManager from '../http/ResourcesManager' import Logger from '../lang/Logger' import XMLUtils from '../util/XMLUtils' import FuncUtils from '../util/FuncUtils' /** * A "Command" object, encapsulating its callbacks, display attributes, etc. */ export default class Action extends Observable{ /** * Standard constructor */ constructor(){ super(); this.__DEFAULT_ICON_PATH = "actions/ICON_SIZE"; this.options = LangUtils.objectMerge({ name:'', icon_class:'', text:'', title:'', text_id:'', title_id:'', weight:0, hasAccessKey:false, accessKey:'', subMenu:false, subMenuUpdateImage:false, subMenuUpdateTitle:false, callbackCode:'', callback:function(){}, listeners : [], activeCondition:null }, arguments[0] || { }); this.context = LangUtils.objectMerge({ selection:true, dir:false, allowedMimes:[], evalMetadata:'', root:true, inZip:true, recycle:false, behaviour:'hidden', actionBar:false, actionBarGroup:'default', contextMenu:false, ajxpWidgets:null, infoPanel:false }, arguments[1] || { }); this.selectionContext = LangUtils.objectMerge({ dir:false, file:true, recycle:false, behaviour:'disabled', allowedMimes:[], evalMetadata:'', unique:true, multipleOnly:false, enableRoot:false }, arguments[2] || { }); this.rightsContext = LangUtils.objectMerge({ noUser:true, userLogged:true, guestLogged:false, read:false, write:false, adminOnly:false }, arguments[3] || { }); this.subMenuItems = LangUtils.objectMerge({ staticItems:null, dynamicItems:null, dynamicBuilderCode:null, popoverContent: null }, arguments[4] || {}); this.elements = []; this.contextHidden = false; this.deny = false; if(this.context.subMenu){ if(!this.options.actionBar){ alert('Warning, wrong action definition. Cannot use a subMenu if not displayed in the actionBar!'); } } } _evalScripts(data, localScopeMetadata){ let metadata = localScopeMetadata; return eval(data); } /** * Sets the manager for this action * @param manager ActionsManager */ setManager (manager){ this.manager = manager; if(this.options.subMenu){ if(this.subMenuItems.staticItems){ this.buildSubmenuStaticItems(); } if(this.subMenuItems.dynamicItems || this.subMenuItems.dynamicBuilderCode){ this.prepareSubmenuDynamicBuilder(); }else if(this.subMenuItems.dynamicBuilderModule){ ResourcesManager.detectModuleToLoadAndApply(this.subMenuItems.dynamicBuilderModule, this.prepareSubmenuDynamicBuilder.bind(this)); } } if(this.options.listeners['init']){ try{ window.listenerContext = this; if(typeof(this.options.listeners['init']) == "string"){ this._evalScripts(this.options.listeners['init']); }else{ this.options.listeners['init'](); } }catch(e){ Logger.error('Error while evaluating init script for action ' + this.options.name); } } } /** * Execute the action code */ apply(){ if(this.deny) return; this.manager.publishActionEvent("beforeApply-"+this.options.name); window.actionArguments = []; window.actionManager = this.manager; if(arguments[0]) window.actionArguments = arguments[0]; if(this.options.callbackCode) { try{ this._evalScripts(this.options.callbackCode); }catch(e){ Logger.error(e); } }else if(this.options.callback){ this.options.callback(this.manager, arguments[0]); } if(this.options.subMenu && arguments[0] && arguments[0][0]){ this.notify("submenu_active", arguments[0][0]); } window.actionArguments = null; window.actionManager = null; this.manager.publishActionEvent("afterApply-"+this.options.name); } /** * Updates the action status on context change * @param PydioDataModel dataModel * @param boolean usersEnabled * @param string crtUser * @returns void */ fireContextChange(dataModel, usersEnabled, crtUser){ var crtIsRecycle = false; var crtInZip = false; var crtIsRoot = false; var crtAjxpMime = ''; var crtIsReadOnly = false; var crtNode = dataModel.getContextNode(); if(crtNode){ crtIsRecycle = (crtNode.getAjxpMime() == "ajxp_recycle"); crtInZip = crtNode.hasAjxpMimeInBranch("ajxp_browsable_archive"); crtIsRoot = crtNode.isRoot(); crtAjxpMime = crtNode.getAjxpMime(); crtIsReadOnly = crtNode.hasMetadataInBranch("ajxp_readonly", "true"); } if(this.options.listeners["contextChange"]){ if(this.options.listeners["contextChange"] instanceof Function){ this.options.listeners["contextChange"](); }else{ window.listenerContext = this; try{ this._evalScripts(this.options.listeners["contextChange"]); }catch(e){ Logger.error("Error while evaluating script for contextChange event - action " + this.options.name); } } } var rightsContext = this.rightsContext; if(!rightsContext.noUser && !usersEnabled){ return this.hideForContext(); } if((rightsContext.userLogged == 'only' && crtUser == null) || (rightsContext.guestLogged && rightsContext.guestLogged=='hidden' && crtUser!=null && crtUser.id=='guest')){ return this.hideForContext(); } if(rightsContext.userLogged == 'hidden' && crtUser != null && !(crtUser.id=='guest' && rightsContext.guestLogged && rightsContext.guestLogged=='show') ){ return this.hideForContext(); } if(rightsContext.adminOnly && (crtUser == null || !crtUser.isAdmin)){ return this.hideForContext(); } if(rightsContext.read && crtUser != null && !crtUser.canRead() ){ return this.hideForContext(); } if(rightsContext.write && crtUser != null && !crtUser.canWrite()){ return this.hideForContext(); } if(rightsContext.write && crtIsReadOnly){ return this.hideForContext(); } if(this.context.allowedMimes.length){ if( this.context.allowedMimes.indexOf("*") == -1 && this.context.allowedMimes.indexOf(crtAjxpMime) == -1){ return this.hideForContext(); } if( this.context.allowedMimes.indexOf("^"+crtAjxpMime) != -1){ return this.hideForContext(); } } if(this.context.recycle){ if(this.context.recycle == 'only' && !crtIsRecycle){ return this.hideForContext(); } if(this.context.recycle == 'hidden' && crtIsRecycle){ return this.hideForContext(); } } if(!this.context.inZip && crtInZip){ return this.hideForContext(); } if(!this.context.root && crtIsRoot){ return this.hideForContext(); } this.showForContext(dataModel); } /** * Upates the action status on selection change */ fireSelectionChange(){ if(this.options.listeners["selectionChange"]){ if(this.options.listeners["selectionChange"] instanceof Function){ this.options.listeners["selectionChange"](); } else { window.listenerContext = this; try { this._evalScripts(this.options.listeners["selectionChange"]); } catch (e) { Logger.error("Error while evaluating script for selectionChange event - action " + this.options.name); } } } if(this.options.activeCondition){ try{ let result = this.options.activeCondition(); if(result === false) this.disable(); else if(result === true) this.enable(); }catch(e){ Logger.error("Error while evaluating activeCondition() script for action " + this.options.name); } } if(this.contextHidden || !this.context.selection) { return; } var userSelection = arguments[0]; var hasRoot = false; if(userSelection != null) { hasRoot = userSelection.selectionHasRootNode(); var bUnique = userSelection.isUnique(); var bFile = userSelection.hasFile(); var bDir = userSelection.hasDir(); var bRecycle = userSelection.isRecycle(); } var selectionContext = this.selectionContext; if(selectionContext.allowedMimes.length){ if(selectionContext.behaviour == 'hidden') this.hide(); else this.disable(); } if(selectionContext.evalMetadata && userSelection && userSelection.isUnique()){ let result = this._evalScripts(selectionContext.evalMetadata, userSelection.getUniqueNode().getMetadata()); if(!result){ if(selectionContext.behaviour == 'hidden') this.hide(); else this.disable(); return; } } if(!selectionContext.enableRoot && hasRoot){ return this.disable(); } if(selectionContext.unique && !bUnique){ return this.disable(); } if(selectionContext.multipleOnly && bUnique){ return this.disable(); } if((selectionContext.file || selectionContext.dir) && !bFile && !bDir){ return this.disable(); } if((selectionContext.dir && !selectionContext.file && bFile) || (!selectionContext.dir && selectionContext.file && bDir)){ return this.disable(); } if(!selectionContext.recycle && bRecycle){ return this.disable(); } if(this.rightsContext.write && userSelection.hasReadOnly()){ return this.disable(); } if(selectionContext.allowedMimes.length && userSelection && selectionContext.allowedMimes.indexOf('*') == -1 && !userSelection.hasMime(selectionContext.allowedMimes)){ if(selectionContext.behaviour == 'hidden') return this.hide(); else return this.disable(); } if(selectionContext.allowedMimes.length && userSelection && selectionContext.allowedMimes.indexOf("^") !== -1){ var forbiddenValueFound = false; selectionContext.allowedMimes.forEach(function(m){ if(m.indexOf("^") == -1) return; if(userSelection.hasMime([m.replace("^", "")])){ forbiddenValueFound = true; //throw $break; } }); if(forbiddenValueFound){ if(selectionContext.behaviour == 'hidden') return this.hide(); else return this.disable(); } } this.show(); this.enable(); } getMenuData(){ let menuItem = { name:this.getKeyedText(), raw_name: this.options.text, alt:this.options.title, action_id:this.options.name, weight:this.options.weight || 0, callback: function(e){this.apply();}.bind(this) }; if(this.options.icon_class){ menuItem.icon_class = this.options.icon_class; } if(this.options.subMenu){ menuItem.subMenu = []; if(this.subMenuItems.staticOptions){ menuItem.subMenu = this.subMenuItems.staticOptions; } if(this.subMenuItems.dynamicBuilder){ menuItem.subMenuBeforeShow = this.subMenuItems.dynamicBuilder; } } return menuItem; } /** * Parses an XML fragment to configure this action * @param xmlNode Node XML Fragment describing the action */ createFromXML(xmlNode){ this.options.name = xmlNode.getAttribute('name'); for(var i=0; i' + accessKey + ')'; } if(displayString.charAt(keyPos) != accessKey){ // case differ accessKey = displayString.charAt(keyPos); } var returnString = displayString.substring(0,displayString.indexOf(accessKey)); returnString += ''+accessKey+''; returnString += displayString.substring(displayString.indexOf(accessKey)+1, displayString.length); return returnString; } /** * Utilitary function to transform XML Node attributes into Object mapping keys. * @param object Object The target object * @param node Node The source node */ attributesToObject(object, node){ for (var key in object){ if(!object.hasOwnProperty(key) || !node.getAttribute(key)) continue; var value = node.getAttribute(key); if(value == 'true') value = true; else if(value == 'false') value = false; if(key == 'allowedMimes'){ if(value && value.split(',').length){ value = value.split(','); }else{ value = []; } } object[key] = value; } } }