2016年12月29日 星期四

(css)transition-problem

<!DOCTYPE html>
<html lang="en">

<head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        #div_1 {
            width: 100px;
            height: 100px;
            transition-property: top;
            transition-duration: 1s;
            position: absolute;
            top: 50px;
            background-color: red;
        }
     
        .noAnimate {
            transition: none;
        }
    </style>
    <script>
        function domRedraw_1(dom) {
            // 藉著寬度改變

            var css = getComputedStyle(dom, null);
            var oldStyle = dom.style.cssText;
            /* ------------------------ */
            /**
             * 改變寬度
             * 
             * 寬度+1
             * 
             * 再改回來
             */

            var width = css.width.replace(/\D/g, '');
            width = Number(width);
            width++;
            dom.style.width = width + 'px';
            /* ------------------------ */
            // 回復
            dom.style.cssText = oldStyle;
        };

        function domRedraw_2(dom) {
            // 藉著(offsetHeight)
            dom.offsetHeight;
        };
    </script>
    <script>
        function test_1() {
            var div = document.querySelector('#div_1');
            var style = div.style;

            style.removeProperty('display');

            // important
            domRedraw_1(div);

            style.top = '200px';
        }
    </script>
</head>

<body>
    <button onclick="test_1();">Click!</button>
    <div id="div_1" style="display: none">
        target
    </div>
</body>

</html>

(css)tansition-problem-1

<!DOCTYPE html>
<html lang="en">

<head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        #div_1 {
            width: 100px;
            height: 100px;
            transition: left 2s;
            position: absolute;
            top: 50px;
            background-color: red;
        }
       
        .noAnimate {
            transition: none;
        }
    </style>
    <script>
        function domRedraw_1(dom) {
            // 藉著寬度改變

            var css = getComputedStyle(dom, null);
            var oldStyle = dom.style.cssText;
            /* ------------------------ */
            /**
             * 改變寬度
             * 
             * 寬度+1
             * 
             * 再改回來
             */

            var width = css.width.replace(/\D/g, '');
            width = Number(width);
            width++;
            dom.style.width = width + 'px';
            /* ------------------------ */
            // 回復
            dom.style.cssText = oldStyle;
        };

        function domRedraw_2(dom) {
            // 藉著(offsetHeight)
            dom.offsetHeight;
        };
    </script>
    <script>
        function test_1() {
            var div = document.querySelector('#div_1');
            var style = div.style;
            div.classList.add('noAnimate');
            style.cssText = 'left:300px;';

            // do this to force a redraw instead of setTimeout() !
            // div[0].offsetHeight;

            domRedraw_1(div);
            // domRedraw_2(div);

            div.classList.remove('noAnimate');
            style.cssText = 'left:0;';

            /*
            setTimeout(function() {
                div.removeClass('noAnimate').css('left', 0);
            }, 10);
            */
        }
    </script>
</head>

<body>
    <button onclick="test_1();">Click!</button>
    <div id="div_1">
        target
    </div>
</body>

</html>

2016年12月27日 星期二

(js)Event模組的原型

function addEvent(element, type, handler) {
    // 检测handler是否有$$guid属性。如果没有,赋值为addEvent的guid属性,将addEvent的guid属性自增1
    // 假设handler没有$$guid属性,addEvent的guid为1,则经此判断,
    // handler会有一个$$guid属性,且值为1,而addEvent的guid属性值变成2
    if (!handler.$$guid)
        handler.$$guid = addEvent.guid++;
    // 检测element是否已经绑定过事件,如果没有绑定过,
    // 则默认设置为一个空对象,用于保存将要绑定的事件
    if (!element.events)
        element.events = {};
    // 获取已经绑定过的type类型的事件对象
    var handlers = element.events[type];
    // 如果还没有type类型的事件被绑定过,则设置该类型的事件为一个空对象,用于保存将要绑定的该类型的事件
    if (!handlers) {
        handlers = element.events[type] = {};
        /*
        if(element["on" + type]){
        handlers[0] = element["on" + type];
        }*/
    }
    //按照序号存进去
    handlers[handler.$$guid] = handler;

    //赋予一个全局事件处理函数来处理所有工作
    element["on" + type] = handleEvent;
}
// addEvent保存一个序号
addEvent.guid = 1;
// 移除事件
function removeEvent(element, type, handler) {
    // 如果element经过addEvent绑定过事件,并且也有type类型的事件
    if (element.events && element.events[type]) {
        // 删除element的type类型事件的handler处理器
        delete element.events[type][handler.$$guid];
    }
}
// 处理事件
function handleEvent(event) {
    // 默认返回值为true
    var returnValue = true;
    // 矫正事件对象event
    event = event || fixEvent(window.event);
    // 获取已绑定的type类型的处理器
    var handlers = this.events[event.type];
    // 遍历执行每一个处理器
    for (var i in handlers) {
        this.$$handleEvent = handlers[i];
        // 如果存在返回值为false的处理器,则设置返回值为false
        if (this.$$handleEvent(event) === false) {
            returnValue = false;
        }
    }
    // 返回处理结果
    return returnValue;
}

