//处理事件:
Namespace.register("U.UF.EV");
/**
* 统一绑定系统处理函数
* @param fun {function} 执行函数
* 绑定的所有函数可通过   U.UF.EV.systemEventBind,Array 查看
*/
U.UF.EV.systemEventBind = function (fun) {
    U.selectEl('body').bind(fun);
    U.UF.EV.systemEventBind, Array.push(fun);
}

/*
*var a = document.body.aaaa ;
*document.body.aaaa = "aaa"
*  U.UF.EV.boundProperties(HTMLElement.prototype,"aaaa", 
*                          function(){
*                             return this.innerHTML;
*                          },
*                          function(value){
*                              this.innerHTML = value; 
*                          })
*
**  作用:属性添加处理 这里处理例如chrome取消innerText等。
当修改html元素的属性时,可以让他触发一个函数.可以用于双向绑定。当某个变量的值变了,触发回调函数,修改其中的样式。
**  @param {object} obj 需要添加属性的对象
**  @param {string} str 类型的名字
**  @param {function} fun1 get函数处理
**  @param {function} fun2 set函数处理 
*/
U.UF.EV.boundProperties = function (obj, str, fun1, fun2) {
    //判断obj是否已经定义了新的属性
    if (obj.__defineGetter__) {//兼容处理
        obj.__defineGetter__ = (obj, fun1); //__definGetter__用于Getter方法追加定义,函数第一个是getter的名称,第二个参数为getter的函数
        obj.__defineSetter__ = (obj, fun2); //__definSetter__用于Setter方法追加定义,函数第一个是setter的名称,第二个参数为setter的函数
    } else if (Object.defineProperty) {//ie8以上的兼容处理
        //obj.defineProperty是直接在某一个对象上定义一个属性,这个属性可以用来添加或修改现有的属性,obj修改对象,key属性名,
        //{//descriptor}对象用来声明新属性的特性
        //configurable:默认false,表示此属性是否可用delete删除。
        //enumerable: 默认为false,表示此属性是否可被for...in、Object.keys遍历到
        //value:默认undefined,此属性的值,可以是任何JavaScript类型
        //writable:默认为false,此属性是否可被改写
        //get:默认undefined,指定一个函数,当属性被调用时,此函数也被调用,默认为返回属性值
        //set:默认undefined,指定一个函数,当属性被赋值时,此函数也被调用,仅接受一个参数,参数为属性被赋的值
        Object.defineProperty(obj, str, { configurable: true, get: fun1, set: fun2 });
    } else {//ie6-1e7
        obj[str] = fun1; //如果自动获取了属性的对象和类型的名字,则自动调用get函数处理
        obj[str].toString = fun1; //获取的属性对象的类型名进行字符串转换
        //attachEvent事件监听处理,第一个参数是事件类型,第二个参数是处理函数
        obj.attachEvent("onpropertychange", function () {
            if (event.propertyName == obj) {//判断事件对象的属性名是否为需要添加的属性的对象
                //argument用于提供调用当前正在执行的函数,caller返回调用这个函数体的函数,则返回U.UF.EV.boundProperties()
                //再添加一个caller,则返回调用了U.UF.EV.boundProperties()这个函数体的函数
                var _str = arguments.caller.caller;
                obj.detachEvent("onpropertychange", _str); //detachEvent事件监听处理,删除事件,与attachEvent相配对。第一个参数是事件参数,第二个是处理函数
                fun2(obj[str]); //调用set方法去设置新的属性
                obj[str] = fun1; //如果自动获取了属性的对象和类型的名字,则自动调用get函数处理
                obj[str].toString = fun2; //获取的属性对象的类型名进行字符串的转换,并且调用set函数处理
                obj.attachEvent("onpropertychange", _str); //重新建立事件监听处理,重新设置新的属性
            }
        });
    }
}

/*
**  作用:对象添加原型方法,添加新的数据类型,或者在已有数据类型上扩充功能,例如:String,Number,Array,Object,Guid等
**  @param {object} obj 数据类型 例如string、number等
**  @param {string、object} str 当这个参数为string的时候下述函数有效
**  @param {function} fun 原型对应的函数
*/
U.UF.EV.addPrototype = function (obj, str, fun) {
    //判断传值的参数类型是否是string
    if (typeof str == "string") {//如果传值的数据类型是string,则执行以下函数
        obj.prototype[str] = fun; //prototype是添加属性和方法,向obj对象中添加一个属性
    } else {
        var i; //用于循环
        for (i in str) {//循环所有包含了str的个数
            obj.prototype[i] = str[i]; //单个添加包含了str这个类型的属性
        }
    }
}


/**
*当页面滚动到底端的时候执行
*
* @param  {function} fun 滚动到底端需要加载的函数
* @param  {objcet} obj 需要滚动的元素
*/
U.UF.EV.scrollLoad = function (obj, fun) {
    obj.onscroll = function () {//滚动滚轮触发
        clearTimeout(U.UF.EV.scrollLoad.time);
        if (U.UF.EV.scrollLoad.scrollTop(obj) + U.UF.EV.scrollLoad.windowHeight(obj) >= (U.UF.EV.scrollLoad.documentHeight(obj))) {
            U.UF.EV.scrollLoad.time = setTimeout(fun, 100);
        }
    }
}

/**
* 获取页面顶部被卷起来的高度
*/
U.UF.EV.scrollLoad.scrollTop = function (obj) {
    return Math.max(//取最大值
    //chrome
       U.selectEl(obj)[0].scrollTop,
    //firefox/IE
       document.documentElement.scrollTop
    );
}

/**
* 获取页面文档的总高度
*/
U.UF.EV.scrollLoad.documentHeight = function (obj) {
    //现代浏览器(IE9+和其他浏览器)和IE8的document.body.scrollHeight和document.documentElement.scrollHeight都可以
    return Math.max($(obj)[0].scrollHeight, document.documentElement.scrollHeight); //取最大值
}
/**
* 获取页面浏览器视口的高度
*/

U.UF.EV.scrollLoad.windowHeight = function (obj) {
    return U.selectEl(obj)[0].clientHeight;
}

/**
* 页面活动监视,当用户离开页面休息时,停止页面活动(计时器)
*
* @param  {function} 页面聚焦回调函数
* @param  {function} 页面离开的回调
* @return  {string}  获取key对应的值
*/
U.UF.EV.IsActivity = function (fun1, fun2) {
    var _timer;
    //页面聚焦的处理
    if (fun1) {
        //判断鼠标是否在body页面上
        U.selectEl(document.body).mouseenter(function () {
            //由于函数会多次触发,所以做一个计时器进行处理,让函数只触发一次
            if (_timer) {
                window.clearTimeout(_timer);
            }
            _timer = window.setTimeout(fun1);
        });

        //页面聚焦同时为活动页面
        U.UF.EV.addElementEvent("focusin", document, function () {
            //由于函数会多次触发,所以做一个计时器进行处理,让函数只触发一次
            if (_timer) {
                window.clearTimeout(_timer);
            }
            _timer = window.setTimeout(fun1);
        });
    }
    //页面失焦的处理
    if (fun2) {
        //页面不活动的时候处理
        U.UF.EV.addElementEvent("focusout", document, function () {
            var _clientx = event.clientX;  //页面x坐标
            var _clienty = event.clientY; //获取event对象的y坐标

            //判断用户的鼠标是否在制定的范围内,如果在说明活动了当前页面
            if ((!(U.UF.CI.getBrowser().browser == "msie") ||
                (_clientx < 0 || _clientx > US.width || _clienty < 0 || _clienty > US.height))) { //判断鼠标不在页面中
                fun2();
            }
        });
    }
}

/**
* 滚动条滚动到制定的位置
*
* @param  {string}  指定scrollTop的数值
* @param  {function}  需要调整滚动条位置的对象
* @param  {function}  加载成功回调
* @return  {element}  图片元素
*/
U.UF.EV.scrollToPosition = function (str, fun1, fun2) {
    var _isnumber = U.UF.C.isNumber(str); //判断str是否是数字true 或者 false
    //动画移动具体的位置
    if (_isnumber && fun2) {
        U.selectEl(fun1).animate({ "scrollTop": str }, fun2);
    }
    else {
        //设置fun1的内容垂直滚动的像素数
        if (typeof str == "number") {
            fun1.scrollTop = str;
        }
        else {
            str.scrollIntoView(); //sty.scrollIntoView 让当前的元素滚动到浏览器窗口的可视区域内
        }
    } //直接移动过
}

/**
* 自动触发HTMLElement事件 Mouse事件,模拟鼠标点击事件
*
* @param  {element} 触发的元素
* @param  {string} 事件类型
* @return  {object} resize对象
*/
U.UF.EV.simulateMouseClicks = function (el, str) {
    //ie直接执行事件的处理
    if (el.fireEvent) {
        return el.fireEvent("on" + str, window.event);
    }
    //ie以外的浏览器处理事件执行
    else if (document.createEvent) {

        var _mousevent = document.createEvent("MouseEvents"), //创建事件事件
            _event = window.event; //事件处理
        //初始化事件
        if (_event) { //原本已经具有事件event来源的情况下处理
            //执行mouse事件处理
            _mousevent.initMouseEvent(
                            str,
                            true,
                            true,
                            window,
                            _event.detail,
                            _event.screenX,
                            _event.screenY,
                            _event.clientX,
                            _event.clientY,
                            _event.ctrlKey,
                            _event.altKey,
                            _event.shiftKey,
                            _event.metaKey,
                            _event.button,
                            _event.relatedTarget
            );
        }
        else {
            //没有事件来源event的处理
            _mousevent.initMouseEvent(
                            str,
                            true,
                            true,
                            document.defaultView,
                            0,
                            0,
                            0,
                            0,
                            0,
                            false,
                            false,
                            false,
                            false,
                            0,
                            el
            )
        }
        //分发事件
        return el.dispatchEvent(_mousevent);
    }
}

/**
* 自动触发HTMLElement Touch事件
*
* @param  {element} 触发的元素
* @param  {string} 事件类型
* @param  {object} resize对象
*/
U.UF.EV.simulatePhoneTouch = function (el, str, obj) {
    if (el.fireEvent) { //ie事件触发处理
        el.fireEvent("on" + TF);
    }
    else if (document.createEvent) { //h5事件处理
        var i,
            _arr,
            _event = obj || window.event;

        //创建一个touch时间的处理
        if (TouchEvent) { //有TouchEvent的创建方式
            var _touchevent = new TouchEvent(str, _event);
        }
        //其他的创建方式
        else {
            var _touchevent = document.createEvent("TouchEvent");
        }

        //执行事件的方法
        if (_touchevent.initTouchEvent) { //有initTouchEvent执行方法的处理
            var _str = "initTouchEvent";
        }
        else { //initEvent执行方法的处理
            var _str = "initEvent";
        }
        //chrome
        _arr = [
        //chrome
            [
                event.touches, //当前屏幕上所有触摸点的列表
                event.targetTouches, //当前对象上所有触摸点的列表
                event.changedTouches, //涉及当前(引发)事件的触摸点的列表
                str,
                event.view,
                event.screenX,
                event.screenY,
                event.clientX,
                event.clientY,
                event.ctrlKey,
                event.alrKey,
                event.shiftKey,
                event.metaKey
            ],
        //safari
            [
                str,
                true,
                event.cancelable,
                event.view,
                event.detail,
                event.screenX,
                event.screenY,
                event.clientX,
                event.clientY,
                event.ctrlKey,
                event.altKey,
                event.shiftKey,
                event.metaKey,
                event.touches,
                event.targetTouches,
                event.changedTouches,
                event.scale,
                event.rotation
            ],
        //firefox
            [
                str,
                true,
                event.cancelable,
                event.view,
                event.detail,
                event.ctrlKey,
                event.altKey,
                event.shiftKey,
                event.metaKey,
                event.touches,
                event.targetTouches,
                event.changedTouches
                ],
            ];
        //由于浏览器对直接执行事件的兼容有三种方案,这里是对三种方案的循环添加
        for (i = 0; i < _arr.length; i++) {
            //直接执行
            try {
                _touchevent[_str].apply(_touchevent, _arr[i]);
            }
            catch (e) {
            }
            if (_touchevent.type == str) {
                break;
            }
        }

    }
    return el.dispatchEvent(_touchevent); //分发事件
}

