2016年12月27日 星期二

(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_);