(js)Area88_transition.js

////////////////////////////////////////////////////////////////////////////////
/**
 * (jquery)擴充
 *
 * 處理transition
 */
////////////////////////////////////////////////////////////////////////////////

(function($) {
    /**
     * 取得(transitionEnd)事件的名字
     */
    $.support = $.support || {};
    $.support.transition = getTransitionEndName();

    function getTransitionEndName() {
        var el = document.createElement('div')
        var transitionendName;

        var data = {
            WebkitTransition: 'webkitTransitionEnd',
            MozTransition: 'transitionend',
            OTransition: 'oTransitionEnd otransitionend',
            transition: 'transitionend'
        }

        for (var k in data) {
            if (el.style[k] !== undefined) {
                transitionendName = data[k];
            }
        }
        return transitionendName;
    }
})(Area88_);
///////////////////////////////////////////////////////////////////////////////
(function($) {
    /**
     * 確保(transitionend)有被執行完
     *
     * @param {int | string} option: 可以指定(time),或指定要監看的(transition-property)
     */
    $.fn.tsEndCheck_ = function(option) {
        debugger;

        var time;
        (typeof option == 'number') && (time = option);

        this.each(function(i, dom) {
            debugger;

            var check = false;
            /* ---------------------------------- */
            if (typeof option == 'string') {
                // 取得 transitionDuration
                time = $(dom).tsTime_(option);
            }
            /* ---------------------------------- */
            debugger;
            // 再綁定一個'transitionend'事件,但事件中有包含一個通知結束的動作
            dom.addEventListener($.support.transition, eventFun);

            function eventFun(e) {
                alert('eventFun()');
                debugger;
                check = true;
                dom.removeEventListener($.support.transition, eventFun);
            };
            /* ---------------------------------- */
            // 檢查
            setTimeout(function() {
                debugger;
                alert('check: ' + check);
                if (check) {
                    return;
                }
                // 若'transitionend'未被觸發過
                var evt = document.createEvent('Event');
                evt.initEvent($.support.transition, true, true);
                dom.dispatchEvent(evt);
            }, time + 50);
        });

        return this;
    };
    /* ========================================================================== */

})(Area88_);


///////////////////////////////////////////////////////////////////////////////

// 取得,設定(動畫時間)

(function($) {
    $.tsTime_ = function(elem, setting) {
        debugger;
        if (setting == null || typeof setting == 'string') {
            var data = getTransitionProperty(elem);

            if (typeof setting == 'string') {
                return (data[setting] || data['all'] || undefined);
            } else {
                return data;
            }
        } else if ($.isPlainObject(setting)) {
            setTransitionProperty(elem, setting);
            return;
        } else {
            throw new Error('arguments type error');
        }
    };
    /* ====================================================================== */
    /**
     * 取得或設定(transition-property)(transition-duration)
     *
     * @param {plaineObject, string, undefined} setting (若'{}'是設定,
     * 'string'則返回特定項目的時間, 'undefined'返回所有項目的時間)
     * @return {[type]} [description]
     */
    $.fn.tsTime_ = function(setting) {
        debugger;
        var result = null;

        // 若是要設定(transition)

        /* -------------------------------------------- */
        this.each(function(index, el) {
            debugger;

            result = $.tsTime_(this, setting);

            if (setting == null || typeof setting == 'string') {
                return false;
            }
        });
        /* -------------------------------------------- */
        if (setting == null || typeof setting == 'string') {
            return result;
        } else {
            return this;
        }
    };
    /* ====================================================================== */
    /**
     * 取得(dom)相關初始的(transitionProperty)
     * 包含了(css)(style)的設定
     *
     * @param {[type]} dom [description]
     * @return {[null]}
     *
     */
    function getTransitionProperty(dom) {
        debugger;

        var result = {};

        var transitionProperty_array = [];
        var transitionDuration_array = [];

        var css = dom.currentStyle || window.getComputedStyle(dom, null);

        var property = css.transitionProperty || '';
        var duration = css.transitionDuration || '';

        property = property.replace(/\s/g, '');
        duration = duration.replace(/\s/g, '');

        property_array = property.split(',');
        duration_array = duration.split(',');

        /* -------------------------------------------- */
        // 若(transitionDuration)數目沒有匹配(transitionProperty)

        for (var i = 0; i < property_array.length; i++) {
            var property = property_array[i];

            // 若沒有對應的時間,會取第一個作為預設
            var duration = duration_array[i] || duration_array[0];
            duration = Number(duration.replace(/[a-zA-Z]*/gi, '')) * 1000; // 去掉(s)

            result[property] = duration;

            if (/all/gi.test(property)) {
                // 若遇到(property = all)會複寫前面屬性的時間
                for (var j = 0; j < i; j++) {
                    property = property_array[j];
                    result[property] = duration;
                }
            }
        }
        return result;
    };
    /* ====================================================================== */
    /**
     * 設定(dom.style.transitionProperty)
     *
     * @param  {[type]} dom            [description]
     * @param {plaineObject} setting 要設定的(transition)選項
     * @return {[type]}
     */
    function setTransitionProperty(dom, setting) {
        debugger;

        setting = setting || {};
        /* -------------------------------------------- */
        var style = dom.style;

        var property = [];
        var duration = [];

        for (var k in setting) {
            property.push(k);

            var _duration = setting[k];

            if (typeof _duration == 'number') {
                _duration = _duration / 1000;
                duration.push(_duration + 's');
            }
        }

        if (property.length > 0 && duration.length > 0) {
            style.transitionProperty = property.join(',');
            style.transitionDuration = duration.join(',');

        }
    };
})(Area88_);
////////////////////////////////////////////////////////////////////////////////