/**
* 注册函数事件 Internet Explorer 8 及更早IE版本不支持 addEventListener() 方法,,Opera 7.0 及 Opera 更早版本也不支持。 但是,对于这些不支持该函数的浏览器,你可以使用 attachEvent() 方法来添加事件句柄 
*
* @param  {string} 事件名称
* @param  {element} 添加事件的元素
* @param  {function} 事件触发后调用的函数
* @param  {string} 指定事件是否在捕获或冒泡阶段执行
*/
U.UF.EV.addElementEvent = function (str, el, fun, isbubble) {
    if (el.addEventListener) { //非IE使用
        el.addEventListener(str, fun, isbubble || false);
    }
    else if (el.attachEvent) { //IE
        el.attachEvent("on" + str, fun);
    }
    else {//html5处理
        el["on" + str] = function () {
            el["on" + str]();
            fun();
        }
    }
}

/**
* 取消函数事件
*
* @param  {string} 事件名称
* @param  {element} 添加事件的元素
* @param  {function} 事件触发后调用的函数
* @param  {string} 指定事件是否在捕获或冒泡阶段执行
*/
U.UF.EV.delElementEvent = function (str, el, fun, isbubble) {
    if (el.removeEventListener) { //非IE使用
        el.removeEventListener(str, fun, isbubble || false);
    }
    else if (el.detachEvent) {//IE使用
        el.detachEvent("on" + str, fun);
    }
    else { el["on" + str] = null; } //非元素
}

/**
* 获取事件源 跨iframe搜索,由于我们在点击iframe的时候,不知道事件是从哪个iframe或者来的,所以这里循环iframe找事件的来源
*
*/
U.UF.EV.getEventSource = function () {
    var i, //循环初始化
        _data, //用于储存数据
        _frames = window.frames; //获取window.frames
    var _event = window.event; //获取window.event
    if (!_event) {
        for (i = 0; i < _frames.length; i++) { //循环所有的iframe 获取事件源
            _data = _frames[i]; //得到iframe处理
            //由于非自己站点的iframe会存在跨域处理
            try {
                _event = _data.event; //获取事件
                //如果找到了事件那么就直接break
                if (_event) {
                    break;
                }
            }
            catch (e) { continue; };
        }
    }
    //返回事件源
    return _event;
}

/**
* 阻止冒泡
*/
U.UF.EV.stopBubble = function () {
    var _event = U.UF.EV.getEventSource(); //获取Event
    //调用的时候判断是否有时间的来源
    if (_event) {
        //非ie系列浏览器支持处理事件冒泡的方案
        if (_event.stopPropagation) {
            _event.stopPropagation();
        }
        //ie系列浏览器支持去小事件冒泡处理
        else {
            _event.cancelBubble = true;
        }
    }
}

