fgnass / spin.js

A spinning activity indicator
http://spin.js.org
MIT License
9.3k stars 1.02k forks source link

!function not bundle friendly #96

Closed Romiko closed 12 years ago

Romiko commented 12 years ago

Hi,

Please can you update the code to use the brackets instead of !function, else it is not bundle friendly and throws exceptions.

so, rather have it as:

Here is the full code that now works. notice the semicolon at the end of the wrapped function and use of round brackets:

(function (window, document, undefined) { var prefixes = ['webkit', 'Moz', 'ms', 'O']; var animations = {}; var useCssAnimations; function createEl(tag, prop) { var el = document.createElement(tag || 'div'), n;

    for (n in prop)
        el[n] = prop[n];

    return el;
}

function ins(parent) {
    for (var i = 1, n = arguments.length; i < n; i++)
        parent.appendChild(arguments[i]);

    return parent;
}

var sheet = function () {
    var el = createEl('style', { type: 'text/css' });
    ins(document.getElementsByTagName('head')[0], el);
    return el.sheet || el.styleSheet;
}();

function addAnimation(alpha, trail, i, lines) {
    var name = ['opacity', trail, ~~(alpha * 100), i, lines].join('-');
    var start = 0.01 + i / lines * 100;
    var z = Math.max(1 - (1 - alpha) / trail * (100 - start), alpha);
    var prefix = useCssAnimations.substring(0, useCssAnimations.indexOf('Animation')).toLowerCase();
    var pre = prefix && '-' + prefix + '-' || '';

    if (!animations[name]) {
        sheet.insertRule(
            '@' + pre + 'keyframes ' + name + '{' +
                '0%{opacity:' + z + '}' +
                start + '%{opacity:' + alpha + '}' +
                (start + 0.01) + '%{opacity:1}' +
                (start + trail) % 100 + '%{opacity:' + alpha + '}' +
                '100%{opacity:' + z + '}' +
                '}', sheet.cssRules.length);

        animations[name] = 1;
    }
    return name;
}

function vendor(el, prop) {
    var s = el.style;
    var pp;
    var i;

    if (s[prop] !== undefined) return prop;
    prop = prop.charAt(0).toUpperCase() + prop.slice(1);
    for (i = 0; i < prefixes.length; i++) {
        pp = prefixes[i] + prop;
        if (s[pp] !== undefined)
            return pp;
    }
    return null;
}

function css(el, prop) {
    for (var n in prop)
        el.style[vendor(el, n) || n] = prop[n];

    return el;
}

function merge(obj) {
    for (var i = 1; i < arguments.length; i++) {
        var def = arguments[i];
        for (var n in def)
            if (obj[n] === undefined) obj[n] = def[n];
    }
    return obj;
}

function pos(el) {
    var o = { x: el.offsetLeft, y: el.offsetTop };
    while ((el = el.offsetParent))
        o.x += el.offsetLeft, o.y += el.offsetTop;

    return o;
}

var defaults = {
    lines: 12,            // The number of lines to draw
    length: 7,            // The length of each line
    width: 5,             // The line thickness
    radius: 10,           // The radius of the inner circle
    rotate: 0,            // Rotation offset
    corners: 1,           // Roundness (0..1)
    color: '#000',        // #rgb or #rrggbb
    speed: 1,             // Rounds per second
    trail: 100,           // Afterglow percentage
    opacity: 1 / 4,         // Opacity of the lines
    fps: 20,              // Frames per second when using setTimeout()
    zIndex: 2e9,          // Use a high z-index by default
    className: 'spinner', // CSS class to assign to the element
    top: 'auto',          // center vertically
    left: 'auto'          // center horizontally
};

spinner = function spinner(o) {
    if (!this.spin) return new spinner(o);
    this.opts = merge(o || {}, spinner.defaults, defaults);
    return null;
};
spinner.defaults = {};

merge(spinner.prototype, {
    spin: function (target) {
        this.stop();
        var self = this;
        var o = self.opts;
        var el = self.el = css(createEl(0, { className: o.className }), { position: 'relative', width: 0, zIndex: o.zIndex });
        var mid = o.radius + o.length + o.width;
        var ep;
        var tp;

        if (target) {
            target.insertBefore(el, target.firstChild || null);
            tp = pos(target);
            ep = pos(el);
            css(el, {
                left: (o.left == 'auto' ? tp.x - ep.x + (target.offsetWidth >> 1) : parseInt(o.left, 10) + mid) + 'px',
                top: (o.top == 'auto' ? tp.y - ep.y + (target.offsetHeight >> 1) : parseInt(o.top, 10) + mid) + 'px'
            });
        }

        el.setAttribute('aria-role', 'progressbar');
        self.lines(el, self.opts);

        if (!useCssAnimations) {
            var i = 0;
            var fps = o.fps;
            var f = fps / o.speed;
            var ostep = (1 - o.opacity) / (f * o.trail / 100);
            var astep = f / o.lines;

            (function anim() {
                i++;
                for (var s = o.lines; s; s--) {
                    var alpha = Math.max(1 - (i + s * astep) % f * ostep, o.opacity);
                    self.opacity(el, o.lines - s, alpha, o);
                }
                self.timeout = self.el && setTimeout(anim, ~~(1000 / fps));
            })();
        }
        return self;
    },

    stop: function () {
        var el = this.el;
        if (el) {
            clearTimeout(this.timeout);
            if (el.parentNode) el.parentNode.removeChild(el);
            this.el = undefined;
        }
        return this;
    },

    lines: function (el, o) {
        var i = 0, seg;

        function fill(color, shadow) {
            return css(createEl(), {
                position: 'absolute',
                width: (o.length + o.width) + 'px',
                height: o.width + 'px',
                background: color,
                boxShadow: shadow,
                transformOrigin: 'left',
                transform: 'rotate(' + ~~(360 / o.lines * i + o.rotate) + 'deg) translate(' + o.radius + 'px' + ',0)',
                borderRadius: (o.corners * o.width >> 1) + 'px'
            });
        }

        for (; i < o.lines; i++) {
            seg = css(createEl(), {
                position: 'absolute',
                top: 1 + ~(o.width / 2) + 'px',
                transform: o.hwaccel ? 'translate3d(0,0,0)' : '',
                opacity: o.opacity,
                animation: useCssAnimations && addAnimation(o.opacity, o.trail, i, o.lines) + ' ' + 1 / o.speed + 's linear infinite'
            });

            if (o.shadow) ins(seg, css(fill('#000', '0 0 4px ' + '#000'), { top: 2 + 'px' }));

            ins(el, ins(seg, fill(o.color, '0 0 1px rgba(0,0,0,.1)')));
        }
        return el;
    },

    opacity: function (el, i, val) {
        if (i < el.childNodes.length) el.childNodes[i].style.opacity = val;
    }

});

(function () {

    function vml(tag, attr) {
        return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr);
    }

    var s = css(createEl('group'), { behavior: 'url(#default#VML)' });

    if (!vendor(s, 'transform') && s.adj) {
        sheet.addRule('.spin-vml', 'behavior:url(#default#VML)');
        spinner.prototype.lines = function (el, o) {
            var r = o.length + o.width, ss = 2 * r;

            function grp() {
                return css(
                    vml('group', {
                        coordsize: s + ' ' + s,
                        coordorigin: -r + ' ' + -r
                    }),
                    { width: ss, height: ss }
                );
            }

            var margin = -(o.width + o.length) * 2 + 'px', g = css(grp(), { position: 'absolute', top: margin, left: margin }), i;

            function seg(ii, dx, filter) {
                ins(g,
                    ins(css(grp(), { rotation: 360 / o.lines * ii + 'deg', left: ~~dx }),
                        ins(css(vml('roundrect', { arcsize: o.corners }), {
                            width: r,
                            height: o.width,
                            left: o.radius,
                            top: -o.width >> 1,
                            filter: filter
                        }),
                            vml('fill', { color: o.color, opacity: o.opacity }),
                            vml('stroke', { opacity: 0 })
                        )
                    )
                );
            }

            if (o.shadow)
                for (i = 1; i <= o.lines; i++)
                    seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)');

            for (i = 1; i <= o.lines; i++) seg(i);
            return ins(el, g);
        };

        spinner.prototype.opacity = function (el, i, val, o) {
            var c = el.firstChild;
            o = o.shadow && o.lines || 0;
            if (c && i + o < c.childNodes.length) {
                c = c.childNodes[i + o];
                c = c && c.firstChild;
                c = c && c.firstChild;
                if (c) c.opacity = val;
            }
        };
    } else
        useCssAnimations = vendor(s, 'animation');
})();

if (typeof window.define == 'function' && window.define.amd)
    window.define(function () { return spinner; });
else
    window.Spinner = spinner;

})(window, document);

Thanks for a great utility :)

Romiko commented 12 years ago

Fixed in ce1230c3c7710e2c763cabcbe5c5859c255e81f8