(js)Area88_geometry.js

////////////////////////////////////////////////////////////////////////////////
/**
 * (jquery)擴充
 *
 * 處理空間位置相關
 */
////////////////////////////////////////////////////////////////////////////////

/**
 * 取得(dom)高度,寬度
 *
 * 特別用於隱藏中的元素(隱藏的)
 */

(function($) {
    $.blockElements_ = ['address', 'article', 'aside', 'blockquote', 'canvas',
        'dd', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'figcaption', 'footer',
        'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'li', 'main',
        'nav', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table', 'tfoot', 'ul', 'video'
    ];
    /* ====================================================================== */
    /**
     * 抓取(dom)尺寸相關訊息
     * 特別用在隱藏的元素
     *
     * @param {boolean} forAnimation 是否為了動畫(inline無法動畫)
     */
    $.getDomSizeData_ = function(dom, forAnimation) {

        if (dom == null || typeof dom.nodeName == 'undefined') {
            throw new Error('dom no exists');
        }
        var css = dom.currentStyle || window.getComputedStyle(dom, null);
        var style = dom.style;

        console.dir(css);
        console.dir(style);

        // (css)(style)元素本來是否可見
        var display = /none/gi.test(css.display) ? false : true;

        // (style)是否設定不可見
        var style_setNoSee = /none/gi.test(style.display) ? true : false;

        var sizeData = {
            'boxSizing': '',
            'borderBottomWidth': '',
            'borderLeftWidth': '',
            'borderRightWidth': '',
            'borderTopWidth': '',
            'paddingBottom': '',
            'paddingLeft': '',
            'paddingRight': '',
            'paddingTop': '',
            'marginBottom': '',
            'marginLeft': '',
            'marginRight': '',
            'marginTop': ''
        };

        debugger;
        /* ============================================ */
        /**
         * 元素是否可見,不可見還要再進一步處理
         *
         * 若不可見,要變為可見才能量(size)
         */
        if (display) {
            // 若元素是顯示的
            sizeData = getDomSizeData_1(dom, sizeData);
        } else {
            // 若元素是隱藏狀態        

            if (style_setNoSee) {
                // 若是藉由(style)設置隱藏

                sizeData = getHideDom_sizeData_2(dom, sizeData);

            } else {

                /**
                 * 藉由(css)設置隱藏,無法從css得知標籤block屬性
                 *
                 * 就只能從標籤判斷是否是(block)
                 */
                var displayType = $.blockElements_.indexOf(dom.nodeName.toLowerCase()) >= 0 ? 'block' : 'inline';

                if (displayType == 'inline') {
                    // inline元素
                    if (forAnimation === true) {
                        // inline元素要作為animation必須畫作inline-block
                        sizeData = getHideDom_sizeData_1(dom, 'inline-block', sizeData);
                    } else {
                        sizeData = getHideDom_sizeData_1(dom, 'inline', sizeData);
                    }
                } else {
                    sizeData = getHideDom_sizeData_1(dom, 'block', sizeData);
                }
            }
        }
        /* -------------------------------------------- */
        // 整理(sizeData)數據
        for (var k in sizeData) {
            if (sizeData.hasOwnProperty(k)) {
                if (k != 'boxSizing') {
                    if (typeof sizeData[k] === 'string') {
                        // 去掉單位
                        var d = sizeData[k].replace(/[^0-9\.]/gi, '');
                        sizeData[k] = Number(d);
                    }
                }
            }
        }

        sizeData.borderBox = false;
        if (/^border.*box$/gi.test(sizeData.boxSizing)) {
            sizeData.borderBox = true;
        }

        debugger;
        return sizeData;
    };

    /* ---------------------------------------------------------------------- */
    /**
     * 針對沒有隱藏的(dom)
     *
     * @param {type} dom
     * @returns {undefined}
     */
    getDomSizeData_1 = function getDomSizeData_1(dom, sizeData) {
        debugger;

        var css = dom.currentStyle || window.getComputedStyle(dom, null);
        var style = dom.style;
        /* -------------------------------------------- */
        // 讀取(css)值

        for (var k in sizeData) {
            sizeData[k] = css[k];
        }
        sizeData.offsetHeight = dom.offsetHeight;
        sizeData.offsetWidth = dom.offsetWidth;
        /* -------------------------------------------- */

        return sizeData;
    };
    /* ====================================================================== */
    /**
     * 針對用css隱藏的dom
     *
     * 這樣用的用意在於(inline)position:absolute,會變成(block)
     *
     * @param {[type]} dom [description]
     *
     * @return {[type]} [description]
     */
    function getHideDom_sizeData_1(dom, blockStyle, sizeData) {
        debugger;

        var parentNode = dom.parentNode;
        var parent_oldCss = parentNode.style.cssText;

        if (parentNode.style.position.trim().length == 0) {
            parentNode.style.position = 'relative';
        }
        /* ---------------------------------- */
        // 複製節點
        var cloneNode = dom.cloneNode(true);

        // 讓隱藏的元素顯示出來,方便量(size)
        cloneNode.style.setProperty('display', blockStyle);
        /* ---------------------------------- */
        // 創建一個隱藏的容器,放要量測的元素
        var container = document.createElement('div');

        container.style.setProperty('height', '0');
        container.style.setProperty('width', '100%');
        container.style.setProperty('padding', '0');
        container.style.setProperty('margin', '0');
        container.style.setProperty('overflow', 'hidden');
        container.style.setProperty('border-width', '0px');
        container.style.setProperty('visibility', 'hidden');

        container.appendChild(cloneNode);
        parentNode.insertBefore(container, dom);
        /* ---------------------------------- */
        // 讀取(css)值
        var css = cloneNode.currentStyle || window.getComputedStyle(cloneNode, null);
        // var style = cloneNode.style;

        for (var k in sizeData) {
            sizeData[k] = css[k];
        }
        sizeData.offsetHeight = cloneNode.offsetHeight;
        sizeData.offsetWidth = cloneNode.offsetWidth;

        /* -------------------------------------------- */
        parentNode.removeChild(container);
        parentNode.style.cssText = parent_oldCss;

        return sizeData;
    };
    /* ====================================================================== */
    /**
     * 針對用style隱藏的dom
     */
    function getHideDom_sizeData_2(dom, sizeData) {
        debugger;
        // 複製節點
        var cloneNode = dom.cloneNode(true);

        var parentNode = dom.parentNode;
        var parent_oldCss = parentNode.style.cssText;

        if (parentNode.style.position.trim().length == 0) {
            parentNode.style.position = 'relative';
        }
        /* ---------------------------------- */

        // 讓隱藏的元素顯示出來,方便量(size)


        // 若是靠(style)隱藏起來的
        cloneNode.style.removeProperty('display');

        /* ---------------------------------- */
        // 創建一個隱藏的容器,放要量測的元素
        var container = document.createElement('div');

        container.style.setProperty('height', '0');
        container.style.setProperty('width', '100%');
        container.style.setProperty('padding', '0');
        container.style.setProperty('margin', '0');
        container.style.setProperty('overflow', 'hidden');
        container.style.setProperty('border-width', '0px');
        container.style.setProperty('visibility', 'hidden');

        container.appendChild(cloneNode);
        parentNode.insertBefore(container, dom);
        /* ---------------------------------- */
        // 讀取(css)值
        var css = cloneNode.currentStyle || window.getComputedStyle(cloneNode, null);
        // var style = cloneNode.style;

        for (var k in sizeData) {
            sizeData[k] = css[k];
        }
        sizeData.offsetHeight = cloneNode.offsetHeight;
        sizeData.offsetWidth = cloneNode.offsetWidth;

        /* -------------------------------------------- */
        parentNode.removeChild(container);
        parentNode.style.cssText = parent_oldCss;

        return sizeData;
    };
    /* ====================================================================== */


})(Area88_);

