1 var func = require("./functions"), 2 obj = require("./object"), 3 define = require("../define").define; 4 5 var comb = exports; 6 7 8 var wrapper = function() { 9 return function() { 10 var c = arguments.callee, listeners = c.__listeners, func = c.func, r; 11 if (func) { 12 r = func.apply(this, arguments); 13 } 14 for (var i = 0; i < listeners.length; i++) { 15 var lis = listeners[i]; 16 if (lis) { 17 lis.apply(this, arguments); 18 } 19 } 20 return r; 21 22 } 23 }; 24 25 26 var listeners = {}; 27 obj.merge(comb, { 28 /**@lends comb*/ 29 /** 30 * Disconnects a listener to a function 31 * @param {handle} A handle returned from comb.connect 32 */ 33 disconnect : function(handle) { 34 if (handle && handle.length == 3) { 35 var obj = handle[0], method = handle[1], cb = handle[2]; 36 if (typeof method != "string") throw "comb.disconnect : When calling disconnect the method must be string"; 37 var scope = obj || global, ls; 38 if (typeof scope[method] == "function") { 39 ls = scope[method].__listeners; 40 if (ls && cb-- > 0) { 41 //we dont want to splice it because our indexing will get off 42 ls[cb] = null; 43 } 44 } else { 45 throw new Error("unknown method " + method + " in object " + obj); 46 } 47 } else { 48 throw "comb.disconnect : invalid handle" 49 } 50 }, 51 52 /** 53 * Function to listen when other functions are called 54 * 55 * @example 56 * 57 * comb.connect(obj, "event", myfunc); 58 * comb.connect(obj, "event", "log", console); 59 * 60 * @param {Object} obj the object in which the method you are connection to resides 61 * @param {String} method the name of the method to connect to 62 * @param {Function} cb the function to callback 63 * @param {Object} [scope] the scope to call the specified cb in 64 * 65 * @returns {Array} handle to pass to {@link comb.disconnect} 66 */ 67 connect : function(obj, method, cb, scope) { 68 var index; 69 if (typeof method != "string") throw new Error("When calling connect the method must be string"); 70 if (!func.isFunction(cb)) throw new Error("When calling connect callback must be a string"); 71 var scope = obj || global, listeners, newMethod; 72 if (typeof scope[method] == "function") { 73 listeners = scope[method].__listeners; 74 if (!listeners) { 75 newMethod = wrapper(); 76 newMethod.func = obj[method]; 77 listeners = (newMethod.__listeners = []); 78 scope[method] = newMethod; 79 } 80 index = listeners.push(cb); 81 } else { 82 throw new Error("unknow method " + method + " in object " + obj); 83 } 84 return [obj, method, index]; 85 }, 86 87 88 /** 89 * Broadcasts an event to all listeners 90 * NOTE : the function takes a variable number of arguments 91 * i.e. all arguments after the topic will be passed to the listeners 92 * 93 * @example 94 * 95 * 96 * comb.broadcast("hello", "hello world"); 97 * //the args "hello" and "world" will be passed to any listener of the topic 98 * //"hello" 99 * comb.broadcast("hello", "hello", "world"); 100 * 101 * @param {String} topic the topic to brodcast 102 * @param params the information to bradcast 103 */ 104 broadcast : function() { 105 var args = Array.prototype.slice.call(arguments); 106 var topic = args.splice(0, 1)[0]; 107 if (topic) { 108 var list = listeners[topic]; 109 if (list) { 110 for (var i = list.length - 1; i >= 0; i--) { 111 var han = list[i], cb = han.cb; 112 if (cb) { 113 cb.apply(this, args); 114 } 115 } 116 } 117 } 118 }, 119 120 /** 121 * Listen for the broadcast of certain events 122 * 123 * @example 124 * comb.listen("hello", function(arg1, arg2){ 125 * console.log(arg1); 126 * console.log(arg2); 127 * }); 128 * 129 * @param {String} topic the topic to listen for 130 * @param {Function} callback the funciton to call when the topic is published 131 * 132 * @returns a handle to pass to {@link comb.unListen} 133 */ 134 listen : function(topic, callback) { 135 if (!func.isFunction(callback)) throw new Error("callback must be a function"); 136 var handle = { 137 topic : topic, 138 cb : callback, 139 pos : null 140 }; 141 var list = listeners[topic]; 142 if (!list) { 143 list = (listeners[topic] = []); 144 } 145 list.push(handle); 146 handle.pos = list.length - 1; 147 return handle; 148 }, 149 150 /** 151 * Disconnects a listener 152 * 153 * @param handle a handle returned from {@link comb.listen} 154 */ 155 unListen : function(handle) { 156 if (handle) { 157 var topic = handle.topic, list = listeners[topic]; 158 if (list) { 159 for (var i = list.length - 1; i >= 0; i--) { 160 if (list[i] == handle) { 161 list.splice(i, 1); 162 } 163 } 164 if (!list.length) { 165 delete listeners[topic]; 166 } 167 } 168 } 169 } 170 171 }); 172 173