1 /** 2 * 3 * 定义widget类 4 * @fileOverView core/widget 5 * @author <a href="mailto:zhang.gd@foxmail.com">Zhang Guangda</a> 6 * @date 2012-10-25 7 */ 8 define("core/widget", function() { 9 10 /** 11 * 获取默认的业务流 12 * @return {object} 业务流默认的一些方法 13 */ 14 var _getDefaultProcess = function() { 15 return { 16 start: $we.emptyFunction, 17 end: $we.emptyFunction, 18 checkSucc: $we.emptyFunction, 19 succ: $we.emptyFunction, 20 fail: $we.emptyFunction, 21 next: $we.emptyFunction, 22 prev: $we.emptyFunction, 23 options: $we.emptyFunction 24 }; 25 }; 26 27 /** 28 * 作为widget的初始化的类 29 * @param {String} name Widget的名称 30 * @param {Function} init 初始化函数 31 * @param {Function} run 初始化widget完毕后运行 32 * @param {Object} params 参数 33 * @param {Object} interfaces 对外的接口 34 * @param {Object} events 需要绑定的事件 35 * @param {Object} notifies 提供给Children使用的方法 36 * @param {Object} notifyTo 传递通知的对象 37 * @param {Object} inherit 传递继承自的对象 38 * @return {Object} 返回一个Widget类 39 */ 40 var widget = function(name, init, run, params, interfaces, events, notifies, process, notifyTo, inherit) { 41 // 管理所有内部的elements 42 this.node = {}; 43 // 管理内部的事件响应 44 this.events = {}; 45 // 管理内部提供给children的方法 46 this.notifies = {}; 47 // 业务流需要的方法 48 this.process = _getDefaultProcess(); 49 // 继承 50 this._super = {}; 51 52 // 设置notifyTo 53 if (notifyTo) this.setNotifyTo(notifyTo); 54 55 this.extend(inherit); 56 widget.extendMethod.call(this, interfaces, events, notifies, process, init, params); 57 if (typeof run == "function") { 58 run.apply(this, params); 59 } 60 }; 61 62 // 自定义的一些events储存在这里 63 widget.customizedEvents = {}; 64 65 // 注册好了的widget储存在这里 66 widget.store = {}; 67 68 widget.tmpDiv = document.createElement("div"); 69 70 71 widget.extendMethod = function(interfaces, events, notifies, process, init, params, bExtend) { 72 for (var s in events) { 73 this.events[s] = events[s]; 74 } 75 var _makeFunction = function(collection, funName) { 76 var me = this; 77 return function() { 78 return collection[funName].apply(me, arguments); 79 }; 80 }; 81 for (var funName in interfaces) { 82 if (typeof interfaces[funName] == "function") { 83 if (!this[funName] || !bExtend) 84 this[funName] = _makeFunction.call(this, interfaces, funName); 85 if (bExtend) 86 this._super[funName] = _makeFunction.call(this, interfaces, funName); 87 } 88 } 89 for (var funName in notifies) { 90 if (typeof notifies[funName] == "function") { 91 this.notifies[funName] = _makeFunction.call(this, notifies, funName); 92 } 93 } 94 95 if (!bExtend) { 96 for (var funName in process) { 97 if (typeof process[funName] == "function") { 98 this.process[funName] = _makeFunction.call(this, process, funName); 99 } 100 } 101 } 102 103 if (typeof init == "function") { 104 init.apply(this, params); 105 } 106 }; 107 108 widget.getEvents = function(action, el, nodes) { 109 var me = this; 110 if (!nodes) { 111 nodes = this.node; 112 } 113 if (typeof this.events[action] == "function") { 114 return function(e) { 115 return !(me.events[action].call(me, e, el, nodes) === false); 116 } 117 } 118 return null; 119 }; 120 121 widget.bindEvents = function(el, evt, action, nodes) { 122 evt = evt.toLowerCase(); 123 if ($.inArray(evt, 124 ("blur focus focusin focusout load resize scroll unload click dblclick " + 125 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + 126 "change select submit keydown keypress keyup error contextmenu").split(" ")) == -1) return; 127 128 var callback = widget.getEvents.call(this, action, el, nodes); 129 if (callback) { 130 $(el).on(evt, callback); 131 } 132 }; 133 134 widget.bindCustomizedEvents = function(el, evt, param, nodes) { 135 if (typeof widget.customizedEvents[evt] == "function") { 136 if (!nodes) nodes = this.node; 137 widget.customizedEvents[evt].call(this, el, param, nodes); 138 } 139 }; 140 141 142 widget.getWidgetConfig = function(name) { 143 var ret = widget.store[name]; 144 if (!ret) { 145 $we.Exception(name + " is not registered"); 146 return false; 147 } 148 if (!ret.interfaces) ret.interfaces = {}; 149 if (!ret.events) ret.events = {}; 150 if (!ret.notifies) ret.notifies = {}; 151 if (!ret.process) ret.process = _getDefaultProcess(); 152 return ret; 153 }; 154 155 widget.emNode = function(node, nodes, group) { 156 if (group) { 157 group.node = {}; 158 } else { 159 group = this; 160 } 161 if (!nodes) { 162 try { 163 nodes = node.getElementsByTagName("em"); 164 } catch (e) { 165 $we.Exception("no nodes specified!"); 166 return; 167 } 168 } 169 var toBind = []; 170 for (var i = 0; nodes && i < nodes.length; ++i) { 171 var text = $(nodes[i]).attr("attr"); 172 if (text && typeof text == "string") { 173 var arr = text.split(";"), 174 el = nodes[i]; 175 for (var j = 0; j < arr.length; ++j) { 176 var t = arr[j].split(":"); 177 if (1 == t.length && t[0]) { 178 group.node[t[0]] = el; 179 } 180 if (2 == t.length) { 181 if ("inner" == t[0]) { 182 group.node[t[1]] = el; 183 } else { 184 // 处理完元素element相关内容,开始处理events和customizedEvents 185 toBind.push({ 186 el: el, 187 key: t[0], 188 value: t[1] 189 }); 190 } 191 } 192 } 193 } 194 } 195 for (var i = 0; i < toBind.length; ++i) { 196 widget.bindEvents.call(this, toBind[i].el, toBind[i].key, toBind[i].value, group); 197 widget.bindCustomizedEvents.call(this, toBind[i].el, toBind[i].key, toBind[i].value, group); 198 } 199 }; 200 201 widget.setNotifyTo = function(obj) { 202 if (!obj._notifyMembers) obj._notifyMembers = []; 203 obj._notifyMembers.push(this); 204 this._notifyTo = obj; 205 return this; 206 }; 207 208 widget.notify = function(type) { 209 var param = []; 210 for (var i = 1; i < arguments.length; ++i) { 211 param.push(arguments[i]); 212 } 213 var notifyTo = this._notifyTo; 214 while (notifyTo) { 215 if (notifyTo.notifies && typeof notifyTo.notifies[type] == "function") { 216 return notifyTo.notifies[type].apply(notifyTo, param); 217 } 218 notifyTo = notifyTo._notifyTo; 219 } 220 }; 221 222 widget.extend = function(p, params) { 223 if (typeof p == "string") p = [p]; 224 if (!$.isArray(p)) return this; 225 if (!$.isArray(params)) params = [params]; 226 227 for (var i = 0; i < p.length; ++i) { 228 var c = widget.getWidgetConfig(p[i]); 229 if (!c) continue; 230 widget.extendMethod.call(this, c.interfaces, c.events, c.notifies, c.process, c.init, params, true); 231 } 232 return this; 233 }; 234 235 widget.enableNode = function(node, group){ 236 // node最好还是element,否则可能会有问题 237 if (typeof node == "string") node = $("#" + node)[0]; 238 if (!node) return; 239 240 var attrs = $(node).find("[attr]").toArray(); 241 attrs.push(node); 242 this.emNode(node, attrs, group); 243 }; 244 245 widget.domOperation = function(type, node, str, conf, group, bNoEnable) { 246 if (typeof node == "string") node = $("#" + node)[0]; 247 if (!node) return; 248 249 str = (""+str).replace(/\$(\w+)\$/g, function(a, b) { 250 return typeof conf[b] != "undefined" ? conf[b] : "$" + b + "$" 251 }); 252 253 $(widget.tmpDiv).empty(); 254 $(widget.tmpDiv).append(str); 255 if (!bNoEnable) { 256 this.enableNode(widget.tmpDiv, group); 257 } 258 259 var childNodes = widget.tmpDiv.childNodes; 260 if(node){ 261 switch (type) { 262 case "append": 263 while(childNodes.length){ 264 node.appendChild(childNodes[0]); 265 } 266 break; 267 case "after": 268 while(childNodes.length){ 269 $(node).after(childNodes[0]); 270 } 271 break; 272 case "before": 273 while(childNodes.length){ 274 $(node).before(childNodes[0]); 275 } 276 break; 277 } 278 279 } 280 }; 281 282 widget.append = function(node, str, conf, group, bNoEnable) { 283 widget.domOperation.call(this, "append", node, str, conf, group, bNoEnable); 284 }; 285 286 widget.after = function(node, str, conf, group, bNoEnable) { 287 widget.domOperation.call(this, "after", node, str, conf, group, bNoEnable); 288 }; 289 290 widget.before = function(node, str, conf, group, bNoEnable) { 291 widget.domOperation.call(this, "before", node, str, conf, group, bNoEnable); 292 }; 293 294 widget.prototype = { 295 // 这4个方法是最最基础的方法 296 setNotifyTo: widget.setNotifyTo, 297 extend: widget.extend, 298 notify: widget.notify, 299 emNode: widget.emNode, 300 // 以下的方法都是基于上面的方法实现出来的 301 enableNode: widget.enableNode, 302 append: widget.append, 303 after: widget.after, 304 before: widget.before 305 }; 306 307 /** 308 * widget类 309 * @class widget类 310 */ 311 $we.widget = { 312 /** 313 * 新增一个widget类的方法 314 * @param {String} name 方法名称 315 * @param {Function} func 函数 316 */ 317 addWidgetFunc: function(name, func) { 318 widget.prototype[name] = func; 319 }, 320 /** 321 * 新增一个widget类的事件 322 * @param {String} name 事件名称 323 * @param {Function} func 函数 324 */ 325 addCustomizedEvents: function(name, func) { 326 widget.customizedEvents[name] = func; 327 }, 328 /** 329 * 使用一个组件 330 * @param {Object} param 参数 331 */ 332 add: function(param) { 333 if (typeof param == "string") { 334 param = { 335 name: param 336 }; 337 } 338 var obj = widget.getWidgetConfig(param.name), 339 params = []; 340 if (!obj) { 341 $we.Exception(param.name + " is not registered"); 342 return; 343 } 344 for (var i = 1; i < arguments.length; ++i) { 345 params.push(arguments[i]); 346 } 347 348 var el = new widget( 349 param.name, 350 obj.init, 351 obj.run, 352 params, 353 obj.interfaces, 354 obj.events, 355 obj.notifies, 356 obj.process, 357 param && param.notifyTo, 358 param && param.extend 359 ); 360 return el; 361 }, 362 /** 363 * 注册一个组件 364 * @param {String} name 组件名称 365 * @param {Object} obj 组件配置 366 */ 367 reg: function(name, obj) { 368 widget.store[name] = obj; 369 }, 370 /** 371 * 支持AMD规范的组件返回值 372 * @param {String} name 需要返回的组件名称 373 * @return {Function} 可以实例化一个组件的函数 374 */ 375 amd: function(name) { 376 return function() { 377 var args = [name].concat($(arguments).toArray()); 378 return $we.widget.add.apply(this, args); 379 }; 380 } 381 }; 382 383 $we.widget.addCustomizedEvents("hover", function(el, param) { 384 $(el).mouseover(function(){ 385 $(el).addClass(param); 386 }).mouseout(function(){ 387 $(el).removeClass(param); 388 }); 389 }); 390 391 $we.widget.addWidgetFunc("appendHTML", function(str, node, conf, group) { 392 this.append(node, str, conf, group); 393 }); 394 395 // add as jq plugin 396 $.fn.addWidget = function() { 397 var params = []; 398 if (this.length && this[0].name) { 399 params.push(this[0]); 400 } else if (this.selector) { 401 params.push(this.selector); 402 } else { 403 $we.Exception("invalid params of using addWidget"); 404 } 405 406 for (var i=0, l=arguments.length; i<l; ++i) { 407 params.push(arguments[i]); 408 } 409 410 return $we.widget.add.apply(window, params); 411 }; 412 413 return $we.widget; 414 415 });