/* ========================================================================== */
/**
 * 各種高度
 */
(function($) {
    /**
     * 用法與(jquery.outerHeight)相同
     * 包括(border)(padding)
     * 但只能取值
     *
     * @param {[boolean]} option [包括(margin)]
     * @return {[number]} [高度]
     */
    $.fn.getOuterHeight_ = function(getMargin) {
        // debugger;

        getMargin = getMargin || false;
        var height, sizeData;
        /* -------------------------------------------- */
        this.each(function(index, el) {
            debugger;

            var dom = this;
            sizeData = $.getDomSizeData_(dom);

            if (index == 0) {
                // 只為了取得高度

                height = sizeData.offsetHeight;
                if (getMargin) {
                    height += sizeData.marginBottom;
                    height -= sizeData.marginTop;
                }
                return false;
            }
        });
        /* -------------------------------------------- */
        return height;

    };
    /* ====================================================================== */
    /**
     * 用法與(jquery.innerHeight)相同
     * 但只取值,不設定
     *
     * 包括(padding)
     *
     * @return {[number]} [高度]
     */
    $.fn.getInnerHeight_ = function() {

        var height, sizeData;
        /* -------------------------------------------- */
        this.each(function(index, el) {
            debugger;

            var dom = this;
            sizeData = $.getDomSizeData_(dom);

            if (index == 0) {
                // 只為了取得高度

                height = sizeData.offsetHeight;
                height -= sizeData.borderTopWidth;
                height -= sizeData.borderBottomWidth;

                return false;
            }
        });
        /* -------------------------------------------- */
        return height;
    };
    /* ====================================================================== */
    /**
     * 用法與(jquery.height)相同
     *
     * 只取高度
     *
     * @return {[type]} [description]
     */
    $.fn.getHeight_ = function() {
        // debugger;

        var height, sizeData;
        /* -------------------------------------------- */
        this.each(function(index, el) {
            debugger;

            var dom = this;
            sizeData = $.getDomSizeData_(dom);

            if (index == 0) {
                // 只為了取得高度

                height = sizeData.offsetHeight;
                height -= sizeData.borderTopWidth;
                height -= sizeData.borderBottomWidth;
                height -= sizeData.paddingTop;
                height -= sizeData.paddingBottom;

                return false;
            }
        });
        /* -------------------------------------------- */
        return height;
    };
    /* ====================================================================== */
})(Area88_);

