123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- /**
- * @file 所有UI组件的基类,通过它可以简单的快速的创建新的组件。
- * @name zepto.ui
- * @short zepto.ui
- * @desc 所有UI组件的基类,通过它可以简单的快速的创建新的组件。
- * @import core/zepto.js, core/zepto.extend.js
- */
- (function($, undefined) {
- var id = 1,
- _blankFn = function(){},
- tpl = '<%=name%>-<%=id%>',
- record = (function(){
- var data = {},
- id = 0,
- iKey = "GMUWidget"+(+ new Date()); //internal key.
- return function( obj, key, val){
- var dkey = obj[ iKey ] || ( obj[ iKey ] = ++id ),
- store = data[dkey] || (data[dkey] = {});
- !$.isUndefined(val) && (store[key] = val);
- $.isNull(val) && delete store[key];
- return store[ key ];
- }
- })();
-
- $.ui = $.ui || {
- version: '2.0.5',
- guid: _guid,
- /**
- * @name $.ui.define
- * @grammar $.ui.define(name, data[, superClass]) ⇒ undefined
- * @desc 定义组件,
- * - ''name'' 组件名称
- * - ''data'' 对象,设置此组件的prototype。可以添加属性或方法
- * - ''superClass'' 基类,指定此组件基于哪个现有组件,默认为Widget基类
- * **示例:**
- * <code type="javascript">
- * $.ui.define('helloworld', {
- * _data: {
- * opt1: null
- * },
- * enable: function(){
- * //...
- * }
- * });
- * </code>
- *
- * **定义完后,就可以通过以下方式使用了**
- *<code type="javascript">
- * var instance = $.ui.helloworld({opt1: true});
- * instance.enable();
- *
- * //或者
- * $('#id').helloworld({opt1:true});
- * //...later
- * $('#id').helloworld('enable');
- * </code>
- *
- * **Tips**
- * 1. 通过Zepto对象上的组件方法,可以直接实例话组件, 如: $('#btn').button({label: 'abc'});
- * 2. 通过Zepto对象上的组件方法,传入字符串this, 可以获得组件实例,如:var btn = $('#btn').button('this');
- * 3. 通过Zepto对象上的组件方法,可以直接调用组件方法,第一个参数用来指定方法名,之后的参数作为方法参数,如: $('#btn').button('setIcon', 'home');
- * 4. 在子类中,如覆写了某个方法,可以在方法中通过this.$super()方法调用父级方法。如:this.$super('enable');
- */
- define: function(name, data, superClass) {
- if(superClass) data.inherit = superClass;
- var Class = $.ui[name] = _createClass(function(el, options) {
- var obj = _createObject(Class.prototype, {
- _id: $.parseTpl(tpl, {
- name: name,
- id: _guid()
- })
- });
- obj._createWidget.call(obj, el, options,Class.plugins);
- return obj;
- }, data);
- return _zeptoLize(name, Class);
- },
- /**
- * @name $.ui.isWidget()
- * @grammar $.ui.isWidget(obj) ⇒ boolean
- * @grammar $.ui.isWidget(obj, name) ⇒ boolean
- * @desc 判断obj是不是widget实例
- *
- * **参数**
- * - ''obj'' 用于检测的对象
- * - ''name'' 可选,默认监测是不是''widget''(基类)的实例,可以传入组件名字如''button''。作用将变为obj是不是button组件实例。
- * @param obj
- * @param name
- * @example
- *
- * var btn = $.ui.button(),
- * dialog = $.ui.dialog();
- *
- * console.log($.isWidget(btn)); // => true
- * console.log($.isWidget(dialog)); // => true
- * console.log($.isWidget(btn, 'button')); // => true
- * console.log($.isWidget(dialog, 'button')); // => false
- * console.log($.isWidget(btn, 'noexist')); // => false
- */
- isWidget: function(obj, name){
- return obj instanceof (name===undefined ? _widget: $.ui[name] || _blankFn);
- }
- };
-
- /**
- * generate guid
- */
- function _guid() {
- return id++;
- };
- function _createObject(proto, data) {
- var obj = {};
- Object.create ? obj = Object.create(proto) : obj.__proto__ = proto;
- return $.extend(obj, data || {});
- }
- function _createClass(Class, data) {
- if (data) {
- _process(Class, data);
- $.extend(Class.prototype, data);
- }
- return $.extend(Class, {
- plugins: [],
- register: function(fn) {
- if ($.isObject(fn)) {
- $.extend(this.prototype,fn);
- return;
- }
- this.plugins.push(fn);
- }
- });
- }
- /**
- * handle inherit & _data
- */
- function _process(Class, data) {
- var superClass = data.inherit || _widget,
- proto = superClass.prototype,
- obj;
- obj = Class.prototype = _createObject(proto, {
- $factory: Class,
- $super: function(key) {
- var fn = proto[key];
- return $.isFunction(fn) ? fn.apply(this, $.slice(arguments, 1)) : fn;
- }
- });
- obj._data = $.extend({}, proto._data, data._data);
- delete data._data;
- return Class;
- }
- /**
- * 强制setup模式
- * @grammar $(selector).dialog(opts);
- */
- function _zeptoLize( name ) {
- $.fn[ name ] = function(opts) {
- var ret,
- obj,
- args = $.slice(arguments, 1);
- $.each( this, function( i, el ){
- obj = record( el, name ) || $.ui[name]( el, $.extend( $.isPlainObject(opts) ? opts : {}, {
- setup: true
- } ) );
- if ($.isString( opts )) {
- if (!$.isFunction( obj[ opts ] ) && opts !== 'this') {
- throw new Error(name + '组件没有此方法'); //当不是取方法是,抛出错误信息
- }
- ret = $.isFunction( obj[ opts ] ) ? obj[opts].apply(obj, args) : undefined;
- }
- if( ret !== undefined && ret !== obj || opts === "this" && ( ret = obj ) ) {
- return false;
- }
- ret = undefined;
- });
- //ret 为真就是要返回ui实例之外的内容
- //obj 'this'时返回
- //其他都是返回zepto实例
- //修改返回值为空的时,返回值不对的问题
- return ret !== undefined ? ret : this;
- };
- }
- /**
- * @name widget
- * @desc GMU所有的组件都是此类的子类,即以下此类里面的方法都可在其他组建中调用。
- */
- var _widget = function() {};
- $.extend(_widget.prototype, {
- _data: {
- status: true
- },
- /**
- * @name data
- * @grammar data(key) ⇒ value
- * @grammar data(key, value) ⇒ value
- * @desc 设置或者获取options, 所有组件中的配置项都可以通过此方法得到。
- * @example
- * $('a#btn').button({label: '按钮'});
- * console.log($('a#btn').button('data', 'label'));// => 按钮
- */
- data: function(key, val) {
- var _data = this._data;
- if ($.isObject(key)) return $.extend(_data, key);
- else return !$.isUndefined(val) ? _data[key] = val : _data[key];
- },
- /**
- * common constructor
- */
- _createWidget: function(el, opts,plugins) {
- if ($.isObject(el)) {
- opts = el || {};
- el = undefined;
- }
- var data = $.extend({}, this._data, opts);
- $.extend(this, {
- _el: el ? $(el) : undefined,
- _data: data
- });
- //触发plugins
- var me = this;
- $.each( plugins, function( i, fn ){
- var result = fn.apply( me );
- if(result && $.isPlainObject(result) ){
- var plugins = me._data.disablePlugin;
- if( !plugins || $.isString(plugins) && !~plugins.indexOf(result.pluginName) ){
- delete result.pluginName;
- $.each(result,function( key, val ){
- var orgFn;
- if((orgFn = me[key]) && $.isFunction( val ) ){
- me[key] = function(){
- me[key + 'Org'] = orgFn;
- return val.apply(me,arguments);
- }
- }else
- me[key] = val;
- });
- }
- }
- });
- // use setup or render
- if(data.setup) this._setup(el && el.getAttribute('data-mode'));
- else this._create();
- this._init();
- var me = this,
- $el = this.trigger('init').root();
- $el.on('tap', function(e) {
- (e['bubblesList'] || (e['bubblesList'] = [])).push(me);
- });
- record( $el[0], me._id.split('-')[0], me );
- },
- /**
- * @interface: use in render mod
- * @name _create
- * @desc 接口定义,子类中需要重新实现此方法,此方法在render模式时被调用。
- *
- * 所谓的render方式,即,通过以下方式初始化组件
- * <code>
- * $.ui.widgetName(options);
- * </code>
- */
- _create: function() {},
- /**
- * @interface: use in setup mod
- * @name _setup
- * @desc 接口定义,子类中需要重新实现此方法,此方法在setup模式时被调用。第一个行参用来分辨时fullsetup,还是setup
- *
- * <code>
- * $.ui.define('helloworld', {
- * _setup: function(mode){
- * if(mode){
- * //为fullsetup模式
- * } else {
- * //为setup模式
- * }
- * }
- * });
- * </code>
- *
- * 所谓的setup方式,即,先有dom,然后通过选择器,初始化Zepto后,在Zepto对象直接调用组件名方法实例化组件,如
- * <code>
- * //<div id="widget"></div>
- * $('#widget').widgetName(options);
- * </code>
- *
- * 如果用来初始化的element,设置了data-mode="true",组件将以fullsetup模式初始化
- */
- _setup: function(mode) {},
- /**
- * @name root
- * @grammar root() ⇒ value
- * @grammar root(el) ⇒ value
- * @desc 设置或者获取根节点
- * @example
- * $('a#btn').button({label: '按钮'});
- * console.log($('a#btn').button('root'));// => a#btn
- */
- root: function(el) {
- return this._el = el || this._el;
- },
- /**
- * @name id
- * @grammar id() ⇒ value
- * @grammar id(id) ⇒ value
- * @desc 设置或者获取组件id
- */
- id: function(id) {
- return this._id = id || this._id;
- },
- /**
- * @name destroy
- * @grammar destroy() ⇒ undefined
- * @desc 注销组件
- */
- destroy: function() {
- var me = this,
- $el;
- $el = this.trigger('destroy').off().root();
- $el.find('*').off();
- record( $el[0], me._id.split('-')[0], null);
- $el.off().remove();
- this.__proto__ = null;
- $.each(this, function(key) {
- delete me[key];
- });
- },
- /**
- * @name on
- * @grammar on(type, handler) ⇒ instance
- * @desc 绑定事件,此事件绑定不同于zepto上绑定事件,此On的this只想组件实例,而非zepto实例
- */
- on: function(ev, callback) {
- this.root().on(ev, $.proxy(callback, this));
- return this;
- },
- /**
- * @name off
- * @grammar off(type) ⇒ instance
- * @grammar off(type, handler) ⇒ instance
- * @desc 解绑事件
- */
- off: function(ev, callback) {
- this.root().off(ev, callback);
- return this;
- },
- /**
- * @name trigger
- * @grammar trigger(type[, data]) ⇒ instance
- * @desc 触发事件, 此trigger会优先把options上的事件回调函数先执行,然后给根DOM派送事件。
- * options上回调函数可以通过e.preventDefaualt()来组织事件派发。
- */
- trigger: function(event, data) {
- event = $.isString(event) ? $.Event(event) : event;
- var onEvent = this.data(event.type),result;
- if( onEvent && $.isFunction(onEvent) ){
- event.data = data;
- result = onEvent.apply(this, [event].concat(data));
- if(result === false || event.defaultPrevented){
- return this;
- }
- }
- this.root().trigger(event, data);
- return this;
- }
- });
- })(Zepto);
|