/**
* 执行mouseout mouseover不冒泡情况,以前是多次触发,现在做到移动进去触发一次,移动出来触发一次
* mouseout||mouseover 冒泡解决
*
* @param  {element} 需要执行的元素 
* @return  {function} 回调函数 
*/
U.UF.EV.stopBubbleMouseOutOrOver = function (el, cb) {
    if (event && "mouseover,mouseout".indexOf(event.type) > -1) { //判断事件源
        var _target = (event.type == "mouseover" ? event.fromElement : event.toElement) || event.relatedTarget, //事件对象
            _bool = U.UF.EL.isChild(el, _target); //判断_target是否是el的子孙节点
        if (!_bool && U.UF.C.isFunction(cb)) { //判断是否在该元素下
            cb();
        }
        return _bool;
    }
}

/**

* 阻止浏览器的默认行为,例如右键菜单,左键选择
*
*/
U.UF.EV.stopDefault = function (e) {
    var _event = e || window.event; //获取window.event对象
    if (_event) {
        //IE中阻止函数器默认动作的方式 
        if (document.all) {
            _event.returnValue = false;
        }
        //阻止默认浏览器动作(W3C) 
        else {
            _event.preventDefault();
        }
        return false;
    }
}

/**
事件委托,本地程序调用客户端程序时会用到。
* 随机产生一个函数 调用后销毁 类似委托
解决跨域问题,以及ajax多个请求,多份实例的问题。
*
* @param  {function} 回调函数
* @param  {array} 回调参数 params1
* @param  {boolean} 执行成功后是否移除委托
* @param  {string} id
* @return  {object} 委托对象
*/
U.UF.EV.eventDelegation = function (cb, params, isremove, id) {
    if (isremove == null) {
        isremove = true;
    }
    var _id = id || "a" + Guid.newGuid(); //唯一识别id
    window[_id] = function () {
        try {
            //判断是否有回调函数
            if (U.UF.C.isFunction(cb)) {
                cb.apply(null, arguments);
            }
            //是否移除事件委托对象
            if (this.isremove) {
                window[_id] = null; //设置对象移除
                delete window[_id]; //清理对象
            }
        }
        catch (e) { }
    }
    return _id;
}

/**
*  页面消息传递,解决跨域问题。
* @param  {function} 跨域iframe传参的回调函数
* @param  {boolean} 是否是发送者,在iframe里面的是接收者,iframe外的是发送者
* @param  {string} 与iframe通讯的唯一识别id,如果是接收多个不同回调的消息,那么需要传参
* @param  {string} 需要跨域的iframe的id
*
*/
U.UF.EV.message = function (fun, issender, id, iframeid) {
    this.fun = fun; //监视消息的函数
    this.id = id || Guid.guidNoDash(); //消息通讯的唯一id
    this.sender = issender; //是否是发送者
    this.iframeid = iframeid; //消息发送到哪个iframe里 接受者没有
    this.iframe = null; //发送给那个iframe的元素
    this.url = ""; //iframe的链接
    U.UF.EV.message.callbacks[this.id] = this; //所有消息记录
    //设置onmessage事件获取浏览器之间的传参
    if ("onmessage" in window) {
        U.UF.EV.addElementEvent("message", window, U.UF.EV.message.getDataAndCallBack);
    }
    //如果是iframe内的发送的处理方式
    if (this.sender) {
        this.iframe = U.selectEl("#" + this.iframeid)[0]; //获取iframe
        this.url = $$("a", { "src": this.iframe.src }).host; //iframe的链接,用于ie跨域传参的时候使用
    }
    //如果是接收者也就是iframe里面的对象的处理方法
    else if (!("onmessage" in window)) {
        U.UF.EV.message.getDataAndCallBack();
    }
}

//这里包含了所有的需要回调的回调函数
U.UF.EV.message.callbacks = [];

/**
*  得到数据的方法
*  @message  {object} 发送者发送的信息
*/
U.UF.EV.message.getDataAndCallBack = function (message) {
    var _data;
    //高版本的浏览器是通过onmessage获取的
    if ("onmessage" in window) {
        _data = message.data; //获取数据
    }
    //低版本的浏览器获取值得处理
    else {
        _data = window.name; //获取数据
    }
    _data = _data.parseJSON(); //传入的数据转化成json处理
    var _fun = U.UF.EV.message.callbacks[_data[1]]; //得到回调函数的类
    //如果类存在,那么调用类的message数据回调方法
    if (_fun) {
        _fun.message(_data[0], _data[1], _data[2]);
    }
}