////////////////////////////////////////////////////////////////////////////////
/**
 * 各種高度
 */
(function($) {
    /**
     * 用法與(jquery.outerHeight)相同
     * 包括(border)(padding)
     * 但只能取值
     *
     * @param {[boolean]} option [包括(margin)]
     * @return {[number]} [高度]
     */
    $.fn.getOuterWidth_ = function(getMargin) {
        // debugger;

        getMargin = getMargin || false;
        var width, sizeData;
        /* -------------------------------------------- */
        this.each(function(index, el) {
            debugger;

            var dom = this;
            sizeData = $.getDomSizeData_(dom);

            if (index == 0) {
                // 只為了取得高度

                width = sizeData.offsetWidth;
                if (getMargin) {
                    width += sizeData.marginLeft;
                    width += sizeData.marginRight;
                }
                return false;
            }
        });
        /* -------------------------------------------- */
        return width;

    };
    /* ====================================================================== */
    /**
     * 用法與(jquery.innerHeight)相同
     * 但只取值,不設定
     *
     * 包括(padding)
     *
     * @return {[number]} [高度]
     */
    $.fn.getInnerWidth_ = function() {

        var width, sizeData;
        /* -------------------------------------------- */
        this.each(function(index, el) {
            debugger;

            var dom = this;
            sizeData = $.getDomSizeData_(dom);

            if (index == 0) {
                // 只為了取得高度

                width = sizeData.offsetWidth;
                width -= sizeData.borderRightWidth;
                width -= sizeData.borderLeftWidth;

                return false;
            }
        });
        /* -------------------------------------------- */
        return width;
    };
    /* ====================================================================== */
    /**
     * 用法與(jquery.width)相同
     *
     * 只取高度
     *
     * @return {[type]} [description]
     */
    $.fn.getWidth_ = function() {
        // debugger;

        var width, sizeData;
        /* -------------------------------------------- */
        this.each(function(index, el) {
            debugger;

            var dom = this;
            sizeData = $.getDomSizeData_(dom);

            if (index == 0) {
                // 只為了取得高度

                width = sizeData.offsetWidth;
                width -= sizeData.borderRightWidth;
                width -= sizeData.borderLeftWidth;
                width -= sizeData.paddingRight;
                width -= sizeData.paddingLeft;

                return false;
            }
        });
        /* -------------------------------------------- */
        return width;
    };
    /* ====================================================================== */
})(Area88_);

