core.js 5.61 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
(function($, JSON) {

    'use strict';

    function initializeBlockLikes(block_class, initializer, element, requestToken) {
        var requestToken = requestToken || $(element).data('request-token');
        if (requestToken) {
            var selector = '.' + block_class + '[data-request-token="' + requestToken + '"]';
        } else {
            var selector = '.' + block_class;
        }
        return $(element).immediateDescendents(selector).map(function(idx, elem) {
            return initializer(elem, requestToken);
        }).toArray();
    }

    function elementRuntime(element) {
        var $element = $(element);
        var runtime = $element.data('runtime-class');
        var version = $element.data('runtime-version');
        var initFnName = $element.data('init');

        if (runtime && version && initFnName) {
            return new window[runtime]['v' + version];
        } else {
26
            if (runtime || version || initFnName) {
27 28
                var elementTag = $('<div>').append($element.clone()).html();
                console.log('Block ' + elementTag + ' is missing data-runtime, data-runtime-version or data-init, and can\'t be initialized');
29
            } // else this XBlock doesn't have a JS init function.
30 31 32 33 34
            return null;
        }
    }

    function initArgs(element) {
35
        var initargs = $(element).children('.xblock-json-init-args').remove().text();
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
        return initargs ? JSON.parse(initargs) : {};
    }

    /**
     * Construct an XBlock family object from an element. The constructor
     * function is loaded from the 'data-init' attribute of the element.
     * The constructor is called with the arguments 'runtime', 'element',
     * and then all of 'block_args'.
     */
    function constructBlock(element, block_args) {
        var block;
        var $element = $(element);
        var runtime = elementRuntime(element);

        block_args.unshift(element);
        block_args.unshift(runtime);


        if (runtime) {

            block = (function() {
                var initFn = window[$element.data('init')];

                // This create a new constructor that can then apply() the block_args
                // to the initFn.
                function Block() {
                    return initFn.apply(this, block_args);
                }
                Block.prototype = initFn.prototype;

                return new Block();
            })();
            block.runtime = runtime;
        } else {
            block = {};
        }
        block.element = element;
        block.name = $element.data('name');
        block.type = $element.data('block-type');
        $element.trigger('xblock-initialized');
        $element.data('initialized', true);
        $element.addClass('xblock-initialized');
        return block;
    }

    var XBlock = {
        Runtime: {},

        /**
         * Initialize the javascript for a single xblock element, and for all of it's
         * xblock children that match requestToken. If requestToken is omitted, use the
         * data-request-token attribute from element, or use the request-tokens specified on
         * the children themselves.
         */
        initializeBlock: function(element, requestToken) {
            var $element = $(element);

            var requestToken = requestToken || $element.data('request-token');
            var children = XBlock.initializeXBlocks($element, requestToken);
            $element.prop('xblock_children', children);

            return constructBlock(element, [initArgs(element)]);
        },

        /**
         * Initialize the javascript for a single xblock aside element that matches requestToken.
         * If requestToken is omitted, use the data-request-token attribute from element, or use
         * the request-tokens specified on the children themselves.
         */
        initializeAside: function(element, requestToken) {
            var blockUsageId = $(element).data('block-id');
            var blockElement = $(element).siblings('[data-usage-id="' + blockUsageId + '"]')[0];
            return constructBlock(element, [blockElement, initArgs(element)]);
        },

        /**
         * Initialize all XBlocks inside element that were rendered with requestToken.
         * If requestToken is omitted, and element has a 'data-request-token' attribute, use that.
         * If neither is available, then use the request tokens of the immediateDescendent xblocks.
         */
        initializeXBlocks: function(element, requestToken) {
            return initializeBlockLikes('xblock', XBlock.initializeBlock, element, requestToken);
        },

        /**
         * Initialize all XBlockAsides inside element that were rendered with requestToken.
         * If requestToken is omitted, and element has a 'data-request-token' attribute, use that.
         * If neither is available, then use the request tokens of the immediateDescendent xblocks.
         */
        initializeXBlockAsides: function(element, requestToken) {
            return initializeBlockLikes('xblock_asides-v1', XBlock.initializeAside, element, requestToken);
        },

        /**
         * Initialize all XBlock-family blocks inside element that were rendered with requestToken.
         * If requestToken is omitted, and element has a 'data-request-token' attribute, use that.
         * If neither is available, then use the request tokens of the immediateDescendent xblocks.
         */
        initializeBlocks: function(element, requestToken) {
            XBlock.initializeXBlockAsides(element, requestToken);
            return XBlock.initializeXBlocks(element, requestToken);
        }
    };

    this.XBlock = XBlock;

}).call(this, $, JSON);