2
\$\begingroup\$

I've started out working on a larger project using Angular for the first time.
For visual feedback, I'm using Waves (Github) (you can see a demo page here).

The standard way to use Waves is to include the script along with its CSS on the page and once the page has finished loading, call

Waves.init();

to bind to all elements with the predefined classes.

My intent is to wrap the above library in a thin wrapper so I can just use it as a dependency for Angular modules. The below code works for my current use-case, but as this is my first deeper interaction with Angular, I doubt my current approach is a reasonable solution:

  • Include the minified library code as a local variable
  • Initialize the library in the .run()
  • Use a provider to make some configurations accessible, namely passing in a config object as shown in the API docs and adding some additional functionality.

The current code is as follows:

/*
 * Thin wrapper for Waves, original license applies.
 */
! function(angular) {
    "use strict";
    /*!
     * Waves v0.7.4
     * http://fian.my.id/Waves
     *
     * Copyright 2014 Alfiana E. Sibuea and other contributors
     * Released under the MIT license
     * https://github.com/fians/Waves/blob/master/LICENSE
     */
    var waves=function(){"use strict";function t(t){return null!==t&&t===t.window}function e(e){return t(e)?e:9===e.nodeType&&e.defaultView}function n(t){var e=typeof t;return"function"===e||"object"===e&&!!t}function a(t){return n(t)&&t.nodeType>0}function o(t){var e=f.call(t);return"[object String]"===e?d(t):n(t)&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(e)&&t.hasOwnProperty("length")?t:a(t)?[t]:[]}function i(t){var n,a,o={top:0,left:0},i=t&&t.ownerDocument;return n=i.documentElement,"undefined"!=typeof t.getBoundingClientRect&&(o=t.getBoundingClientRect()),a=e(i),{top:o.top+a.pageYOffset-n.clientTop,left:o.left+a.pageXOffset-n.clientLeft}}function r(t){var e="";for(var n in t)t.hasOwnProperty(n)&&(e+=n+":"+t[n]+";");return e}function s(t,e,n){if(n){n.classList.remove("waves-rippling");var a=n.getAttribute("data-x"),o=n.getAttribute("data-y"),i=n.getAttribute("data-scale"),s=n.getAttribute("data-translate"),u=Date.now()-Number(n.getAttribute("data-hold")),c=350-u;0>c&&(c=0),"mousemove"===t.type&&(c=150);var l="mousemove"===t.type?2500:p.duration;setTimeout(function(){var t={top:o+"px",left:a+"px",opacity:"0","-webkit-transition-duration":l+"ms","-moz-transition-duration":l+"ms","-o-transition-duration":l+"ms","transition-duration":l+"ms","-webkit-transform":i+" "+s,"-moz-transform":i+" "+s,"-ms-transform":i+" "+s,"-o-transform":i+" "+s,transform:i+" "+s};n.setAttribute("style",r(t)),setTimeout(function(){try{e.removeChild(n)}catch(t){return!1}},l)},c)}}function u(t){if(h.allowEvent(t)===!1)return null;for(var e=null,n=t.target||t.srcElement;null!==n.parentElement;){if(n.classList.contains("waves-effect")&&!(n instanceof SVGElement)){e=n;break}n=n.parentElement}return e}function c(t){var e=u(t);if(null!==e){if(e.disabled||e.getAttribute("disabled")||e.classList.contains("disabled"))return;if(h.registerEvent(t),"touchstart"===t.type&&p.delay){var n=!1,a=setTimeout(function(){a=null,p.show(t,e)},p.delay),o=function(o){a&&(clearTimeout(a),a=null,p.show(t,e)),n||(n=!0,p.hide(o,e))},i=function(t){a&&(clearTimeout(a),a=null),o(t)};e.addEventListener("touchmove",i,!1),e.addEventListener("touchend",o,!1),e.addEventListener("touchcancel",o,!1)}else p.show(t,e),m&&(e.addEventListener("touchend",p.hide,!1),e.addEventListener("touchcancel",p.hide,!1)),e.addEventListener("mouseup",p.hide,!1),e.addEventListener("mouseleave",p.hide,!1)}}var l=l||{},d=document.querySelectorAll.bind(document),f=Object.prototype.toString,m="ontouchstart"in window,p={duration:750,delay:200,show:function(t,e,n){if(2===t.button)return!1;e=e||this;var a=document.createElement("div");a.className="waves-ripple waves-rippling",e.appendChild(a);var o=i(e),s=0,u=0;"touches"in t&&t.touches.length?(s=t.touches[0].pageY-o.top,u=t.touches[0].pageX-o.left):(s=t.pageY-o.top,u=t.pageX-o.left),u=u>=0?u:0,s=s>=0?s:0;var c="scale("+e.clientWidth/100*3+")",l="translate(0,0)";n&&(l="translate("+n.x+"px, "+n.y+"px)"),a.setAttribute("data-hold",Date.now()),a.setAttribute("data-x",u),a.setAttribute("data-y",s),a.setAttribute("data-scale",c),a.setAttribute("data-translate",l);var d={top:s+"px",left:u+"px"};a.classList.add("waves-notransition"),a.setAttribute("style",r(d)),a.classList.remove("waves-notransition"),d["-webkit-transform"]=c+" "+l,d["-moz-transform"]=c+" "+l,d["-ms-transform"]=c+" "+l,d["-o-transform"]=c+" "+l,d.transform=c+" "+l,d.opacity="1";var f="mousemove"===t.type?2500:p.duration;d["-webkit-transition-duration"]=f+"ms",d["-moz-transition-duration"]=f+"ms",d["-o-transition-duration"]=f+"ms",d["transition-duration"]=f+"ms",a.setAttribute("style",r(d))},hide:function(t,e){e=e||this;for(var n=e.getElementsByClassName("waves-rippling"),a=0,o=n.length;o>a;a++)s(t,e,n[a])}},v={input:function(t){var e=t.parentNode;if("i"!==e.tagName.toLowerCase()||!e.classList.contains("waves-effect")){var n=document.createElement("i");n.className=t.className+" waves-input-wrapper",t.className="waves-button-input",e.replaceChild(n,t),n.appendChild(t);var a=window.getComputedStyle(t,null),o=a.color,i=a.backgroundColor;n.setAttribute("style","color:"+o+";background:"+i),t.setAttribute("style","background-color:rgba(0,0,0,0);")}},img:function(t){var e=t.parentNode;if("i"!==e.tagName.toLowerCase()||!e.classList.contains("waves-effect")){var n=document.createElement("i");e.replaceChild(n,t),n.appendChild(t)}}},h={touches:0,allowEvent:function(t){var e=!0;return/^(mousedown|mousemove)$/.test(t.type)&&h.touches&&(e=!1),e},registerEvent:function(t){var e=t.type;"touchstart"===e?h.touches+=1:/^(touchend|touchcancel)$/.test(e)&&setTimeout(function(){h.touches&&(h.touches-=1)},500)}};return l.init=function(t){var e=document.body;t=t||{},"duration"in t&&(p.duration=t.duration),"delay"in t&&(p.delay=t.delay),m&&(e.addEventListener("touchstart",c,!1),e.addEventListener("touchcancel",h.registerEvent,!1),e.addEventListener("touchend",h.registerEvent,!1)),e.addEventListener("mousedown",c,!1)},l.attach=function(t,e){t=o(t),"[object Array]"===f.call(e)&&(e=e.join(" ")),e=e?" "+e:"";for(var n,a,i=0,r=t.length;r>i;i++)n=t[i],a=n.tagName.toLowerCase(),-1!==["input","img"].indexOf(a)&&(v[a](n),n=n.parentElement),-1===n.className.indexOf("waves-effect")&&(n.className+=" waves-effect"+e)},l.ripple=function(t,e){t=o(t);var n=t.length;if(e=e||{},e.wait=e.wait||0,e.position=e.position||null,n)for(var a,r,s,u={},c=0,l={type:"mousedown",button:1},d=function(t,e){return function(){p.hide(t,e)}};n>c;c++)if(a=t[c],r=e.position||{x:a.clientWidth/2,y:a.clientHeight/2},s=i(a),u.x=s.left+r.x,u.y=s.top+r.y,l.pageX=u.x,l.pageY=u.y,p.show(l,a),e.wait>=0&&null!==e.wait){var f={type:"mouseup",button:1};setTimeout(d(f,a),e.wait)}},l.calm=function(t){t=o(t);for(var e={type:"mouseup",button:1},n=0,a=t.length;a>n;n++)p.hide(e,t[n])},l.displayEffect=function(t){console.error("Waves.displayEffect() has been deprecated and will be removed in future version. Please use Waves.init() to initialize Waves effect"),l.init(t)},l}();
    var config;

    angular.module('angularWaves', [])
    .run(function() {
        angular.element(document).ready(function() {
            //Initialize Waves once the page is ready
            waves.init(config || {});
        });
    })
    .provider('waves', function() {
        //Allow adding new colors to Waves
        //Basic input either as '#FF0000', '#F00', [255,0,0] or {r: 255, b: 0, g: 0}
        this.addColor = function(name, code) {
            var r, g, b;
            if (typeof code === 'string' || code instanceof String) {
                //http://stackoverflow.com/a/5624139/1470607
                code = code.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, function(m, r, g, b) {
                    return r + r + g + g + b + b;
                });
                var raw = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(code);
                if (raw === null) return;
                r = parseInt(raw[1], 16);
                g = parseInt(raw[2], 16);
                b = parseInt(raw[3], 16);
            } else if (Array.isArray(code) && code.length === 3) {
                r = code[0];
                g = code[1];
                b = code[2];
            } else if (code.hasOwnProperty('r') && code.hasOwnProperty('g') && code.hasOwnProperty('b')) {
                r = code.r;
                g = code.g;
                b = code.b;
            } else {
                return this;
            }
            //http://stackoverflow.com/a/524721/1470607
            var css = [];
            css.push('.waves-effect.waves-' + name + ' .waves-ripple {');
            css.push('background: rgba(' + r + ',' + g + ',' + b + ',.4);');
            ['-webkit-', '-o-', '-moz-', ''].forEach(function(prefix) {
                css.push('background: ' + prefix + 'radial-gradient(rgba(' + r + ',' + g + ',' + b + ', .2) 0, rgba(' + r + ',' + g + ',' + b + ', .3) 40%, rgba(' + r + ',' + g + ',' + b + ', .4) 50%, rgba(' + r + ',' + g + ',' + b + ', .5) 60%, rgba(' + r + ',' + g + ',' + b + ', 0) 70%);');
            });
            css.push('}');
            css = css.join('');
            var style = document.createElement('style');
            style.type = 'text/css';
            style.styleSheet ? style.styleSheet.cssText = css : style.appendChild(document.createTextNode(css));
            document.head.appendChild(style);
            return this;
        };

        //Make config available
        this.config = function (newConfig) {
            config = newConfig;
            return this;
        };

        this.$get = function() {
            return waves;
        };
    });
}(window.angular);

As it is, I can currently successfully use it as a dependency:

var app = angular.module('comatic', ['angularWaves']);
app.config([
    'wavesProvider',
    function(wavesProvider) {
        wavesProvider
            .addColor('red', '#F00')
            .config({
                duration: 100
            });
    }
]);

So to shortly recap, is this a reasonable approach (which I doubt) and how could this be improved?

\$\endgroup\$

Your Answer

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

Browse other questions tagged or ask your own question.