(js)$Map_

/**
 * 類似(Map)的功能
 */

function $Map_(dataList) {
    var self = this;
    this.size = 0;

    // this.keys = []; // [key, key.......]
    this.dataList = []; // [{k: key, v: value}, {k: key, v: value}.....]


    function __constructor() {
        if (Array.isArray(dataList)) {
            self.dataList = dataList;
            self.size = self.dataList.length;
        }
    };

    __constructor();
};

////////////////////////////////////////////////////////////////////////////////
(function() {
    /**
     *
     * @return {Map}
     */
    this.set = function(key, value) {
        var index;

        var data = {
            'k': key,
            'v': value
        };

        if ((index = this.indexOfKey(key)) >= 0) {
            // 若(key)已經存在
            this.dataList[index] = data;
        } else {
            this.dataList.push(data);
            this.size = this.dataList.length;
        }

        return this;
    };
    /* ====================================================================== */
    this.get = function(key) {
        var index, index, _k, valueObj, checkCount = 0;

        if ((index = this.indexOfKey(key)) <= 0) {
            // 若沒找到(key)
            return result;
        }
        /* ---------------------------------- */
        var data = this.dataList[index];

        return data.v;
    };
}).call($Map_.prototype);

////////////////////////////////////////////////////////////////////////////////
(function() {

    /* ====================================================================== */
    this.clear = function() {
        this.dataList = [];
        this.size = this.dataList.length;
    };
    /* ====================================================================== */
    this.delete = function(key) {
        var index, result = false;

        if ((index = this.indexOfKey) >= 0) {

            this.dataList.splice(index, 1);
            this.size = this.dataList.length;

            result = true;
        }
        return result;
    };
})($Map_.prototype);
////////////////////////////////////////////////////////////////////////////////

(function() {
    this.indexOfKey = function(key) {
        var index = -1;

        if (key == null) {
            return index;
        }

        this.dataList.some(function(data, i) {
            var _key = data.k || undefined;
            if (_key === key) {
                index = i;
                return true;
            }
        });
        return index;
    };

    /* ====================================================================== */
    this.has = function(key) {
        var index, result = false;

        if ((index = this.indexOfKey(key)) >= 0) {
            result = true;
        }
        return result;
    };
}).call($Map_.prototype);

////////////////////////////////////////////////////////////////////////////////
(function() {

    /**
     * 返回(array)
     *
     * @return {array} [keys]
     */
    this.keys = function() {
        var keys_array = [];

        this.dataList.forEach(function(data) {
            var key = data.k;
            keys_array.push(key);
        });

        return keys_array;
    };
    /* ====================================================================== */
    /**
     * 返回(array)
     *
     * @return {array} [values]
     */
    this.values = function() {
        var values_array = [];

        this.dataList.forEach(function(data) {
            var values = data.v;
            values_array.push(values);
        });

        return values_array;
    };
}).call($Map_.prototype);

////////////////////////////////////////////////////////////////////////////////
(function() {
    this.forEach = function(callback) {

        var self = this;

        this.dataList.forEach(function(data, i) {
            var k = data.k;
            var v = data.v;
            /* ------------------------ */
            var copyKey = self.__clone(k);
            var copyData = self.__clone(v);

            /* ------------------------ */
            callback(copyData, copyKey, self);
        });
    };
    /* ====================================================================== */
    this.some = function(callback) {

        var self = this;
        var result = false;
        this.dataList.some(function(data, i) {

            var k = data.k;
            var v = data.v;

            var copyKey = self.__clone(k);
            var copyData = self.__clone(v);
            /* ------------------------ */
            result = callback(copyData, copyKey, self);

            if (result !== true) {
                result = false;
            }
            /* ------------------------ */
            return result;
        });
        return result;
    };
}).call($Map_.prototype);
////////////////////////////////////////////////////////////////////////////////
(function() {
    this.map = function() {

    };
    /* ====================================================================== */
    this.filter = function() {

    };

}).call($Map_.prototype);

////////////////////////////////////////////////////////////////////////////////
(function() {
    /**
     * 依照(key)排序
     */
    this.keySort = function(sortFun) {
        if (typeof sortFun != 'function') {
            throw new TypeError('sortFun must be function');
        }

        this.dataList.sort(_sortFun);
        /* ---------------------------------- */
        function _sortFun(a, b) {
            // 排序的函式
            var key_a = a.k || undefined;
            var key_b = b.k || undefined;

            return sortFun(key_a, key_b);
        }
    };
    /* ====================================================================== */
    this.valueSort = function(sortFun) {
        if (typeof sortFun != 'function') {
            throw new TypeError('sortFun must be function');
        }
        this.dataList.sort(_sortFun);
        /* ---------------------------------- */
        function _sortFun(a, b) {
            // 排序的函式
            var value_a = a.v || undefined;
            var value_b = b.v || undefined;

            var result = sortFun(value_a, value_b);
            return result;
        }
    };
}).call($Map_.prototype);

////////////////////////////////////////////////////////////////////////////////

(function() {
    /**
     * 複製
     */
    this.slice = function() {
        'use strict';
        debugger;

        var arg = [].slice.call(arguments);
        var copyDataList = this.dataList.slice.apply(this.dataList, arg);

        var map = new $Map_(copyDataList);

        return map;
    };
    /* ====================================================================== */
    /**
     * 移除,拼接(不能新增)
     */
    this.splice = function(start, count) {
        'use strict';
        debugger;

        var copyDataList;

        if (arguments.length == 0) {
            copyDataList = this.dataList.splice();
        } else if (arguments.length == 1) {
            copyDataList = this.dataList.splice(start);
        } else {
            // arguments.length > 1
            copyDataList = this.dataList.splice(start, count);
        }

        var map = new $Map_(copyDataList);
        /* ---------------------------------- */
        this.size = this.dataList.length;

        return map;
    };
}).call($Map_.prototype);
////////////////////////////////////////////////////////////////////////////////

(function() {
    this.__clone = function(data) {
        debugger;
        var result;
        if (typeof $.deepCopy_ == 'function') {
            result = $.deepCopy_(data);
        } else {
            result = data;
        }
        return result;
    };
}).call($Map_.prototype);

2016年12月26日 星期一

(js)Area88_event.js

////////////////////////////////////////////////////////////////////////////////
/**
 *
 */
////////////////////////////////////////////////////////////////////////////////

(function($) {
    var eventData = new Map();
    $.eventGuid = 0;
    /**
     * 取得或設定事件的資料
     */
    $.eventData_ = function(dom, name, _data) {
        var data;

        if ((data = eventData.get(dom)) == null) {
            eventData.set(dom, {});
            data = eventData.get(dom);
        }
        /* ---------------------------------- */
        if (arguments.length == 2) {
            return data[name];
        } else if (arguments.length == 1) {
            return data;
        }
        /* ---------------------------------- */
        data[name] = _data;
    };
})(Area88_);


////////////////////////////////////////////////////////////////////////////////
/**
 * trigger
 */
(function($) {

    $.trigger_ = function(dom, eventType, data) {
        var eventObj = document.createEvent("CustomEvent");
        eventObj.initCustomEvent(eventType, true, true, data);

        dom.dispatchEvent(eventObj);
    };
    /* ====================================================================== */
    $.fn.trigger_ = function(eventType, data) {
        this.each(function() {
            $.trigger_(this, eventType, data);
        });
    };
    /* ====================================================================== */
})(Area88_);
////////////////////////////////////////////////////////////////////////////////
/**
 * 事件綁定的核心
 */
(function($) {
    /**
     *
     * @param {boolean} one:只執行一次
     */
    $._bindEvent_ = function(dom, types, fn, data, selector, one) {
        debugger;

        var eventData, events, _handle, namespace;
        var one = one ? true : false;

        eventData = $.eventData_(dom);
        (events = eventData.events) || (events = eventData.events = {});
        (_handle = eventData.handle) || (_handle = eventData.handle = handle);
        _handle.elem = dom;

        /* ---------------------------------- */
        types = types.split(/\s+/gi);

        types.forEach(function(type) {
            namespace = type.split(/\./gi);
            type = namespace.shift();


            if (!fn.guid) {
                fn.guid = ++$.eventGuid;
            }

            var _data = {
                one: one,
                type: type,
                data: data,
                handler: fn,
                guid: fn.guid,
                selector: (typeof selector == 'string' ? selector : ''),
                namspace: (namespace.length ? namespace.join('.') : '')
            };

            if (!events[type]) {
                // 若沒有登錄過該事件
                events[type] = [];
                dom.addEventListener(type, _handle);
            }
            events[type].push(_data);
        });

    };
    /* ====================================================================== */
    /**
     * 事件
     */
    function handle() {
        debugger;
        $._dispatch_.apply(handle.elem, arguments);
    };

    /* ====================================================================== */
    /**
     * 只會進來單一事件
     */
    $._dispatch_ = function() {
        debugger;

        alert('_dispatch_');

        var dom = this; // 事件綁定的dom
        var e = arguments[0];
        var type = e.type;
        var currentTarget = e.currentTarget;
        var target = e.target;
        var events = $.eventData_(dom, 'events');

        var handler_array = events[type] || [];

        // 巡迴該事件要執行的fn
        for (var i = 0; i < handler_array.length; i++) {
            var data = handler_array[i];

            var one = data.one;
            var namspace = data.namespace || '';
            var selector = data.selector;
            var handler = data.handler;

            if (selector) {
                var selectDom = document.querySelector(selector);
                if (selectDom !== target) {
                    continue;
                }
            }
            /* ---------------------------------- */

            //只執行一次的任務
            if (one) {
                handler_array.splice(i, 1);
                i--;
            }
            var result = handler.apply(dom, arguments);
            (result === false) && (e.preventDefault());
        };

    };
})(Area88_);
////////////////////////////////////////////////////////////////////////////////
/**
 * 移除事件的核心
 */
