1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011, 2013, 2014, 2016 Synacor, Inc. 5 * 6 * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: https://www.zimbra.com/license 9 * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15 10 * have been added to cover use of software over a computer network and provide for limited attribution 11 * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B. 12 * 13 * Software distributed under the License is distributed on an "AS IS" basis, 14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. 15 * See the License for the specific language governing rights and limitations under the License. 16 * The Original Code is Zimbra Open Source Web Client. 17 * The Initial Developer of the Original Code is Zimbra, Inc. All rights to the Original Code were 18 * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015. 19 * 20 * All portions of the code are Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * Creates a callback which consists of at least a function reference, and possibly also 26 * an object to call it from. 27 * @constructor 28 * @class 29 * This class represents a callback function which can be called standalone, or from a 30 * given object. What the callback takes as arguments and what it returns are left to the 31 * client. 32 * 33 * @author Conrad Damon 34 * 35 * @param {object} obj the object to call the function from 36 * @param {function} func the callback function 37 * @param {array} args the default arguments 38 * 39 */ 40 AjxCallback = function(obj, func, args) { 41 if (arguments.length == 0) return; 42 43 if (typeof arguments[0] == "function") { 44 this.obj = null; 45 this.func = arguments[0]; 46 this.args = arguments[1]; 47 } 48 else { 49 this.obj = obj; 50 this.func = func; 51 this.args = args; 52 } 53 }; 54 55 AjxCallback.prototype.isAjxCallback = true; 56 AjxCallback.prototype.toString = function() { return "AjxCallback"; } 57 58 AjxCallback.NOP = new AjxCallback(function(){}); 59 60 /** 61 * Runs the callback function, from within the object if there is one. The 62 * called function passed arguments are the concatenation of the argument 63 * array passed to this object's constructor and the argument array passed 64 * to the <code>run</code> method. Whatever the called function returns is 65 * returned to the caller. 66 * 67 * @param {array} [arg1..argN] the first argument which will be appended to the argument 68 * array passed to this object's constructor. Any number of 69 * arguments may be passed to the <code>run</code> method. 70 */ 71 AjxCallback.prototype.run = 72 function(/* arg1 ... argN */) { 73 // combine original args with new ones 74 var args = []; 75 76 // sometimes we want to pass a null or false argument, so simply 77 // checking for if (this.args) won't do. 78 if (typeof this.args != "undefined") { 79 if (this.args!==null && this.args instanceof Array) { // IE mysteriously screws up the instanceof test if this.args is null 80 // NOTE: We must NOT use this.args directly if this method's 81 // params are gonna be pushed onto the array because it 82 // will change the original args! 83 args = arguments.length > 0 ? args.concat(this.args) : this.args; 84 } else { 85 args.push(this.args); 86 } 87 } 88 89 for (var i = 0; i < arguments.length; ++i) { 90 args.push(arguments[i]); 91 } 92 93 // invoke function 94 if (this.func) { 95 return this.func.apply(this.obj || window, args); 96 } 97 }; 98 99 /** 100 * This version of {@link AjxCallback.run} is here for {@link AjxDispatcher}, because it has a <code>run()</code> 101 * method in which it marshals arguments into an array. That leads to a problem 102 * in which the arguments are marshalled twice, so that by the time AjxDispatcher 103 * calls <code>callback.run(args)</code>, the args have already been collected into an array. 104 * Then when the function is invoked, it gets passed an actual array instead of the 105 * intended arg list. Calling <code>callback.run.apply(callback, args)</code> works on Firefox, 106 * but IE throws the error "Object expected", so we do this instead. 107 * 108 * @param {array} argList an array of arguments and treats them as an argument list, instead of as a single argument 109 * 110 * @private 111 */ 112 AjxCallback.prototype.run1 = 113 function(argList) { 114 // combine original args with new ones 115 var args = []; 116 117 // sometimes we want to pass a null or false argument, so simply 118 // checking for if (this.args) won't do. 119 if (typeof this.args != "undefined") { 120 if (this.args!==null && this.args instanceof Array) { 121 // NOTE: We must NOT use this.args directly if this method's 122 // params are gonna be pushed onto the array because it 123 // will change the original args! 124 args = arguments.length > 0 ? args.concat(this.args) : this.args; 125 } else { 126 args.push(this.args); 127 } 128 } 129 130 if (argList && argList.length) { 131 for (var i = 0; i < argList.length; ++i) { 132 args.push(argList[i]); 133 } 134 } 135 136 // invoke function 137 if (this.func) { 138 return this.func.apply(this.obj || window, args); 139 } 140 }; 141 142 /** 143 * This method returns a plain function that will call your supplied "func" in the context 144 * of "obj" and pass to it, in this order, any additional arguments that you 145 * pass to <code>simpleClosure</code> and the arguments that were passed to it at the call 146 * time. 147 * 148 * <p> 149 * An example should do: 150 * 151 * <pre> 152 * div.onclick = AjxCallback.simpleClosure(this.handler, this, "some data"); 153 * ... 154 * this.handler = function(data, event) { 155 * // event will be passed for DOM2 compliant browsers 156 * // and data is "some data" 157 * }; 158 * </pre> 159 * 160 * @param {function} func the function 161 * @param {object} obj the object to call the function from 162 * @param {array} [arg1...argN] any number of arguments 163 */ 164 AjxCallback.simpleClosure = function(func, obj) { 165 var args = []; 166 for (var i = 2; i < arguments.length; ++i) 167 args.push(arguments[i]); 168 return function() { 169 var args2 = []; 170 for (var i = 0; i < arguments.length; ++i) 171 args2.push(arguments[i]); 172 return func.apply(obj || this, args.concat(args2)); 173 }; 174 }; 175 176 AjxCallback.returnFalse = function() { return false; }; 177 178 AjxCallback.isNull = function(x) { return x == null; }; 179