API Docs for:
Show:

File: development/modules/bgchanger/js/bgchanger.js

import $ from 'jquery';
import DOMModule from '../../__base/dommodule';
import {isString} from '../../../js/utils/type';
import {uuid} from '../../../js/utils/uuid';
import {tag} from '../../../js/utils/helpers';
import {each} from '../../../js/utils/enums';

/**
 * @module Modules
 */


const _getStylesheet = Symbol('_getStylesheet');
const _insertStyles = Symbol('_insertStyles');



// The RuleParser is used to transform a string from the data-rbg attribute into
//   a rule which can then be inserted into an embedded stylesheet
const RuleParser = {
    defaults() {
        return { url: '', media: null, position: '50% 50%' };
    },
    make(rule) { // creates css rules from parsed atoms
        if (rule.media) {
            return RuleParser.complete(rule)
        }
        return RuleParser.partial(rule);
    },
    parse(atoms) { // parse atoms into basic rules
        return atoms.reduce((rule, atom) => {
            if (isString(atom)) {
                if (/\([\w\-]+?:\s?\d{1,}?(px|em)\)/g.test(atom)) {
                    rule.media = atom;

                } else if (/^\d{1,3}?%\s+?\d{1,3}?%/g.test(atom)) {
                    rule.position = atom;

                } else {
                    rule.url = atom;
                }
            }
            return rule;
        }, RuleParser.defaults());
    },
    complete({media, selector, url, position}) {
        return `@media only screen and ${media} {
            ${selector} {
                background-image: url(${url});
                background-position: ${position};
            }
        }`;
    },
    partial({selector, url, position}) {
        return `${selector} {
            background-image: url(${url});
            background-position: ${position};
        }`;
    }
};



/**
 * BgChanger module
 * @class Modules.BgChanger
 * @constructor
 * @extends Modules._DOMModule
 */
class BgChanger extends DOMModule {
    constructor(options) {
        super(options);
        this.id = this.$rootNode.attr('id');
        if (!this.id) {
            this.id = 'rbg-container_' + uuid();
            this.$rootNode.attr('id', this.id);
        }
    }
    /**
     * Creates a new BgChanger instance without the "new" keyword but does not
     *     initialize it
     * @method of
     * @static
     * @for Modules.BgChanger
     * @param {node|string|configs} node Node, CSS selector or configuration object
     * @return {BgChanger} A new instance
     * 
     * @example
     *     import BgChanger from './modules/bgchanger/js/bgchanger';
     *
     *     const myChanger = BgChanger.of('[data-widget=BgChanger]');
     *     myChanger.init();
     */
    static of(node) {
        return new BgChanger(node);
    }
    /**
     * Finds and initializes all BgChangers on a page at once
     * @method findAll
     * @static
     * @for Modules.BgChanger
     * @param {string} selector CSS selector to match nodes against
     * @return {array} A list of instances
     * 
     * @example
     *     import BgChanger from './modules/bgchanger/js/bgchanger';
     *
     *     BgChanger.findAll('[data-widget=BgChanger]');
     */
    static findAll(selector) {
        return $(selector).toArray().map((node) => {
            const changer = BgChanger.of(node);
            changer.init();
            return changer;
        });
    }
    /**
     * Initializes the instance, thereby creating an embedded stylesheet which
     *     is placed into the <head> element of the document if not already
     *     present
     * @method init
     * @for Modules.BgChanger
     * @return {undefined} Nothing
     * 
     * @example
     *     import BgChanger from './modules/bgchanger/js/bgchanger';
     *
     *     const myChanger = BgChanger.of('[data-widget=BgChanger]');
     *     myChanger.init();
     */
    init() {
        this[_getStylesheet]();
        this[_insertStyles]();
    }
    // === PRIVATE STUFF ===
    [_getStylesheet]() {
        if (BgChanger.embeddedCSS == null) {
            let style = tag('style', {
                type: 'text/css',
                data: {bgchangerStyle: ''},
                innerHTML: ''
            });
            this.$head.append(style);
            
            BgChanger.embeddedCSS = style.sheet;
        }
        return BgChanger.embeddedCSS;
    }
    [_insertStyles]() {
        each(this.$data('rbg'), (cssRule, idx) => {
            const parsed = RuleParser.parse(cssRule.split('|'));
            parsed.selector = `#${this.id}`;
            const rule = RuleParser.make(parsed);
            
            BgChanger.embeddedCSS.insertRule(rule, idx);
        });
    }
}



export default BgChanger;