all files / montage/composer/ composer.js

41.18% Statements 7/17
15.38% Branches 2/13
50% Functions 5/10
41.18% Lines 7/17
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 26 27 28 29 30 31 32 33 34 35 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 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200                                                                          139×     580×                                           528×     544×                                                                                                                                     64×                                                                                                                                  
/**
 * @module montage/composer/composer
 * @requires montage/core/target
 */
var Target = require("../core/target").Target;
 
/**
 * The `Composer` helps to keep event normalization and calculation out of
 * specific `Component`s and in a reusable place. For example, the
 * `TranslateComposer` handles listening to different mouse and touch events
 * that represent dragging, and emits common `translate` events with helpful
 * information about the move.
 *
 * Specific composersshould specialize this `Composer` class and implement the
 * `load` and `unload` methods to attach and remove their event listeners.
 * Subclasses can also implement `frame` if they need access to their
 * component's draw cycle.
 *
 * @classdesc Abstracts a pattern of DOM events, emitting more useful,
 * higher-level events.
 * @class Composer
 * @extends Target
 */
exports.Composer = Target.specialize( /** @lends Composer# */ {
 
    _component: {
        value: null
    },
 
    /**
     * The Montage `Component` this `Composer` is attached to. Each composer is
     * attached to a single component. By default, most composer will listen to
     * DOM events on this component's element. This is also the component whose
     * draw cycle is affected by `needsFrame` and `frame`.
     * @type {Component}
     * @default null
     */
    component: {
        get: function () {
            return this._component;
        },
        set: function (component) {
            this._component = component;
        }
    },
 
    _element: {
        value: null
    },
 
    /**
     * The DOM element where the composer will listen for events. If no element
     * is specified then the composer will use the element associated with its
     * `component` property.
     *
     * Subclasses may want to set their `element` to something other than the
     * component's element during `load` for certain event patterns. One common
     * pattern is to set element to `window` to listen for events anywhere on
     * the page.
     * @type {Element}
     * @default null
     */
    element: {
        get: function () {
            return this._element;
        },
        set: function (element) {
            this._element = element;
        }
    },
 
 
    /**
     * This property controls when the component will call this composer's
     * `load` method, which is where the composer adds its event listeners:
     *
     * - If `false`, the component will call `load` during the next draw cycle
     *   after the composer is added to it.
     * - If `true`, the component will call `load` after its
     *   `prepareForActivationEvents`.
     *
     * Delaying the creation of event listeners can improve performance.
     * @default true
     */
    lazyLoad: {
        value: true
    },
 
    _needsFrame: {
        value: false
    },
 
    /**
     * This property should be set to 'true' when the composer wants to have
     * its `frame()` method executed during the next draw cycle. Setting this
     * property to 'true' will cause Montage to schedule a new draw cycle if
     * one has not already been scheduled.
     * @type {boolean}
     * @default false
     */
    needsFrame: {
        set: function (value) {
            if (this._needsFrame !== value) {
                this._needsFrame = value;
 
                if (this._component && value) {
                    this._component.scheduleComposer(this);
                }
            }
        },
        get: function () {
            return this._needsFrame;
        }
    },
 
    /**
     * This method will be invoked by the framework at the beginning of a draw
     * cycle. This is where a composer may implement its update logic if it
     * needs to respond to draws by its component.
     * @function
     * @param {Date} timestamp The time that the draw cycle started
     */
    frame: {
        value: Function.noop
    },
 
 
    /**
     * Invoked by the framework to default the composer's element to the
     * component's element if necessary.
     * @private
     */
    _resolveDefaults: {
        value: function () {
            Iif (!this.element && this.element == null && this.component != null) {
                this.element = this.component.element;
            }
        }
    },
 
    _isLoaded: {
        value: false
    },
 
    isLoaded: {
        get: function () {
            return this._isLoaded;
        }
    },
 
    /**
     * The component calls `load` on its composers when they should initialize
     * themselves. Exactly when this happens is controlled by the composer's
     * `lazyLoad` property.
     *
     * Subclasses should override `load` with their DOM initialization. Most
     * composers attach DOM event listeners to `this.element` in `load`.
     *
     * @function
     */
    load: {
        value: Function.noop
    },
 
    /**
     * The `component` will call `unload` when the composer is removed from the
     * component or the component is removed.
     *
     * Subclasses should override `unload` to do any necessary cleanup, such as
     * removing event listeners.
     *
     * @function
     */
    unload: {
        value: Function.noop
    },
 
    /**
     * Called when a composer is part of a template serialization. It's
     * responsible for calling `addComposer` on the component.
     * @private
     */
    deserializedFromTemplate: {
        value: function () {
            if (this.component) {
                this.component.addComposer(this);
            }
        }
    }
 
}, {
 
    isCoordinateOutsideRadius: {
        value: function (x, y, radius) {
            return x * x + y * y > radius * radius;
        }
    }
 
});