//message类的原型方法
U.UF.EV.message.prototype = {
    /**
    *  接收消息
    *  @data  {object} 接收的信息
    *  @cookie  {object} 接受者 cookie
    */
    message: function (data, id, cookie) {
        //如果页面监视的是回调函数的处理
        if (U.UF.C.isFunction(this.fun)) {
            this.fun(data, id, cookie);
        }
        //如果是接收者,同时又是在低版本的浏览器下使用的iframe,那么清空iframe的使用
        if (this.sender && !("onmessage" in window)) {
            var _doc = this.obj.contentWindow.document; //重新创建一个document
            _doc.open(); //打开
            _doc.write(""); //整个页面写入空
            _doc.close(); //关闭
        }
    },
    /**
    *  提交消息
    *  @data  {object} 发送者发送的信息
    *  @id  {object} 发送者的id
    *  @cookie  {object} 发送者 cookie
    */
    post: function (data, id, cookie) {
        var _win,
            _message = U.UF.C.jsonToStr([data, id || this.id, cookie]); //拼接传参的参数,由于发送者和接受者都公用这个 所以当接受者给发送者发回消息的时候第二个参数是发送者的id。
        //高版本的iframe发送消息
        if ("onmessage" in window) {
            if (this.sender) {
                //得到iframe传参的域
                try {
                    _win = this.iframe.contentWindow || this.iframe; //如果是发送者,那么获取contentWindow
                }
                catch (e) {
                    _win = this.iframe; //如果是接收者发送回给发送者,那么iframe是parent就不需要获取contentWindow了
                }
            }
            else {
                _win = parent;
            }
            _win.postMessage(_message, "*"); //发送消息
        }
        //低版本的浏览器发送iframe消息
        else {
            //如果是发送者发消息的处理
            if (this.sender) {
                //等待iframe重新加载后处理跨域
                U.UF.DL.iframeLoad(this.iframe, U.UF.C.apply(this, function () {
                    this.iframe.contentWindow.name = _message;  //设置window.name传参值
                    this.iframe.contentWindow.location.href = this.url; //刷新到跨域的页面
                    //重新设置onlaod事件处理等待页面响应
                    U.UF.DL.iframeLoad(this.iframe, U.UF.C.apply(this, function () {
                        U.UF.EV.message.getDataAndCallBack(); //调用iframe返回数据后重新load "about:blank"链接后的回调
                    }));
                }));
                this.iframe.src = "about:blank"; //重新加载iframe
            }
            //接受者的处理
            else {
                window.name = _message; //设置window.name传参值
                window.src = "about:blank"; //
            }
        }
    }
}


/**
*  打印处理函数
*  
*/
U.UF.EV.print = function (el) {
    //    var AllContent = window.document.body.innerHTML; //首先获得元素的html内容,保存当前页面的HTML
    //    var newstr = el.innerHTML; //得到需要打印的元素HTML
    //    document.body.innerHTML = newstr; //把当前页面替换为打印内容HTML
    //    window.print(); //执行打印操作
    //    document.body.innerHTML = AllContent; //还原当前页面

    var iframe = document.createElement('iframe');
    var doc = null;
    iframe.setAttribute('style', 'position:absolute;width:0px;height:0px;left:-500px;top:-500px;');
    document.body.appendChild(iframe);
    doc = iframe.contentWindow.document;
    doc.write('<div>' + el.innerHTML + '</div>');
    doc.close();
    iframe.contentWindow.focus();
    iframe.contentWindow.print();
    if (navigator.userAgent.indexOf("MSIE") > 0) {
        document.body.removeChild(iframe);
    }
}