(function($) {
    $._unbindEvent_ = function(dom, types, fn, selector) {
        var events = $.eventData_(dom, 'events');

        if (!events) {
            return;
        }
        types = types.split(/\s+/gi);


        types.forEach(function(type) {
            // 不同事件的迴圈
            var namespace_array = type.split(/\./gi);
            type = namespace.shift();


            var handler_array = events[type] || [];

            for (var i = 0; i < handler_array.length; i++) {

                var _namspace_array = data.namespace.split(/\./gi);;
                var _selector = data.selector;
                var _guid = data.guid;

                var del = false;

                if (!del && typeof selector == 'string' && _selector.localeCompare(selector) == 0) {
                    // check selector
                    del = true;
                }

                if (!del && namespace_array.length > 0 && havveNamespace(namespace_array, _namspace_array)) {
                    // check namespace
                    del = true;
                }

                if (!del && typeof fn == 'function' && typeof fn.guid != 'undefined' && fn.guid === _guid) {}

                if (del) {
                    handler_array.splice(i, 1);
                    i--;
                }
            }
        });
    };

    function havveNamespace(array_1, array_2) {
        var result = false;
        loop1: for (i = 0; i < array_1.length; i++) {
            for (j = 0; j < array_2.length; j++) {

                if (array_1[i] === array_2[j]) {
                    result = true;
                    break loop1;
                }
            }
        }

        return result;
    };
})(Area88_);



////////////////////////////////////////////////////////////////////////////////
(function() {
    /**
     * 綁定事件
     */
    $.fn.on = $.fn.on || function(types, selector, data, fn, one) {
        debugger;
        var type, origFn;

        if (data == null && fn == null) {
            // ( types, fn )
            fn = selector;
            data = selector = undefined;
        } else if (fn == null) {
            if (typeof selector === "string") {
                // ( types, selector, fn )
                fn = data;
                data = undefined;
            } else {
                // ( types, data, fn )
                fn = data;
                data = selector;
                selector = undefined;
            }
        }

        if (typeof fn != 'function') {
            return this;
        }
        /* ---------------------------------- */
        this.each(function(i, dom) {
            debugger;
            $._bindEvent_(this, types, fn, data, selector, one);
        });
        return this;
    };

})(Area88_);

/* ========================================================================== */

(function($) {
    /**
     * 移除事件
     */
    $.fn.off = $.fn.off || function(types, selector, fn) {
        if (arguments.length == 2 && typeof selector == "function") {
            // ( types [, fn] )
            fn = selector;
            selector = undefined;
        }

        if (typeof types != 'string') {
            return this;
        }
        /* ---------------------------------- */
        this.each(function(i, dom) {
            $._unbindEvent_(dom, types, fn, selector);
        });
        return this;
    };
})(Area88_);
/* ========================================================================== */
(function($) {
    /**
     * 綁定只執行一次的事件
     */
    $.fn.one = $.fn.one || function(types, selector, data, fn) {
        this.on(types, selector, data, fn, 1);
        return this;
    };
})(Area88_);

2016年12月22日 星期四

(css)disable - transition, animation

* {
/*CSS transitions*/
-o-transition-property: none !important;
-moz-transition-property: none !important;
-ms-transition-property: none !important;
-webkit-transition-property: none !important;
transition-property: none !important;
/*CSS transforms*/
-o-transform: none !important;
-moz-transform: none !important;
-ms-transform: none !important;
-webkit-transform: none !important;
transform: none !important;
/*CSS animations*/
-webkit-animation: none !important;
-moz-animation: none !important;
-o-animation: none !important;
-ms-animation: none !important;
animation: none !important;
}