Ruby's Louvre

每天学习一点点算法

导航

mass Framework event模块 v4

event.js


//==========================================
//  事件模块(包括伪事件对象,事件绑定与事件代理)
//==========================================
$.define("event",document.dispatchEvent ?  "node" : "node,event_fix",function(){
    // $.log("已加载target模块")
    var rhoverHack = /(?:^|\s)hover(\.\S+)?\b/,  rmapper = /(\w+)_(\w+)/g,
    rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, revent = /(^|_|:)([a-z])/g
    function addCallback(queue, obj){//添加回调包到列队中
        var check = true, fn = obj.callback;
        for ( var i = 0, el; el = queue[i++]; ) {
            if( el.callback === fn ){
                check = false;
                break;
            }
        }
        if( check ){
            queue.push(obj);
        }
    }
    function quickIs( elem, m ) {
        var attrs = elem.attributes || {};
        return (
            (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
            (!m[2] || (attrs.id || {}).value === m[2]) &&
            (!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))
            );
    }
    //如果不存在添加一个
    var facade = $.event = $.event || {};
    //添加或增强二级属性eventAdapter
    $.Object.merge(facade,{
        eventAdapter:{
            focus: {
                delegateType: "focusin"
            },
            blur: {
                delegateType: "focusout"
            },
            beforeunload: {
                setup: function(src, _, _, fn ) {
                    // We only want to do this special case on windows
                    if ( $.type(src, "Window") ) {
                        src.onbeforeunload = fn;
                    }
                },
                teardown: function( src, _, _, fn ) {
                    if ( src.onbeforeunload === fn ) {
                        src.onbeforeunload = null;
                    }
                }
            }
        }
    });
    var eventAdapter  = $.event.eventAdapter;
    $.mix(facade,{
        bind : function( hash ){
            //它将在原生事件派发器或任何能成为事件派发器的普通JS对象添加一个名叫uniqueNumber的属性,用于关联一个缓存体,
            //把需要的数据储存到里面,而现在我们就把一个叫events的对象储放都它里面,
            //而这个event的表将用来放置各种事件类型与对应的回调函数
            if(arguments.length > 1 ){
                throw "$.event bind method only need one argument, and it's a hash!"
            }
            var target = this, DOM =  $[ "@target" ] in target, events = $._data( target),
            types = hash.type, fn = hash.callback,selector = hash.selector, callback;
            if(target.nodeType === 3 || target.nodeType === 8 || !events){
                return
            }
            hash.uuid =  $.getUid(fn); //确保UUID,bag与callback的UUID一致
            if( DOM ){ //处理DOM事件
                callback = events.callback ||  (events.callback = function( e ) {
                    return ((e || event).type !== facade.fireType ) ? facade.dispatch.apply( callback.target, arguments ) : void 0;
                });
                callback.target = target;
                types = types.replace( rhoverHack, "mouseover$1 mouseout$1" )
            }
            events = events.events || (events.events = {});
            //对多个事件进行绑定
            types.replace( $.rword, function( old ){
                var
                tns = rtypenamespace.exec( old ) || [],//"focusin.aaa.bbb"
                namespace = ( tns[2] || "" ).split( "." ).sort(),//取得命名空间 "aaa.bbb"
                adapter = DOM && eventAdapter[ tns[1] ] || {},// focusin -> focus
                type = (selector ? adapter.delegateType : adapter.bindType ) || tns[1],//focus

                queue = events[ type ] = events[ type ] ||  [],  //创建事件队列
                item = $.mix({
                    type: type,
                    origType: tns[1],
                    namespace: namespace.join(".")
                }, hash, false);
                //只有原生事件发送器才能进行DOM level2 多投事件绑定
                if( DOM && !queue.length  ){
                    adapter = eventAdapter[ type ] || {};
                    if (!adapter.setup || adapter.setup( target, selector, item.origType, callback ) === false ) {
                        // 为此元素这种事件类型绑定一个全局的回调,用户的回调则在此回调中执行
                        $.bind(target, type, callback, !!selector)
                    }
                }
           
                addCallback( queue, item );//同一事件不能绑定重复回调
            });
            return this;
        },
        //外部的API已经确保typesr至少为空字符串
        unbind: function( hash, mappedTypes  ) {
            var target = this, events = $._data( target, "events");
            if(!events ) return;
            var types = hash.type || "", selector = hash.selector, fn = hash.callback,
            tns, type, origType, namespace, origCount, DOM =  $["@target"] in target,
            j, adapter, queue, item;
            //将types进行映射并转换为数组
            types = DOM ? types.replace( rhoverHack, "mouseover$1 mouseout$1" ) : types;
            types =  types.match( $.rword ) || [];
            for (var t = 0; t < types.length; t++ ) {
                //"aaa.bbb.ccc" -> ["aaa.bbb.ccc", "aaa", "bbb.ccc"]
                tns = rtypenamespace.exec( types[t] ) || []
                origType = type = tns[1];
                namespace = tns[2];
                // 如果types只包含命名空间,则去掉所有拥有此命名空间的事件类型的回调
                if ( !type  ) {
                    for ( j in events ) {
                        facade.unbind.call( target, {
                            type: j + types[t],//说明这个types[t]为命名空间
                            selector: selector,
                            callback: fn
                        }, true );
                    }
                    continue;
                }
                //如果使用事件冒充则找到其正确事件类型
                adapter = eventAdapter[ type ] || {};
                type = ( selector ? adapter.delegateType: adapter.bindType ) || type;
                queue =  events[ type ] || [];
                origCount = queue.length;
                namespace = namespace ? new RegExp("(^|\\.)" + namespace.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
                //  namespace =  namespace?  namespace.split( "." ).sort().join(".") : null;
                //只有指定了命名空间,回调或选择器才能进入此分支
                if ( fn || namespace || selector ) {
                    for ( j = 0; j < queue.length; j++ ) {
                        item = queue[ j ];
                        if ( ( mappedTypes || origType === item.origType ) &&
                            ( !fn || fn.uuid === item.uuid ) &&//如果指定了回调,只检测其UUID
                            ( !namespace || namespace.test( item.namespace ) ) &&//如果指定了命名空间
                            ( !selector || selector === item.selector || selector === "**" && item.selector ) ) {
                            queue.splice( j--, 1 );
                        }
                    }
                } else {
                    //移除此类事件的所有回调
                    queue.length = 0;
                }
                if ( DOM && (queue.length === 0 && origCount !== queue.length) ) {//如果在回调队列的长度发生变化时才进行此分支
                    if ( !adapter.teardown || adapter.teardown( target, selector, origType, fn ) === false ) {
                        $.unbind( target, type, $._data( target, "callback") );
                    }
                    delete events[ type ];
                }
            }
            if( $.isEmptyObject( events ) ){
                fn = $.removeData( target,"callback") ;
                fn.target = null;
                $.removeData( target, "events") ;
            }
            return this;
        },

        fire: function( event ){//event的类型可能是字符串,原生事件对象,伪事件对象
            var target = this, namespace = [], type = event.type || event;
            if(!isFinite(event.mass)){
                event = new jEvent(event);
                if( ~type.indexOf( "." ) ) {//处理命名空间
                    namespace = type.split(".");
                    type = namespace.shift();
                    namespace.sort();
                    event.namespace = namespace.join( "." );
                    event.namespace_re = event.namespace ? new RegExp("(^|\\.)" + namespace.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
                }
                event.target = target;
            }
            var args = [ event ].concat( $.slice(arguments,1) );
            if( $["@target"] in target){
                var cur = target,  ontype = "on" + type;
                do{//模拟事件冒泡与执行内联事件
                    if( ($._data(cur,"events")|| {})[type] ){
                        facade.dispatch.apply( cur, args );
                    }
                    if (cur[ ontype ] && cur[ ontype ].call(cur) === false) {
                        event.preventDefault();
                    }
                    cur = cur.parentNode ||
                    cur.ownerDocument ||
                    cur === target.ownerDocument && window;
                } while ( cur && !event.isPropagationStopped );
                if ( !event.isDefaultPrevented ) {//模拟默认行为 click() submit() reset() focus() blur()
                    var old;//在opera 中节点与window都有document属性
                    if (ontype && target[ type ] && ((type !== "focus" && type !== "blur") || target.offsetWidth !== 0) && !target.eval) {
                        old = target[ ontype ];
                        if (old) {   // 不用再触发内联事件
                            target[ ontype ] = null;
                        }
                        facade.fireType = type;
                        target[ type ]();
                    }
                    delete facade.fireType ;
                    if ( old ) {
                        target[ ontype ] = old;
                    }
                }

            }else{//普通对象的自定义事件
                facade.dispatch.apply(target, args);
            }
            return this;
        },
        filter: function( cur, parent, expr ){
            var matcher = typeof expr === "function"? expr : expr.input ? quickIs : $.match
            for ( ; cur != parent; cur = cur.parentNode || parent ) {
                if(matcher(cur, expr))
                    return true
            }
            return false;
        },
        dispatch: function( e ) {
            var win = ( this.ownerDocument || this.document || this ).parentWindow || window,
            event = facade.fix( e || win.event ),
            queue = $._data(this,"events");//这个其实是对象events
            if (  queue ) {
                queue = queue[ event.type] || [];//到此处时才是数组
                event.currentTarget = this;
                var src = event.target,args = [event].concat($.slice(arguments,1)), result;
                //复制数组以防影响下一次的操作
                queue = queue.concat();
                //开始进行拆包操作
                for ( var i = 0, item; item = queue[i++]; ) {
                    //如果是事件代理,确保元素处于enabled状态,并且满足过滤条件
                    if ( !src.disabled && !(event.button && event.type === "click")
                        && (!item.selector  || facade.filter(src, this, item.selector))
                        && (!event.namespace || event.namespace_re.test( item.namespace ) ) ) {
                        //取得回调函数
                        event.type = item.origType;
                        result = item.callback.apply( item.selector ? src : this, args );
                        item.times--;
                        if(item.times === 0){
                            facade.unbind.call( this, item)
                        }
                        if ( result !== void 0 ) {
                            event.result = result;
                            if ( result === false ) {
                                event.preventDefault();
                                event.stopPropagation();
                            }
                        }
                        if ( event.isImmediatePropagationStopped ) {
                            break;
                        }
                    }
                }
            }

            return event.result;
        },
        _dispatch: function( src, type, e ){
            e = facade.fix( e );
            e.type = type;
            for(var i in src){
                if(src.hasOwnProperty(i)){
                    facade.dispatch.call( src[ i ], e );
                }
            }
        },
        fix: function( event ){
            if( !isFinite(event.mass) ){
                var originalEvent = event
                event = new jEvent(originalEvent);
                for( var prop in originalEvent ){
                    //去掉所有方法与常量
                    if( typeof originalEvent[prop] !== "function" && prop !== "type" ){
                        if(/^[A-Z_]+$/.test(prop))
                            continue
                        event[prop] = originalEvent[prop]
                    }
                }
                //如果不存在target属性,为它添加一个
                if ( !event.target ) {
                    event.target = event.srcElement || document;
                }
                //safari的事件源对象可能为文本节点,应代入其父节点
                if ( event.target.nodeType === 3 ) {
                    event.target = event.target.parentNode;
                }
                // 处理鼠标事件
                if( /^(?:mouse|contextmenu)|click/.test(event.type) ){
                    //如果不存在pageX/Y则结合clientX/Y做一双出来
                    if ( event.pageX == null && event.clientX != null ) {
                        var doc = event.target.ownerDocument || document,
                        html = doc.documentElement, body = doc.body;
                        event.pageX = event.clientX + (html && html.scrollLeft || body && body.scrollLeft || 0) - (html && html.clientLeft || body && body.clientLeft || 0);
                        event.pageY = event.clientY + (html && html.scrollTop  || body && body.scrollTop  || 0) - (html && html.clientTop  || body && body.clientTop  || 0);
                    }
                    //如果不存在relatedTarget属性,为它添加一个
                    if ( !event.relatedTarget && event.fromElement ) {
                        event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
                    }
                    //标准浏览判定按下鼠标哪个键,左1中2右3
                    var button = event.button
                    //IE event.button的意义
                    //0:没有键被按下 1:按下左键 2:按下右键 3:左键与右键同时被按下 4:按下中键 5:左键与中键同时被按下 6:中键与右键同时被按下 7:三个键同时被按下
                    if ( !event.which && isFinite(button) ) {
                        event.which  = [0,1,3,0,2,0,0,0][button];//0现在代表没有意义
                    }
                }
                if ( event.which == null ) {//处理键盘事件
                    event.which = event.charCode != null ? event.charCode : event.keyCode;
                }
                if( window.Touch && event.touches && event.touches[0] ){
                    $.log("fix touch pageXY")
                    event.pageX = event.touches[0].pageX
                    event.pageY = event.touches[0].pageY
                }
                //处理滚轮事件
                if( event.type === "mousewheel" ){
                    if ("wheelDelta" in originalEvent){
                        var delta = originalEvent.wheelDelta/120;
                        //opera 9x系列的滚动方向与IE保持一致,10后修正
                        if(top.opera && opera.version() < 10)
                            delta = -delta;
                        event.wheelDelta = Math.round(delta); //修正safari的浮点 bug
                    }else if("detail" in originalEvent){
                        event.wheelDelta = -event.detail/3;
                    }
                }
                // 处理组合键
                if ( event.metaKey === void 0 ) {
                    event.metaKey = event.ctrlKey;
                }
            }
            return event;
        }
    });

    var jEvent = $.Event = function ( event ) {
        this.originalEvent = event.type ? event: {};
        this.type = (event.type || event).replace(/\..*/g,"");
        this.timeStamp  = Date.now();
        this.mass = $.mass;//用于判定是否为伪事件对象
    };
    // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
    jEvent.prototype = {
        constructor: jEvent,
        //http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/events.html#Conformance
        toString: function(){
            return "[object Event]"
        },
        preventDefault: function() {
            this.isDefaultPrevented = true;
            var e = this.originalEvent;
            // 如果存在preventDefault 那么就调用它
            if ( e.preventDefault ) {
                e.preventDefault();
            }
            // 如果存在returnValue 那么就将它设为false
            e.returnValue = false;
            return this;
        },
        stopPropagation: function() {
            this.isPropagationStopped = true;
            var e = this.originalEvent;
            // 如果存在preventDefault 那么就调用它
            if ( e.stopPropagation ) {
                e.stopPropagation();
            }
            // 如果存在returnValue 那么就将它设为true
            e.cancelBubble = true;
            return this;
        },
        stopImmediatePropagation: function() {
            this.isImmediatePropagationStopped = true;
            this.stopPropagation();
            return this;
        }
    };
    var types = "contextmenu,click,dblclick,mouseout,mouseover,mouseenter,mouseleave,mousemove,mousedown,mouseup,mousewheel," +
    "abort,error,load,unload,resize,scroll,change,input,select,reset,submit,input,"+"blur,focus,focusin,focusout,"+"keypress,keydown,keyup"
  
    //事件派发器的接口
    //实现了这些接口的对象将具有注册事件和广播事件的功能
    //http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget
    $.EventTarget = {
        uniqueNumber : $.getUid({}),
        defineEvents : function( names ){
            var events = [];
            if(typeof names == "string"){
                events = names.match( $.rword ) || [];
            }else if($.isArray(names)){
                events = names;
            }
            events.forEach(function(name){
                var method = 'on'+name.replace(revent,function($, $1, $2) {
                    return $2.toUpperCase();
                });
                if (!(method in this)) {
                    this[method] = function() {
                        return $.fn.on.apply(this, [].concat.apply([name], arguments));
                    };
                }
            },this);
        }
    };
    "bind_on,unbind_off,fire_fire".replace( rmapper,function(_, type, mapper){
        $.EventTarget[ type ] = function(){
            $.fn[ mapper ].apply(this, arguments);
            return this;
        }
    });
    $.eventSupport = function( eventName,el ) {
        el = el || document.createElement("div");
        eventName = "on" + eventName;
        var ret = eventName in el;
        if ( el.setAttribute && !ret ) {
            el.setAttribute( eventName, "" );
            ret = typeof el[ eventName ] === "function";
            el.removeAttribute(eventName);
        }
        el = null;
        return ret;
    };
    /**
用于在标准浏览器下模拟mouseenter与mouseleave
现在除了IE系列支持mouseenter/mouseleave/focusin/focusout外
opera11,FF10也支持这四个事件,同时它们也成为w3c DOM3 Event的规范
详见http://www.filehippo.com/pl/download_opera/changelog/9476/
http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html
 */
    if( !+"\v1" || !$.eventSupport("mouseenter")){
        "mouseenter_mouseover,mouseleave_mouseout".replace(rmapper, function(_, type, mapper){
            eventAdapter[ type ]  = {
                setup: function( src ){//使用事件冒充
                    $._data( src, type+"_handle", $.bind( src, mapper, function( e ){
                        var parent = e.relatedTarget;
                        try {
                            while ( parent && parent !== src ) {
                                parent = parent.parentNode;
                            }
                            if ( parent !== src ) {
                                facade._dispatch( [ src ], type, e );
                            }
                        } catch(err) { };
                    }));
                },
                teardown: function(){
                    $.unbind( this, mapper, $._data( type+"_handle" ) );
                }
            };
        });
    }
    //在标准浏览器里面模拟focusin
    if( !$.eventSupport("focusin") ){
        "focusin_focus,focusout_blur".replace(rmapper, function(_,type, mapper){
            var notice = 0, focusinNotify = function (e) {
                var src = e.target
                do{//模拟冒泡
                    var events = $._data( src, "events" );
                    if(events && events[ type ]){
                        facade._dispatch( [ src ], type, e );
                    }
                } while (src = src.parentNode );
            }
            eventAdapter[ type ] = {
                setup: function( ) {
                    if ( notice++ === 0 ) {
                        document.addEventListener( mapper, focusinNotify, true );
                    }
                },
                teardown: function() {
                    if ( --notice === 0 ) {
                        document.removeEventListener( mapper, focusinNotify, true );
                    }
                }
            };
        });
    }
    try{
        //FF需要用DOMMouseScroll事件模拟mousewheel事件
        document.createEvent("MouseScrollEvents");
        eventAdapter.mousewheel = {
            bindType    : "DOMMouseScroll",
            delegateType: "DOMMouseScroll"
        }
        try{
            //可能末来FF会支持标准的mousewheel事件,则需要删除此分支
            document.createEvent("WheelEvent");
            delete eventAdapter.mousewheel;
        }catch(e){};
    }catch(e){};
    //当一个元素,或者其内部任何一个元素获得焦点的时候会触发这个事件。
    //这跟focus事件区别在于,他可以在父元素上检测子元素获取焦点的情况。
    var  rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/
    function quickParse( selector ) {
        var quick = rquickIs.exec( selector );
        if ( quick ) {
            //   0  1    2   3
            // [ _, tag, id, class ]
            quick[1] = ( quick[1] || "" ).toLowerCase();
            quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
        }
        return quick;
    }
    "on_bind,off_unbind".replace( rmapper, function(_,method, mapper){
        $.fn[ method ] = function(types, selector, fn ){//$.fn.on $.fn.off
            if ( typeof types === "object" ) {
                for ( var type in types ) {
                    $.fn[ method ].call(this, type, selector, types[ type ], fn );
                }
                return this;
            }
            var hash = {};
            for(var i = 0 ; i < arguments.length; i++ ){
                var el = arguments[i];
                if(typeof el == "number"){
                    hash.times = el
                }else if(typeof el == "function"){
                    hash.callback = el
                }if(typeof el === "string"){
                    if(hash.type != null){
                        hash.selector = el.trim()
                    }else{
                        hash.type = el.trim()
                    }
                }
            }
            if(method === "on"){
                if( !hash.type || !hash.callback ){//必须指定事件类型与回调
                    return this;
                }
                hash.times = hash.times > 0  ? hash.times : Infinity;
                hash.selector =  hash.selector ? quickParse( hash.selector ) : false
            }
            if(this.mass && this.each){
                return this.each(function() {
                    facade[ mapper ].call( this, hash );
                });
            }else{
                return facade[ mapper ].call( this, hash );
            }
        }
        $.fn[ mapper ] = function(){// $.fn.bind $.fn.unbind
            return $.fn[ method ].apply(this, arguments );
        }
    });

    $.implement({
        toggle: function(/*fn1,fn2,fn3*/){
            var fns = [].slice.call(arguments), i = 0;
            return this.click(function(e){
                var fn  = fns[i++] || fns[i = 0, i++];
                fn.call( this, e );
            })
        },
        hover: function( fnIn, fnOut ) {
            return this.mouseenter( fnIn ).mouseleave( fnOut || fnIn );
        },
        delegate: function( selector, types, fn, times ) {
            return this.on( types, selector, fn, times);
        },
        live: function( types, fn, times ) {
            $( this.ownerDocument ).on( types, this.selector, fn, times );
            return this;
        },
        one: function( types, fn ) {
            return this.on( types, fn, 1 );
        },
        undelegate: function(selector, types, fn ) {
            return arguments.length == 1? this.off( selector, "**" ) : this.off( types, fn, selector );
        },
        die: function( types, fn ) {
            $( this.ownerDocument ).off( types, fn, this.selector || "**", fn );
            return this;
        },
        fire: function(  ) {
            var args = arguments;
            if(this.mass && this.each){
                return this.each(function() {
                    $.event.fire.apply(this, args );
                });
            }else{
                return $.event.fire.apply(this, args );
            }
        }
    });

    types.replace( $.rword, function( type ){
        $.fn[ type ] = function( callback ){
            return callback?  this.bind( type, callback ) : this.fire( type );
        }
    });
});

event_fix.js

//=========================================
//  事件补丁模块
//==========================================
$.define("event_fix", !!document.dispatchEvent, function(){
    //模拟IE678的reset,submit,change的事件代理
    var rform  = /^(?:textarea|input|select)$/i ,
    changeType = {
        "select-one": "selectedIndex",
        "select-multiple": "selectedIndex",
        "radio": "checked",
        "checkbox": "checked"
    }
    function changeNotify( e ){
        if( e.propertyName === ( changeType[ this.type ] || "value") ){
            $._data( this, "_just_changed", true );
            $.event._dispatch( $._data( this, "publisher" ), "change", e );
        }
    }
    function changeFire( e ){
        if( !$._data( this,"_just_changed" ) ){
            $.event._dispatch( $._data( this ,"publisher"), "change", e );
        }else{
            $.removeData( this, "_just_changed", true );
        }
    }
    function delegate( fn ){ 
        return function( src, selector, type ){
            var adapter = $.event.eventAdapter,
            fix = adapter[ type ] && adapter[ type ].check && adapter[ type ].check( src );
            return (fix || selector) ? fn(src, type, fix) : false;
        }
    }

    var facade = $.event = {
        eventAdapter:{
            //input事件的支持情况:IE9+,chrome+, gecko2+, opera10+,safari+
            input: {
                check: function(src){
                    return rform.test(src.tagName) && !/^select/.test(src.type);
                },
                bindType: "change",
                delegateType: "change"
            },

            change: {//change事件的冒泡情况 IE6-9全灭
                check: function(src){
                    return rform.test(src.tagName) && /radio|checkbox/.test(src.type)
                },
                setup: delegate(function( src, type, fix ){
                    var subscriber = $._data( src, "subscriber", {} );//用于保存订阅者的UUID
                    $._data( src, "_beforeactivate", $.bind( src, "beforeactivate", function() {
                        var e = src.document.parentWindow.event, target = e.srcElement, tid = $.getUid( target )
                        //如果发现孩子是表单元素并且没有注册propertychange事件,则为其注册一个,那么它们在变化时就会发过来通知顶层元素
                        if ( rform.test( target.tagName) && !subscriber[ tid ] ) {
                            subscriber[ tid] = target;//表明其已注册
                            var publisher = $._data( target,"publisher") || $._data( target,"publisher",{} );
                            publisher[ $.getUid(src) ] = src;//此孩子可能同时要向N个顶层元素报告变化
                            $.fn.on.call( target,"propertychange._change", changeNotify );
                            //允许change事件可以通过fireEvent("onchange")触发
                            if(type === "change"){
                                $._data(src, "_change_fire", $.bind(target, "change", changeFire.bind(target, e) ));
                            }
                        }
                    }));
                    if( fix ){//如果是事件绑定
                        src.fireEvent("onbeforeactivate")
                    }
                }),
                teardown: delegate(function( src, els, i ){
                    $.unbind( src, "beforeactive", $._data( src, "_beforeactivate") );
                    $.unbind( src, "change", $._data(src, "_change_fire")  );
                    els = $.removeData( src, "subscriber", true ) || {};
                    for( i in els){
                        facade.unbind.call( els[i], "._change" );
                        var publisher = $._data( els[i], "publisher");
                        if(publisher){
                            delete publisher[ src.uniqueNumber ];
                        }
                    }
                })
            }
        }
    }
    var adapter = facade.eventAdapter;
    //submit事件的冒泡情况----IE6-9 :form ;FF: document; chrome: window;safari:window;opera:window
    //reset事件的冒泡情况----FF与opera能冒泡到document,其他浏览器只能到form
    "submit,reset".replace( $.rword, function( type ){
        adapter[ type ] = {
            setup: delegate(function( src ){
                $.fn.on.call( src, "click._"+type+" keypress._"+type, function( e ) {
                    var el = e.target;
                    if( el.form && (adapter[ type ].keyCode[ e.which] || adapter[ type ].kind[  el.type ] ) ){
                        facade._dispatch( [ src ], type, e );
                    }
                });
            }),
            keyCode: $.oneObject(type == "submit" ? "13,108" : "27"),
            kind:  $.oneObject(type == "submit" ? "submit,image" : "reset"),
            teardown: delegate(function( src ){
                facade.unbind.call( src, "._"+type );
            })
        };
    });
});
//2012.5.1 fix delegate BUG将submit与reset这两个适配器合而为一

posted on 2012-05-28 15:38  司徒正美  阅读(1191)  评论(0编辑  收藏  举报