/* * Copyright 2007-2011 Charles du Jeu * This file is part of AjaXplorer. * * AjaXplorer 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. * * AjaXplorer 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 AjaXplorer. If not, see . * * The latest code can be found at . */ /** * A "Command" object, encapsulating its callbacks, display attributes, etc. */ Class.create("Action", { /** * @var String Default "/images/actions/ICON_SIZE" */ __DEFAULT_ICON_PATH : "/images/actions/ICON_SIZE", /** * Standard constructor */ initialize:function(){ this.options = Object.extend({ name:'', src:'', text:'', title:'', text_id:'', title_id:'', hasAccessKey:false, accessKey:'', subMenu:false, subMenuUpdateImage:false, subMenuUpdateTitle:false, callbackCode:'', callbackDialogNode:null, callback:Prototype.emptyFunction, prepareModal:false, listeners : [], formId:undefined, formCode:undefined }, arguments[0] || { }); this.context = Object.extend({ selection:true, dir:false, allowedMimes:$A([]), root:true, inZip:true, recycle:false, behaviour:'hidden', actionBar:false, actionBarGroup:'default', contextMenu:false, ajxpWidgets:null, infoPanel:false }, arguments[1] || { }); this.selectionContext = Object.extend({ dir:false, file:true, recycle:false, behaviour:'disabled', allowedMimes:$A([]), unique:true, multipleOnly:false }, arguments[2] || { }); this.rightsContext = Object.extend({ noUser:true, userLogged:true, guestLogged:false, read:true, write:false, adminOnly:false }, arguments[3] || { }); this.subMenuItems = Object.extend({ staticItems:null, dynamicItems:null, dynamicBuilderCode:null }, arguments[4] || {}); this.elements = new Array(); 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!'); } } }, /** * Sets the manager for this action * @param manager ActionsManager */ setManager : function(manager){ this.manager = manager; if(this.options.subMenu){ if(this.subMenuItems.staticItems){ this.buildSubmenuStaticItems(); } if(this.subMenuItems.dynamicItems || this.subMenuItems.dynamicBuilderCode){ this.prepareSubmenuDynamicBuilder(); } } if(this.options.listeners['init']){ try{ window.listenerContext = this; if(Object.isString(this.options.listeners['init'])){ this.options.listeners['init'].evalScripts(); }else{ this.options.listeners['init'](); } }catch(e){ alert(e); } } }, /** * Execute the action code */ apply: function(){ if(this.deny) return; document.fire("ajaxplorer:beforeApply-"+this.options.name); if(this.options.prepareModal){ modal.prepareHeader( this.options.title, resolveImageSource(this.options.src,this.__DEFAULT_ICON_PATH, 16) ); } window.actionArguments = $A([]); if(arguments[0]) window.actionArguments = $A(arguments[0]); if(this.options.callbackCode) { try{ this.options.callbackCode.evalScripts(); }catch(e){ ajaxplorer.displayMessage('ERROR', e.message); } }else if(this.options.callbackDialogNode){ var node = this.options.callbackDialogNode; var dialogFormId = node.getAttribute("dialogOpenForm"); var okButtonOnly = (node.getAttribute("dialogOkButtonOnly") === "true")?true:false ; var skipButtons = (node.getAttribute("dialogSkipButtons") === "true")?true:false ; var onOpenFunc = null; var onCompleteFunc = null; var onCancelFunc = null; var onOpenNode = XPathSelectSingleNode(node, "dialogOnOpen"); if(onOpenNode && onOpenNode.firstChild) var onOpenFunc = new Function("oForm", onOpenNode.firstChild.nodeValue); var onCompleteNode = XPathSelectSingleNode(node, "dialogOnComplete"); if(onCompleteNode && onCompleteNode.firstChild) { var completeCode = onCompleteNode.firstChild.nodeValue; if(onCompleteNode.getAttribute("hideDialog") === "true"){ completeCode += "hideLightBox(true);"; } var onCompleteFunc = new Function("oForm", completeCode); } var onCancelNode = XPathSelectSingleNode(node, "dialogOnCancel"); if(onCancelNode && onCancelNode.firstChild) var onCancelFunc = new Function("oForm", onCancelNode.firstChild.nodeValue); this.options.callback = function(){ modal.showDialogForm('Dialog', dialogFormId, onOpenFunc, onCompleteFunc, onCancelFunc, okButtonOnly, skipButtons); }; this.options.callback(); this.options.callbackDialogNode = null; }else if(this.options.callback){ this.options.callback(); } if(this.options.subMenu && arguments[0] && arguments[0][0]){ this.notify("submenu_active", arguments[0][0]); } window.actionArguments = null; document.fire("ajaxplorer:afterApply-"+this.options.name); }, /** * Updates the action status on context change * @returns void */ fireContextChange: function(){ if(arguments.length < 4) return; var usersEnabled = arguments[0]; var crtUser = arguments[1]; var crtIsRecycle = arguments[2]; var crtInZip = arguments[3]; var crtIsRoot = arguments[4]; var crtAjxpMime = arguments[5] || ''; if(this.options.listeners["contextChange"]){ window.listenerContext = this; this.options.listeners["contextChange"].evalScripts(); } 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(this.context.allowedMimes.length){ if( !this.context.allowedMimes.include("*") && !this.context.allowedMimes.include(crtAjxpMime)){ 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(); }, /** * Upates the action status on selection change */ fireSelectionChange: function(){ if(this.options.listeners["selectionChange"]){ window.listenerContext = this; this.options.listeners["selectionChange"].evalScripts(); } if(arguments.length < 1 || this.contextHidden || !this.context.selection) { return; } var userSelection = arguments[0]; var bSelection = false; if(userSelection != null) { bSelection = !userSelection.isEmpty(); var bUnique = userSelection.isUnique(); var bFile = userSelection.hasFile(); var bDir = userSelection.hasDir(); var bRecycle = userSelection.isRecycle(); } var selectionContext = this.selectionContext; if(selectionContext.allowedMimes.size()){ if(selectionContext.behaviour == 'hidden') this.hide(); else this.disable(); } if(selectionContext.unique && !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((selectionContext.allowedMimes.size() && userSelection && !userSelection.hasMime(selectionContext.allowedMimes) && !selectionContext.allowedMimes.include('*')) && !(selectionContext.dir && bDir)){ if(selectionContext.behaviour == 'hidden') return this.hide(); else return this.disable(); } this.show(); this.enable(); }, /** * Parses an XML fragment to configure this action * @param xmlNode Node XML Fragment describing the action */ createFromXML:function(xmlNode){ this.options.name = xmlNode.getAttribute('name'); for(var i=0; i'; } }else if(processNode.nodeName == "clientListener" && processNode.firstChild){ this.options.listeners[processNode.getAttribute('name')] = ''; } } }else if(node.nodeName == "gui"){ this.options.text_id = node.getAttribute('text'); this.options.title_id = node.getAttribute('title'); this.options.text = MessageHash[node.getAttribute('text')] || 'not_found'; this.options.title = MessageHash[node.getAttribute('title')] || 'not_found'; this.options.src = node.getAttribute('src'); if(node.getAttribute('hasAccessKey') && node.getAttribute('hasAccessKey') == "true"){ this.options.accessKey = node.getAttribute('accessKey'); this.options.hasAccessKey = true; } if(node.getAttribute('specialAccessKey')){ this.options.specialAccessKey = node.getAttribute('specialAccessKey'); } for(var j=0; j'; } } } } if(!this.options.hasAccessKey) return; if(this.options.accessKey == '' || !MessageHash[this.options.accessKey] || this.options.text.indexOf(MessageHash[this.options.accessKey]) == -1) { this.options.accessKey == this.options.text.charAt(0); }else{ this.options.accessKey = MessageHash[this.options.accessKey]; } }, /** * Creates the submenu items */ buildSubmenuStaticItems : function(){ var menuItems = []; if(this.subMenuItems.staticItems){ this.subMenuItems.staticItems.each(function(item){ var itemText = MessageHash[item.text]; if(item.hasAccessKey && (item.hasAccessKey=='true' || item.hasAccessKey===true) && MessageHash[item.accessKey]){ itemText = this.getKeyedText(MessageHash[item.text],true,MessageHash[item.accessKey]); if(!this.subMenuItems.accessKeys) this.subMenuItems.accessKeys = []; this.manager.registerKey(MessageHash[item.accessKey],this.options.name, item.command); } menuItems.push({ name:itemText, alt:MessageHash[item.title], image:resolveImageSource(item.src, '/images/actions/ICON_SIZE', 22), isDefault:(item.isDefault?true:false), callback:function(e){this.apply([item]);}.bind(this) }); }, this); } this.subMenuItems.staticOptions = menuItems; }, /** * Caches some data for dynamically built menus */ prepareSubmenuDynamicBuilder : function(){ this.subMenuItems.dynamicBuilder = function(protoMenu){ setTimeout(function(){ if(this.subMenuItems.dynamicBuilderCode){ window.builderContext = this; this.subMenuItems.dynamicBuilderCode.evalScripts(); var menuItems = this.builderMenuItems || []; }else{ var menuItems = []; this.subMenuItems.dynamicItems.each(function(item){ var action = this.manager.actions.get(item['actionId']); if(action.deny) return; menuItems.push({ name:action.getKeyedText(), alt:action.options.title, image:resolveImageSource(action.options.src, '/images/actions/ICON_SIZE', 16), callback:function(e){this.apply();}.bind(action) }); }, this); } protoMenu.options.menuItems = menuItems; protoMenu.refreshList(); }.bind(this),0); }.bind(this); }, /** * Refresh icon image source * @param newSrc String The image source. Can reference an image library */ setIconSrc : function(newSrc){ this.options.src = newSrc; if($(this.options.name +'_button_icon')){ $(this.options.name +'_button_icon').src = resolveImageSource(this.options.src,this.__DEFAULT_ICON_PATH, 22); } }, /** * Refresh the action label * @param newLabel String the new label * @param newTitle String the new tooltip */ setLabel : function(newLabel, newTitle){ this.options.text = MessageHash[newLabel]; if($(this.options.name+'_button_label')){ $(this.options.name+'_button_label').update(this.getKeyedText()); } if(!newTitle) return; this.options.title = MessageHash[newTitle]; if($(this.options.name+'_button_icon')){ $(this.options.name+'_button_icon').title = this.options.title; } }, refreshInstances : function(){ $$('#action_instance_'+this.options.name).each(function(instance){ // Check img var img; if(instance.firstChild.nodeType == Node.ELEMENT_NODE && instance.firstChild.nodeName.toLowerCase()=="img"){ img = instance.firstChild.cloneNode(true); } instance.update(this.getKeyedText()); if(img){ instance.insert({top:img}); } }.bind(this)); }, /** * Grab its label from the i18n MessageHash */ refreshFromI18NHash : function(){ var text; var title; this.setLabel(this.options.text_id, this.options.title_id); }, /** * Return data necessary to build InfoPanel * @returns Hash */ toInfoPanel:function(){ return this.options; }, /** * Return necessary data to buid contextual menu * @returns Hash */ toContextMenu:function(){ return this.options; }, /** * Changes show/hide state */ hideForContext: function(){ this.hide(); this.contextHidden = true; }, /** * Changes show/hide state */ showForContext: function(){ this.show(); this.contextHidden = false; }, /** * Changes show/hide state * Notifies "hide" Event */ hide: function(){ this.deny = true; this.notify('hide'); }, /** * Changes show/hide state * Notifies "show" Event */ show: function(){ this.deny = false; this.notify('show'); }, /** * Changes enable/disable state * Notifies "disable" Event */ disable: function(){ this.deny = true; this.notify('disable'); }, /** * Changes enable/disable state * Notifies "enable" Event */ enable: function(){ this.deny = false; this.notify('enable'); }, /** * To be called when removing */ remove: function(){ // Remove all elements and forms from html this.elements.each(function(el){ $(el).remove(); }.bind(this)); this.elements = new Array(); if(this.options.formId && $('all_forms').select('[id="'+this.options.formId+'"]').length){ $('all_forms').select('[id="'+this.options.formId+'"]')[0].remove(); } }, /** * Create a text label with access-key underlined. * @param displayString String the label * @param hasAccessKey Boolean whether there is an accessKey or not * @param accessKey String The key to underline * @returns String */ getKeyedText: function(displayString, hasAccessKey, accessKey){ if(!displayString){ displayString = this.options.text; } if(!hasAccessKey){ hasAccessKey = this.options.hasAccessKey; } if(!accessKey){ accessKey = this.options.accessKey; } if(!hasAccessKey) return displayString; var keyPos = displayString.toLowerCase().indexOf(accessKey.toLowerCase()); if(keyPos==-1){ return displayString + ' (' + accessKey + ')'; } if(displayString.charAt(keyPos) != accessKey){ // case differ accessKey = displayString.charAt(keyPos); } returnString = displayString.substring(0,displayString.indexOf(accessKey)); returnString += ''+accessKey+''; returnString += displayString.substring(displayString.indexOf(accessKey)+1, displayString.length); return returnString; }, /** * Inserts Html FORM declared by manifest in the all_forms div. */ insertForm: function(){ if(!this.options.formCode || !this.options.formId) return; if($('all_forms').select('[id="'+this.options.formId+'"]').length) return; $('all_forms').insert(this.options.formCode); }, /** * Utilitary function to transform XML Node attributes into Object mapping keys. * @param object Object The target object * @param node Node The source node */ attributesToObject: function(object, node){ Object.keys(object).each(function(key){ if(node.getAttribute(key)){ value = node.getAttribute(key); if(value == 'true') value = true; else if(value == 'false') value = false; if(key == 'allowedMimes'){ if(value && value.split(',').length){ value = $A(value.split(',')); }else{ value = $A([]); } } this[key] = value; } }.bind(object)); } });