3
\$\begingroup\$

Concerned with the length of this and the organization. Looking to organize it better if possible. If anyone knows the jQuery equivalent of these methods I would like to put them in the comments.

I'm not interested in changing the style, i.e. - identifier names, whitespace, etc.

/***************************************************************************************************
    **DOM
     - additional coverage for the dom
     - consistent coding style ...
     - fewer function branches
    ***************************************************************************************************/

    (function (win, doc) {

        "use strict";

            // p(R)ivate propeties go here

        var Priv = {},

            // (P)ublic properties go here

            Pub = function (selector) {
                return new Priv.Constructor(selector);
            },

            // (D)ependencies go here

            $A;

        $A = (function manageGlobal() {

            // manually match to utility global
            Priv.g = '$A';
            if (win[Priv.g] && win[Priv.g].pack && win[Priv.g].pack.utility) {

                // utility was found, add dom
                win[Priv.g].pack.dom = true;
            } else {
                throw new Error("dom requires utility module");
            }
            return win[Priv.g];
        }());

        Pub.Debug = (function () {
            var publik = {},
                hold = {};

            // addTags and removeTags can add and remove groups of html tags for
            // visual feedback on how a site works
            publik.addTags = function (tag) {
                if (hold[tag]) {
                    $A.someIndex(hold[tag], function (val) {
                        if (tag === 'script' || tag === 'style') {
                            document.head.appendChild(val);
                        } else {
                            document.body.appendChild(val);
                        }
                    });
                }
            };
            publik.removeTags = function (tag) {
                var styles = document.getElementsByTagName(tag),
                    i;
                hold[tag] = [];
                for (i = styles.length; i; i--) {
                    hold[tag][i] = styles[i];
                    $A.removeElement((styles[i]));
                }
            };

            publik.removeStorage = function () {
                localStorage.clear();
                sessionStorage.clear();
            };

            // extracts z-indices not set to auto
            publik.zIndex = function () {
                var obj_2d = {},
                    elements = document.body.getElementsByTagName("*"),
                    z_index;

                // loop through elements and pull information from them
                $A.someIndex(elements, function (val, index) {
                    z_index = win.getComputedStyle(val).getPropertyValue("z-index");

                    // ignore elements with the auto value
                    if (z_index !== "auto") {
                        obj_2d[index] = [val.id, val.tagName, val.className, z_index];
                    }
                });
                return obj_2d;
            };
            return publik;
        }());

        Pub.el = function (selector_native) {
            if (selector_native) {
                var tokens = selector_native.match(/^(@|#|\.)([\x20-\x7E]+)$/),
                    type,
                    identifier;
                if (!tokens || !tokens[1] || !tokens[2]) {
                    return new Error("mal-formed selector");
                }
                type = tokens[1];
                identifier = tokens[2];
                if (type === '#') {
                    return doc.getElementById(identifier);
                }
                if (type === '.' && doc.getElementsByClassName) {
                    return doc.getElementsByClassName(identifier);
                }
                if (type === '@') {
                    return doc.getElementsByName(identifier);
                }
                return new Error("mal-formed selector");
            }
        };

        Pub.removeElement = function (el) {
            if (el && el.parentNode) {
                return el.parentNode.removeChild(el);
            }
            return null;
        };

        Pub.insertAfter = function (el, ref) {
            if (el && ref && ref.parentNode) {
                return ref.parentNode.insertBefore(el, ref.nextSibling);
            }
            return null;
        };

        Pub.isElement = function (obj) {
            return !!(obj && obj.nodeType === 1);
        };

        Pub.eachChild = function (ref_el, func, con) {
            if (ref_el) {
                var iter_el = ref_el.firstChild,
                    result;
                do {
                    result = func.call(con, iter_el, ref_el);
                    if (result !== undefined) {
                        return result;
                    }
                    iter_el = iter_el.nextSibling;
                } while (iter_el !== null);
            }
            return null;
        };

        Pub.HTMLToElement = function (html) {
            var div = document.createElement('div');
            div.innerHTML = html;
            return div.firstChild;
        };

        Pub.getData = function (id) {
            var data,
                obj = {},
                el = document.getElementById(id);
            if (el.dataset) {
                $A.someKey(el.dataset, function (val, key) {
                    obj[key] = val;
                });
            } else {
                data = $A.filter(el.attributes, function (at) {
                    return (/^data-/).test(at.name);
                });
                $A.someIndex(data, function (val, i) {
                    obj[data[i].name.slice(5)] = val.value;
                });
            }
            return obj;
        };

        Priv.hasClass = function (el, name) {
            return new RegExp('(\\s|^)' + name, 'g').test(el.className);
        };

        Priv.toggleNS = function (el, ns, prop) {
            Pub.someString(el.className, function (val) {
                if (val.match(/toggle_/)) {
                    var names = val.split(/_/);
                    if (names[1] === ns && names[2] !== prop) {
                        Pub.removeClass(el, val);
                    }
                }
            });
        };

        Pub.addClass = function (el, name) {
            if (!Priv.hasClass(el, name)) {
                el.className += (el.className ? ' ' : '') + name;
            }
            var temp = name.match(/toggle_(\w+)_(\w+)/);
            if (temp) {
                Priv.toggleNS(el, temp[1], temp[2]);
                return;
            }
        };

        Pub.removeClass = function (el, name) {
            el.className = name ? el.className.replace(new RegExp('(\\s|^)' +
                    name, 'g'), '') : '';
        };

        Priv.Constructor = function (selector) {
            var type,
                type1,
                type2,
                temp,
                obj_type;

            // $A object detected

            if (selector instanceof Priv.Constructor) {
                return selector;
            }

            // window object detected

            if (selector === win) {
                this[0] = selector;
                return this;
            }

            // document object detected

            if (selector === doc) {
                this[0] = selector;
                return this;
            }

            // element object detected

            if (Pub.isElement(selector)) {
                this[0] = selector;
                return this;
            }

            // only strings should be left

            if (selector) {
                obj_type = $A.getType(selector);
            }

            if (obj_type !== 'String') {
                return this;
            }

            // selector is a symbol follwed by asci

            type = selector.match(/^(@|#|\.)([\x20-\x7E]+)$/);
            if (!type) {
                return this;
            }
            type1 = type[1];
            type2 = type[2];

            // id

            if (type1 === '#') {
                temp = doc.getElementById(type2);
                if (!temp) {
                    return this;
                }
                this[0] = temp;
                return this;
            }

            // class

            if (type1 === '.' && doc.getElementsByClassName) {
                temp = doc.getElementsByClassName(type2);
                if (!temp) {
                    return this;
                }
                $A.someIndex(temp, function (val, index) {
                    this[index] = val;
                }, this);
                return this;
            }

            // name

            if (type1 === '@') {
                temp = doc.getElementsByName(type2);
                if (!temp) {
                    return this;
                }
                $A.someIndex(temp, function (val, index) {
                    this[index] = val;
                }, this);
                return this;
            }
        };

        // jQuery like prototype assignment
        Priv.proto = Priv.Constructor.prototype;

        Priv.proto.fade = function (direction, max_time, callback) {
            var privates = {},
                self = this;

            // initialize
            privates.elapsed = 0;
            privates.GRANULARITY = 10;
            if (privates.timer_id) {
                win.clearInterval(privates.timer_id);
            }

            (function next() {
                privates.elapsed += privates.GRANULARITY;
                if (!privates.timer_id) {
                    privates.timer_id = win.setInterval(next, privates.GRANULARITY);
                }
                if (direction === 'up') {
                    $A.someKey(self, function (val) {
                        val.style.opacity = privates.elapsed / max_time;
                    });

                } else if (direction === 'down') {
                    $A.someKey(self, function (val) {
                        val.style.opacity = (max_time - privates.elapsed) / max_time;
                    });
                }
                if (privates.elapsed >= max_time) {
                    if (callback) {
                        callback();
                    }
                    win.clearInterval(privates.timer_id);
                }
            }());
        };

        Pub.peakOut = function (elem, offset, delay, callback) {
            var privates = {};

            // constants initialization
            privates.RADIX = 10;
            privates.GRAN_TIME = 15;
            privates.GRAN_DIST = 1;
            privates.UNITS = 'px';

            // privates initialization
            privates.el = elem;
            privates.start = parseInt(Pub.getComputedStyle(privates.el).getPropertyValue("top"),
                    privates.RADIX);

            privates.status = 'down';
            privates.end = privates.start + offset;
            privates.current = privates.start;
            privates.id = null;

            (function next() {
                if ((privates.status === 'down') && (privates.current < privates.end)) {
                    privates.current += privates.GRAN_DIST;
                    privates.el.style.top = privates.current + privates.UNITS;
                    if (!privates.id) {
                        privates.id = Pub.setInterval(next, privates.GRAN_TIME);
                    }
                } else if ((privates.status === 'down') && (privates.current === privates.end)) {
                    privates.status = 'up';
                    Priv.resetInterval(privates);
                    Pub.setTimeout(next, delay);
                } else if ((privates.status === 'up') && (privates.current > privates.start)) {
                    privates.current -= privates.GRAN_DIST;
                    privates.el.style.top = privates.current + privates.UNITS;
                    if (!privates.id) {
                        privates.id = Pub.setInterval(next, privates.GRAN_TIME);
                    }
                } else if ((privates.status === 'up') && (privates.current === privates.start)) {
                    Priv.resetInterval(privates);
                    callback();
                }
            }());
        };

        Priv.resetInterval = function (privates) {
            Pub.clearInterval(privates.id);
            privates.id = 0;
        };

        Priv.expandFont = function (direction, max_time) {
            var self = this,
                el_prim = self[0],
                privates = {};

            if (el_prim.timer_id) {
                return;
            }

            el_prim.style.fontSize = Pub.getComputedStyle(el_prim,
                    null).getPropertyValue("font-size");

            privates.final_size = parseInt(el_prim.style.fontSize, privates.RADIX);
            privates.GRANULARITY = 10;
            privates.time_elapsed = 0;
            (function next() {
                $A.someKey(self, function (val) {
                    if (direction === 'up') {
                        val.style.fontSize = ((privates.time_elapsed / max_time) *
                                privates.final_size) + 'px';

                    } else if (direction === 'down') {
                        val.style.fontSize = ((max_time - privates.time_elapsed) /
                                max_time) + 'px';
                    }
                });
                privates.time_elapsed += privates.GRANULARITY;

                // completed, do not call next

                if (el_prim.timer_id_done) {
                    Pub.clearTimeout(el_prim.timer_id);
                    el_prim.timer_id = undefined;
                    el_prim.timer_id_done = undefined;

                // intermediate call to next

                } else if (privates.time_elapsed < max_time) {
                    el_prim.timer_id = Pub.setTimeout(next, privates.GRANULARITY);

                // normalizing call to guarante (elapsed === max)

                } else if (privates.time_elapsed >= max_time) {
                    el_prim.timer_id = Pub.setTimeout(next, privates.GRANULARITY);
                    el_prim.timer_id_done = true;
                    privates.time_elapsed = max_time;
                }
            }());
        };

        Priv.proto.expandFont = function (direction, max_time, big_size) {
            return Priv.expandFont.call(this, direction, max_time, big_size);
        };

        Pub.expandFont = (function () {
            return function (element, direction, max_time, big_size) {
                var temp = [];
                temp[0] = element;
                Priv.expandFont.call(temp, direction, max_time, big_size);
            };
        }());

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

        Priv.functionNull = function () {
            return undefined;
        };

        // createEvent

        Priv.createEvent = function () {
            if (doc.createEvent) {
                return function (type) {
                    var event = doc.createEvent("HTMLEvents");
                    event.initEvent(type, true, false);
                    $A.someKey(this, function (val) {
                        val.dispatchEvent(event);
                    });
                };
            }
            if (doc.createEventObject) {
                return function (type) {
                    var event = doc.createEventObject();
                    event.eventType = type;
                    $A.someKey(this, function (val) {
                        val.fireEvent('on' + type, event);
                    });
                };
            }
            return Priv.functionNull;
        };

        Priv.proto.createEvent = function (type) {
            return Priv.createEvent.call(this, type);
        };

        Pub.createEvent = (function () {
            return function (element, type) {
                var temp = [];
                temp[0] = element;
                Priv.createEvent.call(temp, type);
            };
        }());

        // addEvent

        Priv.addEvent = (function () {
            if (win.addEventListener) {
                return function (type, callback) {
                    $A.someKey(this, function (val) {
                        val.addEventListener(type, callback);
                    });
                };
            }
            if (win.attachEvent) {
                return function (type, callback) {
                    $A.someKey(this, function (val) {
                        val.attachEvent('on' + type, callback);
                    });
                };
            }
            return Priv.functionNull;
        }());

        Priv.proto.addEvent = function (type, callback) {
            return Priv.addEvent.call(this, type, callback);
        };

        Pub.addEvent = (function () {
            return function (element, type, callback) {
                var temp = [];
                temp[0] = element;
                Priv.addEvent.call(temp, type, callback);
            };
        }());

        Priv.proto.removeEvent = (function () {
            if (win.removeEventListener) {
                return function (type, callback) {
                    $A.someKey(this, function (val) {
                        val.removeEventListener(type, callback);
                    });
                };
            }
            if (win.detachEvent) {
                return function (type, callback) {
                    $A.someKey(this, function (val) {
                        val.detachEvent('on' + type, callback);
                    });
                };
            }
            return Priv.functionNull;
        }());

        Priv.proto.removeEvent = function (type, callback) {
            return Priv.removeEvent.call(this, type, callback);
        };

        Pub.removeEvent = (function () {
            return function (element, type, callback) {
                var temp = [];
                temp[0] = element;
                Priv.removeEvent.call(temp, type, callback);
            };
        }());

        Pub.ajax = function (config_ajax) {
            var xhr;

            // get
            if (config_ajax.type === 'get') {
                xhr = new win.XMLHttpRequest();
                xhr.open('GET', config_ajax.url, true);
                xhr.onload = function () {
                    if (this.status === 200) {
                        config_ajax.callback(xhr.responseText);
                    }
                };
                xhr.send(null);
            }

            // post
            if (config_ajax.type === 'post') {
                xhr = new win.XMLHttpRequest();
                xhr.open("POST", config_ajax.url, true);
                xhr.setRequestHeader("Content-type",
                        "application/x-www-form-urlencoded");
                xhr.onload = function () {
                    if (this.status === 200) {
                        config_ajax.callback(xhr.responseText);
                    }
                };
                xhr.send(config_ajax.data);
            }

            // post for form_data
            if (config_ajax.type === 'multi') {
                xhr = new win.XMLHttpRequest();
                xhr.open("POST", config_ajax.url, true);
                xhr.onload = function () {
                    if (this.status === 200) {
                        config_ajax.callback(xhr.responseText);
                    }
                };
                xhr.send(config_ajax.data);
            }

        };

        Priv.Queue = (function () {
            var queue = [],
                publik = {};
            function getIndexFromToken(callback) {
                var hold;
                $A.someIndex(queue, function (val, index) {
                    if (val.callback === callback) {
                        hold = index;
                        return index;
                    }
                });
                return hold;
            }
            function getBlockedProperty(item) {
                var blocked;
                if (item) {
                    blocked = item.blocked;
                } else {
                    blocked = false;
                }
                return blocked;
            }
            publik.addItem = function (callback) {
                var temp = {};
                temp.blocked = false;
                temp.callback = callback;
                temp.response_text = null;
                queue.push(temp);
            };
            publik.itemCompleted = function (response_text, callback) {
                var index,
                    item,
                    blocked;
                index = getIndexFromToken(callback);
                if (index !== 0) {
                    queue[index].blocked = true;
                    queue[index].response_text = response_text;
                } else {
                    item = queue.shift();
                    item.callback(response_text);
                    blocked = getBlockedProperty(queue[0]);
                    while (blocked) {
                        item = queue.shift();
                        item.callback(item.response_text);
                        blocked = getBlockedProperty(queue[0]);
                    }
                }
            };
            return publik;
        }());

        Pub.serialAjax = function (source, callback) {
            Priv.Queue.addItem(callback);
            Pub.ajax({
                type:       'get',
                url:        source,
                callback:   function (response_text) {
                    Priv.Queue.itemCompleted(response_text, callback);
                }
            });
        };

        Pub.setTimeout = function () {
            return win.setTimeout.apply(win, arguments);
        };

        Pub.clearTimeout = function () {
            return win.clearTimeout.apply(win, arguments);
        };

        Pub.setInterval = function () {
            return win.setInterval.apply(win, arguments);
        };

        Pub.clearInterval = function () {
            return win.clearInterval.apply(win, arguments);
        };

        Pub.getComputedStyle = function () {
            return win.getComputedStyle.apply(win, arguments);
        };

        Pub.createDocumentFragment = function () {
            return doc.createDocumentFragment.apply(doc, arguments);
        };

        Pub.createElement = function () {
            return doc.createElement.apply(doc, arguments);
        };

        Pub.FormData = win.FormData;

        Pub.FileReader = win.FileReader;

        Pub.localStorage = win.localStorage;

        Pub.sessionStorage = win.sessionStorage;

        Pub.log = function (obj) {
            var logger,
                type,
                temp,
                completed;

            // wrap win.console to protect from IE
            // bind to satisfy Safari
            if (win.console) {
                logger = win.console.log.bind(win.console);
            } else {
                return;
            }

            // validation
            type = $A.getType(obj);
            if (!type) {
                logger("Object did not stringify");
                return;
            }

            // host objects
            if (type === 'Event') {
                logger('LOG|host|event>');
                logger(obj);
                return;
            }

            // library objects
            if (win.jQuery && (obj instanceof win.jQuery)) {
                logger('LOG|library|jquery>');
                logger(obj);
                return;
            }

            // language objects
            $A.someIndex(['Arguments', 'Array', 'Object'], function (val) {
                if (type === val) {
                    try {
                        temp = JSON.stringify(obj, null, 1);
                    } catch (e) {
                        temp = false;
                    }
                    if (temp) {
                        logger('LOG|language|' + type + '>');
                        logger(temp);
                    } else {
                        logger('LOG|language|' + type + '>');
                        logger(obj);
                    }
                    completed = true;
                }
            });

            if (completed) {
                return;
            }

            $A.someIndex(['Boolean', 'Date', 'Error', 'Function', 'JSON', 'Math',
                'Number', 'Null', 'RegExp', 'String', 'Undefined'],
                function (val) {
                    if (type === val) {
                        logger('LOG|language|' + type + '>');
                        logger(obj);
                        completed = true;
                    }
                });

            if (completed) {
                return;
            }

            // remaining

            logger('LOG|not_implemented|>');
            logger(obj);
            return;

        };
        win[Priv.g] = $A.extendSafe(Pub, $A);
    }(window, window.document));
\$\endgroup\$
  • 3
    \$\begingroup\$ "Concerned with the length of this and the organization", Ironically the StackExchange system automatically flagged this question as "excessively long" :) There's nothing wrong with your question though. \$\endgroup\$ – Simon Forsberg Jan 23 '14 at 21:10
4
\$\begingroup\$

From a once over

  • ASCII header, using "use strict" in a surrounding function, good stuff
  • addTags, would have been nice if the caller could set the parent to which the tags should be added ( a la jQuery )
  • addTags, it is unclear from naming what hold is, what is supposed to do, there are no explaining comments either
  • addTags, it is clear after reading removeTags, maybe you should put that function there
  • addTags, removeTags, the code does not put the tags back from where they were removed, that is a very limited feature
  • removeTags -> styles seems an unfortunate name, the parameter could have been called tagName
  • removeStorage -> Seems to be the wrong library, you have different a library for storage already
  • zIndex -> why not just return the elements in the array ? It would take less memory, while returning more info
  • Pub.el needs a comment with sample selector_native values
  • Pub.removeElement etc., silent failures, could be frustrating
  • isElement -> !! on a Boolean expression seems pointless, update : it is not pointless, it will convert a falsey value to the boolean false.
  • eachChild -> some cryptic names, not following lowerCamelCase, the name is lying since it is not guaranteed to iterate over each child
  • HTMLToElement is smart, but could use a comment as to how it works
  • someKey -> sigh.. , really you should use js 1.6, or use the shims
  • Priv.Constructor -> too much white space by far
  • win -> you are making it too hard, just use window
  • doc -> seriously..
  • (/^(@|#|\.)([\x20-\x7E]+)$/ is used twice, you should give it a good name in a constant
  • You are having code in Priv.Constructor that is very similar to what is in Pub.el, consider merging some of this code

From here I still only reviewed half of the code. Your helper functions like expandFont really need each a few lines of comment so that the reader can easily determine what it does ( yes, it increase the font but what does max_time, big_size and direction do ?? )

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Done. However, since your code never checks for boolean equality with === it still is kind of pointless ;) \$\endgroup\$ – konijn Jan 27 '14 at 15:55
  • \$\begingroup\$ I'm not interested in advice on style - identifier names, whitespace, etc. I've updated the question to reflect this, so you can remove those bullets as well. \$\endgroup\$ – user34330 Jan 27 '14 at 16:00
  • 3
    \$\begingroup\$ @www.arcmarks.com reviewers are free to comment on any aspect of the code you post, not just what you deem useful. \$\endgroup\$ – Mathieu Guindon Jan 27 '14 at 16:25
  • \$\begingroup\$ right its your content, take it. \$\endgroup\$ – user34330 Jan 27 '14 at 16:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy