<commit_before>class StoriesAPI {

    constructor() {
        this.sections = {};
    }

    section(name) {
        if (!this.sections[name]) {
            this.sections[name] = {};
        }

        let sectionAPI = {};

        sectionAPI.story = (storyName) => {
            let section = this.sections[name];
            let storyAPI = {};
            storyAPI.add = (title, template, model) => {
                if (!section[storyName]) {
                    section[storyName] = [];
                }
                section[storyName].push({ title, template, model });
            }
            return storyAPI;
        };

        return sectionAPI;

    }

    getSections() {
        return this.sections;
    }

}

window.sb = new StoriesAPI();<commit_msg>Maked section.add chineble<commit_after>class StoriesAPI {

    constructor() {
        this.sections = {};
    }

    section(name) {
        if (!this.sections[name]) {
            this.sections[name] = {};
        }

        let sectionAPI = {};

        sectionAPI.story = (storyName) => {
            let section = this.sections[name];
            let storyAPI = {};
            storyAPI.add = (title, template, model) => {
                if (!section[storyName]) {
                    section[storyName] = [];
                }
                section[storyName].push({ title, template, model });
                return storyAPI;
            }
            return storyAPI;
        };

        return sectionAPI;

    }

    getSections() {
        return this.sections;
    }

}

window.sb = new StoriesAPI();<|endoftext|>


<commit_before>/**
 * @file Pipes for streams
 */
/*#ifndef(UMD)*/
"use strict";
/*global _GPF_EVENT_ANY*/ // gpf.events.EVENT_ANY
/*global _GPF_EVENT_DATA*/ // gpf.events.EVENT_DATA
/*global _GPF_EVENT_END_OF_DATA*/ // gpf.events.EVENT_END_OF_DATA
/*global _GPF_EVENT_READY*/ // gpf.events.EVENT_READY
/*global _GPF_STREAM_DEFAULT_READ_SIZE*/ // Global default for stream read size
/*global _gpfEventsFire*/ // gpf.events.fire (internal, parameters must match)
/*global _gpfI*/ // gpf.interfaces
/*global _gpfIgnore*/ // Helper to remove unused parameter warning
/*global _gpfQueryInterface*/ // gpf.interfaces.query
/*exported _gpfStreamPipe*/ // gpf.stream.pipe
/*#endif*/

/**
 * @inheritdoc _gpfStreamPipe
 * @constructor
 */
function _GpfStreamPipe (configuration, eventsHandler) {
    /*jshint validthis:true*/ // constructor
    this._readable = _gpfQueryInterface(configuration.readable, _gpfI.IReadableStream, true);
    this._writable = _gpfQueryInterface(configuration.writable, _gpfI.IWritableStream, true);
    if (undefined !== configuration.chunkSize) {
        this._chunkSize = configuration.chunkSize;
    }
    this._eventsHandler = eventsHandler;
}

_GpfStreamPipe.prototype = {
    // @property {gpf.interfaces.IReadableStream} Read stream
    _readable: null,        // Readable stream
    // @property {gpf.interfaces.IWritableStream} Write stream
    _writable: null,        // Writable stream
    // @property {Number} Buffer size to read data
    _chunkSize: _GPF_STREAM_DEFAULT_READ_SIZE,
    // @property {gpf.events.EventHandler} events handler
    _eventsHandler: null,   // Original
    // @property {_GpfStreamPipe} itself
    scope: null
};

// gpf.events.EVENT_READY event handler
_GpfStreamPipe.prototype[_GPF_EVENT_READY] = function (event) {
    _gpfIgnore(event);
    this._readable.read(this._chunkSize, this);
};

// gpf.events.EVENT_END_OF_DATA event handler
_GpfStreamPipe.prototype[_GPF_EVENT_END_OF_DATA] = function (event) {
    _gpfIgnore(event);
    _gpfEventsFire.call(this, _GPF_EVENT_READY, {}, this._eventsHandler);
};

// gpf.events.EVENT_DATA event handler
_GpfStreamPipe.prototype[_GPF_EVENT_DATA] = function (event) {
    var buffer = event.get("buffer");
    this._writable.write(buffer, this);
};

// gpf.events.EVENT_ANY event handler
_GpfStreamPipe.prototype[_GPF_EVENT_ANY] = function (event) {
    // Forward to original handler (error or data)
    _gpfEventsFire.call(this, event, {}, this._eventsHandler);
};

/**
 * Creates a pipe that transfer data from the readable stream to writable one
 *
 * @param {Object} configuration
 * - {gpf.interfaces.IReadableStream} readable The stream to read from
 * - {gpf.interfaces.IWritableStream} writable The stream to write to
 * - {Number} [chunkSize=_GPF_STREAM_DEFAULT_READ_SIZE] chunkSize Chunk size
 * @param {gpf.events.Handler} eventsHandler
 *
 * @event ready
 * The readable stream was written in the writable one
 */
function _gpfStreamPipe (configuration, eventsHandler) {
    var scope = new _GpfStreamPipe(configuration, eventsHandler);
    scope.ready();
}

gpf.stream.pipe = _gpfStreamPipe;
<commit_msg>WIP (#202)<commit_after>/**
 * @file Stream piping
 */
/*#ifndef(UMD)*/
"use strict";
//*global _gpfQueryInterface*/ // gpf.interfaces.query
/*exported _gpfStreamPipe*/ // gpf.stream.pipe
/*#endif*/

/**
 * Pipe streams.
 *
 * @param {gpf.interfaces.IReadableStream} source Source stream
 * @param {...gpf.interfaces.IWritableStream} destination Writable streams
 * @return {Promise} Resolved when reading (and subsequent writings) are done
 */
function _gpfStreamPipe (source, destination) {
    return Promise.resolve();
}

/** @gpf:sameas _gpfStreamPipe */
gpf.stream.pipe = _gpfStreamPipe;
<|endoftext|>


<commit_before>/**
 * @file Stream piping
 */
/*#ifndef(UMD)*/
"use strict";
//*global _gpfQueryInterface*/ // gpf.interfaces.query
/*exported _gpfStreamPipe*/ // gpf.stream.pipe
/*#endif*/

/**
 * Pipe streams.
 *
 * @param {gpf.interfaces.IReadableStream} source Source stream
 * @param {...gpf.interfaces.IWritableStream} destination Writable streams
 * @return {Promise} Resolved when reading (and subsequent writings) are done
 */
function _gpfStreamPipe (source, destination) {
    return Promise.resolve();
}

/** @gpf:sameas _gpfStreamPipe */
gpf.stream.pipe = _gpfStreamPipe;
<commit_msg>WIP (#202)<commit_after>/**
 * @file Stream piping
 */
/*#ifndef(UMD)*/
"use strict";
/*global _gpfStreamQueryReadable*/ // Get an IReadableStream or fail if not implemented
/*global _gpfStreamQueryWritable*/ // Get an IWritableStream or fail if not implemented
/*exported _gpfStreamPipe*/ // gpf.stream.pipe
/*#endif*/

/**
 * Pipe streams.
 *
 * @param {gpf.interfaces.IReadableStream} source Source stream
 * @param {...gpf.interfaces.IWritableStream} destination Writable streams
 * @return {Promise} Resolved when reading (and subsequent writings) are done
 */
function _gpfStreamPipe (source, destination) {
    var iReadableStream = _gpfStreamQueryReadable(source),
        iWritableStream = _gpfStreamQueryWritable(destination);
    return iReadableStream .read(iWritableStream);
}

/** @gpf:sameas _gpfStreamPipe */
gpf.stream.pipe = _gpfStreamPipe;
<|endoftext|>


<commit_before>/*jslint browser: true, sloppy: true, todo: true, devel: true, white: true */
/*global $ */

var carousel;

// Object to handle presentation of the carousel
var EmbeddableCarousel = function (element) {
    var self = this;
    this.container = element;
    this.buttonHeight = this.container.find('.buttons').height();
    // Set up the carousel
    this.container.jcarousel({
        'list': '.embeddables',
        'items': '.question'
    });
    // Update the control state when we're done changing
    this.container.on('animateend.jcarousel', function (event, carousel) {
        self.updateControls(carousel);
        return event;
    });
    // Get our controls
    this.controlNext = $('.jcarousel-next');
    this.controlPrev = $('.jcarousel-prev');
    // Assume we start at the first item
    this.turnOnNext();
    // Two cases here: one, we have an image which may take a bit to load and thus define
    // the height of the .interactive-mod which is what we're using to get the height.
    // Two, we have an iframe or video tag which has already been height-adjusted (or the
    // image is already loaded and we don't need to wait.)
    // The first solution was pretty wonky, so I set a minimum height of 300 for those cases.
	this.setCarouselSize();
};

EmbeddableCarousel.prototype.setCarouselSize = function () {
    // Set 'bestHeight' and 'bestWidth' values
    this.calculateSize();
    // Set the carousel to those values and reload it
    this.setHeight(this.bestHeight);
    this.setWidth(this.bestWidth);
	// recalculate scroll values for new dimensions
    this.container.jcarousel('reload');
};

// Set the height of the container
EmbeddableCarousel.prototype.setHeight = function (newHeight) {
    this.container.css('height', newHeight + 'px');
    // Adjust embeddable containers to allow for buttons
    var embeddableHeight = newHeight - this.buttonHeight;
    $('.question').css('max-height', embeddableHeight + 'px');
};

// Set the width of the embeddables
EmbeddableCarousel.prototype.setWidth = function (newWidth) {
    $('.question').css('width', newWidth + 'px');
};

// Update state of carousel controls
EmbeddableCarousel.prototype.updateControls = function (carousel) {
    // "carousel" here is a carousel object from jcarousel
    var list = carousel.items();
    if (list.index(carousel.target()) === 0) {
        // If at start of list, turn off "prev" and on "next"
        this.turnOffPrev();
        this.turnOnNext();
    } else if (list.index(carousel.target()) === (list.length - 1)) {
        // If at end of list, turn off "next" and on "prev"
        this.turnOffNext();
        this.turnOnPrev();
    } else {
        // Otherwise turn on both
        this.turnOnPrev();
        this.turnOnNext();
    }
};

// Activate the "next" control
EmbeddableCarousel.prototype.turnOnNext = function () {
    this.controlNext.jcarouselControl({
        target: '+=1'
    });
    this.controlNext.find('.button').prop('disabled', false);
};

// Deactivate the "next" control
EmbeddableCarousel.prototype.turnOffNext = function () {
    this.controlNext.jcarouselControl('destroy');
    this.controlNext.find('.button').prop('disabled', true);
};

// Activate the "previous" control
EmbeddableCarousel.prototype.turnOnPrev = function () {
    this.controlPrev.jcarouselControl({
        target: '-=1'
    });
    this.controlPrev.find('.button').prop('disabled', false);
};

// Deactivate the "previous" control
EmbeddableCarousel.prototype.turnOffPrev = function () {
    this.controlPrev.jcarouselControl('destroy');
    this.controlPrev.find('.button').prop('disabled', true);
};

EmbeddableCarousel.prototype.tallestQuestion = function() {
    var tallest = 0;
    var current = 0;
    var self = this;
    $('.question').each( function () {
        current = $(this).height() + self.buttonHeight;
        tallest = Math.max(tallest, current);
    });
    return tallest;
};

EmbeddableCarousel.prototype.isFullWidth = function() {
    return $('.content-mod').hasClass('l-full-width');
};

/** Calculates the proper height for the carousel container. */
EmbeddableCarousel.prototype.calculateHeight = function() {
    var available = $(window).height() - $('.activity-nav-mod').height();
    if (this.isFullWidth()) {
        this.bestHeight = Math.min(this.tallestQuestion(), available);
    }
    else {
        this.bestHeight = Math.max($('.interactive-mod').height(), this.tallestQuestion());
    }
};

/** Calculates the proper width for the carousel container. */
EmbeddableCarousel.prototype.calculateWidth = function() {
    if (this.isFullWidth()) {
        this.bestWidth = 960;
        return;
    }
    if ($('.content-mod').hasClass('l-6040')) {
        this.bestWidth = 374;
        return;
    }
    if ($('.content-mod').hasClass('r-4060')) {
        this.bestWidth =  374;
        return;
    }
    this.bestWidth = 278;
};

/** Calculates the proper width & height the carousel container. */
EmbeddableCarousel.prototype.calculateSize = function () {
    this.calculateHeight();
    this.calculateWidth();
};

// unlike document.ready window.load() is called
// after all layout has completed.
// Handy for when you need to get $(foo).height()
$(window).load(function () {
    // Set up the jQuery Carousel if it's active
    if ($('.jcarousel').length > 0) {
        carousel = new EmbeddableCarousel($('.jcarousel'));
    }
});
<commit_msg>Attempt to limit the maximum extent of the question to window-height<commit_after>/*jslint browser: true, sloppy: true, todo: true, devel: true, white: true */
/*global $ */

var carousel;

// Object to handle presentation of the carousel
var EmbeddableCarousel = function (element) {
    var self = this;
    this.container = element;
    this.buttonHeight = this.container.find('.buttons').height();
    // Set up the carousel
    this.container.jcarousel({
        'list': '.embeddables',
        'items': '.question'
    });
    // Update the control state when we're done changing
    this.container.on('animateend.jcarousel', function (event, carousel) {
        self.updateControls(carousel);
        return event;
    });
    // Get our controls
    this.controlNext = $('.jcarousel-next');
    this.controlPrev = $('.jcarousel-prev');
    // Assume we start at the first item
    this.turnOnNext();
    // Two cases here: one, we have an image which may take a bit to load and thus define
    // the height of the .interactive-mod which is what we're using to get the height.
    // Two, we have an iframe or video tag which has already been height-adjusted (or the
    // image is already loaded and we don't need to wait.)
    // The first solution was pretty wonky, so I set a minimum height of 300 for those cases.
	this.setCarouselSize();
};

EmbeddableCarousel.prototype.setCarouselSize = function () {
    // Set 'bestHeight' and 'bestWidth' values
    this.calculateSize();
    // Set the carousel to those values and reload it
    this.setHeight(this.bestHeight);
    this.setWidth(this.bestWidth);
	// recalculate scroll values for new dimensions
    this.container.jcarousel('reload');
};

// Set the height of the container
EmbeddableCarousel.prototype.setHeight = function (newHeight) {
    this.container.css('height', newHeight + 'px');
    // Adjust embeddable containers to allow for buttons
    var embeddableHeight = newHeight - this.buttonHeight -2;
    $('.question').css('max-height', embeddableHeight + 'px');
};

// Set the width of the embeddables
EmbeddableCarousel.prototype.setWidth = function (newWidth) {
    $('.question').css('width', newWidth + 'px');
};

// Update state of carousel controls
EmbeddableCarousel.prototype.updateControls = function (carousel) {
    // "carousel" here is a carousel object from jcarousel
    var list = carousel.items();
    if (list.index(carousel.target()) === 0) {
        // If at start of list, turn off "prev" and on "next"
        this.turnOffPrev();
        this.turnOnNext();
    } else if (list.index(carousel.target()) === (list.length - 1)) {
        // If at end of list, turn off "next" and on "prev"
        this.turnOffNext();
        this.turnOnPrev();
    } else {
        // Otherwise turn on both
        this.turnOnPrev();
        this.turnOnNext();
    }
};

// Activate the "next" control
EmbeddableCarousel.prototype.turnOnNext = function () {
    this.controlNext.jcarouselControl({
        target: '+=1'
    });
    this.controlNext.find('.button').prop('disabled', false);
};

// Deactivate the "next" control
EmbeddableCarousel.prototype.turnOffNext = function () {
    this.controlNext.jcarouselControl('destroy');
    this.controlNext.find('.button').prop('disabled', true);
};

// Activate the "previous" control
EmbeddableCarousel.prototype.turnOnPrev = function () {
    this.controlPrev.jcarouselControl({
        target: '-=1'
    });
    this.controlPrev.find('.button').prop('disabled', false);
};

// Deactivate the "previous" control
EmbeddableCarousel.prototype.turnOffPrev = function () {
    this.controlPrev.jcarouselControl('destroy');
    this.controlPrev.find('.button').prop('disabled', true);
};

/** Return the height of the tallest question element in our list */
EmbeddableCarousel.prototype.tallestQuestion = function() {
    var tallest = 0;
    var current = 0;
    var self = this;
    $('.question').each( function () {
        current = $(this).height() + self.buttonHeight;
        tallest = Math.max(tallest, current);
    });
    return tallest;
};

/** Return true if we are in full-width layout */
EmbeddableCarousel.prototype.isFullWidth = function() {
    return $('.content-mod').hasClass('l-full-width');
};

/** Calculates the proper height for the carousel container. */
EmbeddableCarousel.prototype.calculateHeight = function() {
    var interactiveHeight = $('.interactive-mod').height();
    var available = $(window).height() - $('.activity-nav-mod').height();
    available = available - $('header').height();

    if (this.isFullWidth()) {
        this.bestHeight = Math.min(this.tallestQuestion(), available);
    }
    else {
        this.bestHeight = Math.max(interactiveHeight, this.tallestQuestion());
        // limit to the window?
        this.bestHeight = Math.min(this.bestHeight, available);
    }
};

/** Calculates the proper width for the carousel container. */
EmbeddableCarousel.prototype.calculateWidth = function() {
    if (this.isFullWidth()) {
        this.bestWidth = 960;
        return;
    }
    if ($('.content-mod').hasClass('l-6040')) {
        this.bestWidth = 374;
        return;
    }
    if ($('.content-mod').hasClass('r-4060')) {
        this.bestWidth =  374;
        return;
    }
    this.bestWidth = 278;
};

/** Calculates the proper width & height the carousel container. */
EmbeddableCarousel.prototype.calculateSize = function () {
    this.calculateHeight();
    this.calculateWidth();
};

// unlike document.ready window.load() is called
// after all layout has completed.
// Handy for when you need to get $(foo).height()
$(window).load(function () {
    // Set up the jQuery Carousel if it's active
    if ($('.jcarousel').length > 0) {
        carousel = new EmbeddableCarousel($('.jcarousel'));
    }
});
<|endoftext|>


<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2018 Photon Storm Ltd.
 * @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
 */

var Class = require('../utils/Class');

/**
 * @callback EachMapCallback
 * @generic E - [entry]
 *
 * @param {string} key - [description]
 * @param {E} entry - [description]
 *
 * @return {?boolean} [description]
 */

/**
 * @classdesc
 * The keys of a Map can be arbitrary values.
 * var map = new Map([
 *    [ 1, 'one' ],
 *    [ 2, 'two' ],
 *    [ 3, 'three' ]
 * ]);
 *
 * @class Map
 * @memberOf Phaser.Structs
 * @constructor
 * @since 3.0.0
 *
 * @generic K
 * @generic V
 * @genericUse {V[]} - [elements]
 *
 * @param {Array.<*>} elements - [description]
 */
var Map = new Class({

    initialize:

    function Map (elements)
    {
        /**
         * [description]
         *
         * @genericUse {Object.<string, V>} - [$type]
         *
         * @name Phaser.Structs.Map#entries
         * @type {Object.<string, *>}
         * @default {}
         * @since 3.0.0
         */
        this.entries = {};

        /**
         * [description]
         *
         * @name Phaser.Structs.Map#size
         * @type {number}
         * @default 0
         * @since 3.0.0
         */
        this.size = 0;

        if (Array.isArray(elements))
        {
            for (var i = 0; i < elements.length; i++)
            {
                this.set(elements[i][0], elements[i][1]);
            }
        }
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#set
     * @since 3.0.0
     *
     * @genericUse {K} - [key]
     * @genericUse {V} - [value]
     * @genericUse {Phaser.Structs.Map.<K, V>} - [$return]
     *
     * @param {string} key - [description]
     * @param {*} value - [description]
     *
     * @return {Phaser.Structs.Map} This Map object.
     */
    set: function (key, value)
    {
        if (!this.has(key))
        {
            this.entries[key] = value;
            this.size++;
        }

        return this;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#get
     * @since 3.0.0
     *
     * @genericUse {K} - [key]
     * @genericUse {V} - [$return]
     *
     * @param {string} key - [description]
     *
     * @return {*} [description]
     */
    get: function (key)
    {
        if (this.has(key))
        {
            return this.entries[key];
        }
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#getArray
     * @since 3.0.0
     *
     * @genericUse {V[]} - [$return]
     *
     * @return {Array.<*>} [description]
     */
    getArray: function ()
    {
        var output = [];
        var entries = this.entries;

        for (var key in entries)
        {
            output.push(entries[key]);
        }

        return output;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#has
     * @since 3.0.0
     *
     * @genericUse {K} - [key]
     *
     * @param {string} key - [description]
     *
     * @return {boolean} [description]
     */
    has: function (key)
    {
        return (this.entries.hasOwnProperty(key));
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#delete
     * @since 3.0.0
     *
     * @genericUse {K} - [key]
     * @genericUse {Phaser.Structs.Map.<K, V>} - [$return]
     *
     * @param {string} key - [description]
     *
     * @return {Phaser.Structs.Map} This Map object.
     */
    delete: function (key)
    {
        if (this.has(key))
        {
            delete this.entries[key];
            this.size--;
        }

        return this;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#clear
     * @since 3.0.0
     *
     * @genericUse {Phaser.Structs.Map.<K, V>} - [$return]
     *
     * @return {Phaser.Structs.Map} This Map object.
     */
    clear: function ()
    {
        Object.keys(this.entries).forEach(function (prop)
        {
            delete this.entries[prop];

        }, this);

        this.size = 0;

        return this;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#keys
     * @since 3.0.0
     *
     * @genericUse {K[]} - [$return]
     *
     * @return {string[]} [description]
     */
    keys: function ()
    {
        return Object.keys(this.entries);
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#values
     * @since 3.0.0
     *
     * @genericUse {V[]} - [$return]
     *
     * @return {Array.<*>} [description]
     */
    values: function ()
    {
        var output = [];
        var entries = this.entries;

        for (var key in entries)
        {
            output.push(entries[key]);
        }

        return output;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#dump
     * @since 3.0.0
     */
    dump: function ()
    {
        var entries = this.entries;

        // eslint-disable-next-line no-console
        console.group('Map');

        for (var key in entries)
        {
            console.log(key, entries[key]);
        }

        // eslint-disable-next-line no-console
        console.groupEnd();
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#each
     * @since 3.0.0
     *
     * @genericUse {EachMapCallback.<V>} - [callback]
     * @genericUse {Phaser.Structs.Map.<K, V>} - [$return]
     *
     * @param {EachMapCallback} callback - [description]
     *
     * @return {Phaser.Structs.Map} This Map object.
     */
    each: function (callback)
    {
        var entries = this.entries;

        for (var key in entries)
        {
            if (callback(key, entries[key]) === false)
            {
                break;
            }
        }

        return this;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#contains
     * @since 3.0.0
     *
     * @genericUse {V} - [value]
     *
     * @param {*} value - [description]
     *
     * @return {boolean} [description]
     */
    contains: function (value)
    {
        var entries = this.entries;

        for (var key in entries)
        {
            if (entries[key] === value)
            {
                return true;
            }
        }

        return false;
    },

    /**
     * Merges all new keys from the given Map into this one
     * If it encounters a key that already exists it will be skipped
     * unless override = true.
     *
     * @method Phaser.Structs.Map#merge
     * @since 3.0.0
     *
     * @genericUse {Phaser.Structs.Map.<K, V>} - [map,$return]
     *
     * @param {Phaser.Structs.Map} map - [description]
     * @param {boolean} [override=false] - [description]
     *
     * @return {Phaser.Structs.Map} This Map object.
     */
    merge: function (map, override)
    {
        if (override === undefined) { override = false; }

        var local = this.entries;
        var source = map.entries;

        for (var key in source)
        {
            if (local.hasOwnProperty(key) && override)
            {
                local[key] = source[key];
            }
            else
            {
                this.set(key, source[key]);
            }
        }

        return this;
    }

});

module.exports = Map;
<commit_msg>Remove generic on type<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2018 Photon Storm Ltd.
 * @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
 */

var Class = require('../utils/Class');

/**
 * @callback EachMapCallback
 * @generic E - [entry]
 *
 * @param {string} key - [description]
 * @param {*} entry - [description]
 *
 * @return {?boolean} [description]
 */

/**
 * @classdesc
 * The keys of a Map can be arbitrary values.
 * var map = new Map([
 *    [ 1, 'one' ],
 *    [ 2, 'two' ],
 *    [ 3, 'three' ]
 * ]);
 *
 * @class Map
 * @memberOf Phaser.Structs
 * @constructor
 * @since 3.0.0
 *
 * @generic K
 * @generic V
 * @genericUse {V[]} - [elements]
 *
 * @param {Array.<*>} elements - [description]
 */
var Map = new Class({

    initialize:

    function Map (elements)
    {
        /**
         * [description]
         *
         * @genericUse {Object.<string, V>} - [$type]
         *
         * @name Phaser.Structs.Map#entries
         * @type {Object.<string, *>}
         * @default {}
         * @since 3.0.0
         */
        this.entries = {};

        /**
         * [description]
         *
         * @name Phaser.Structs.Map#size
         * @type {number}
         * @default 0
         * @since 3.0.0
         */
        this.size = 0;

        if (Array.isArray(elements))
        {
            for (var i = 0; i < elements.length; i++)
            {
                this.set(elements[i][0], elements[i][1]);
            }
        }
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#set
     * @since 3.0.0
     *
     * @genericUse {K} - [key]
     * @genericUse {V} - [value]
     * @genericUse {Phaser.Structs.Map.<K, V>} - [$return]
     *
     * @param {string} key - [description]
     * @param {*} value - [description]
     *
     * @return {Phaser.Structs.Map} This Map object.
     */
    set: function (key, value)
    {
        if (!this.has(key))
        {
            this.entries[key] = value;
            this.size++;
        }

        return this;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#get
     * @since 3.0.0
     *
     * @genericUse {K} - [key]
     * @genericUse {V} - [$return]
     *
     * @param {string} key - [description]
     *
     * @return {*} [description]
     */
    get: function (key)
    {
        if (this.has(key))
        {
            return this.entries[key];
        }
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#getArray
     * @since 3.0.0
     *
     * @genericUse {V[]} - [$return]
     *
     * @return {Array.<*>} [description]
     */
    getArray: function ()
    {
        var output = [];
        var entries = this.entries;

        for (var key in entries)
        {
            output.push(entries[key]);
        }

        return output;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#has
     * @since 3.0.0
     *
     * @genericUse {K} - [key]
     *
     * @param {string} key - [description]
     *
     * @return {boolean} [description]
     */
    has: function (key)
    {
        return (this.entries.hasOwnProperty(key));
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#delete
     * @since 3.0.0
     *
     * @genericUse {K} - [key]
     * @genericUse {Phaser.Structs.Map.<K, V>} - [$return]
     *
     * @param {string} key - [description]
     *
     * @return {Phaser.Structs.Map} This Map object.
     */
    delete: function (key)
    {
        if (this.has(key))
        {
            delete this.entries[key];
            this.size--;
        }

        return this;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#clear
     * @since 3.0.0
     *
     * @genericUse {Phaser.Structs.Map.<K, V>} - [$return]
     *
     * @return {Phaser.Structs.Map} This Map object.
     */
    clear: function ()
    {
        Object.keys(this.entries).forEach(function (prop)
        {
            delete this.entries[prop];

        }, this);

        this.size = 0;

        return this;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#keys
     * @since 3.0.0
     *
     * @genericUse {K[]} - [$return]
     *
     * @return {string[]} [description]
     */
    keys: function ()
    {
        return Object.keys(this.entries);
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#values
     * @since 3.0.0
     *
     * @genericUse {V[]} - [$return]
     *
     * @return {Array.<*>} [description]
     */
    values: function ()
    {
        var output = [];
        var entries = this.entries;

        for (var key in entries)
        {
            output.push(entries[key]);
        }

        return output;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#dump
     * @since 3.0.0
     */
    dump: function ()
    {
        var entries = this.entries;

        // eslint-disable-next-line no-console
        console.group('Map');

        for (var key in entries)
        {
            console.log(key, entries[key]);
        }

        // eslint-disable-next-line no-console
        console.groupEnd();
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#each
     * @since 3.0.0
     *
     * @genericUse {EachMapCallback.<V>} - [callback]
     * @genericUse {Phaser.Structs.Map.<K, V>} - [$return]
     *
     * @param {EachMapCallback} callback - [description]
     *
     * @return {Phaser.Structs.Map} This Map object.
     */
    each: function (callback)
    {
        var entries = this.entries;

        for (var key in entries)
        {
            if (callback(key, entries[key]) === false)
            {
                break;
            }
        }

        return this;
    },

    /**
     * [description]
     *
     * @method Phaser.Structs.Map#contains
     * @since 3.0.0
     *
     * @genericUse {V} - [value]
     *
     * @param {*} value - [description]
     *
     * @return {boolean} [description]
     */
    contains: function (value)
    {
        var entries = this.entries;

        for (var key in entries)
        {
            if (entries[key] === value)
            {
                return true;
            }
        }

        return false;
    },

    /**
     * Merges all new keys from the given Map into this one
     * If it encounters a key that already exists it will be skipped
     * unless override = true.
     *
     * @method Phaser.Structs.Map#merge
     * @since 3.0.0
     *
     * @genericUse {Phaser.Structs.Map.<K, V>} - [map,$return]
     *
     * @param {Phaser.Structs.Map} map - [description]
     * @param {boolean} [override=false] - [description]
     *
     * @return {Phaser.Structs.Map} This Map object.
     */
    merge: function (map, override)
    {
        if (override === undefined) { override = false; }

        var local = this.entries;
        var source = map.entries;

        for (var key in source)
        {
            if (local.hasOwnProperty(key) && override)
            {
                local[key] = source[key];
            }
            else
            {
                this.set(key, source[key]);
            }
        }

        return this;
    }

});

module.exports = Map;
<|endoftext|>


<commit_before>/**
 * @license Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.html or http://ckeditor.com/license
 */

CKEDITOR.editorConfig = function( config ) {
	config.extraPlugins 								 = 'oembed,showblocks';

 	config.filebrowserBrowseUrl          = '/admin/documents/new';
  config.filebrowserUploadUrl          = '/admin/documents/new';
  config.filebrowserImageBrowseUrl     = '/admin/images/new';
  config.filebrowserImageUploadUrl     = '/admin/images/new';
  config.filebrowserImageBrowseLinkUrl = '/admin/documents/new';
  config.filebrowserImageUploadLinkUrl = '/admin/documents/new';
  config.filebrowserWindowWidth        = 950;
  config.filebrowserWindowHeight       = 750;

	config.autoGrow_onStartup    				 = true;
	config.forcePasteAsPlainText 				 = true;
	config.allowedContent        				 = true;

	// The toolbar groups arrangement, optimized for two toolbar rows.
	config.toolbarGroups = [
		{ name: 'document',	   groups: [ 'mode', 'document', 'showblocks' ] },
		{ name: 'clipboard',   groups: [ 'clipboard' ] },
		{ name: 'styles' },
		{ name: 'list' },
		{ name: 'indent' },
		{ name: 'basicstyles', groups: [ 'basicstyles' ] },
		{ name: 'links',       groups: [ 'links', 'insert', 'oembed' ] },
	];

	// Remove some buttons, provided by the standard plugins, which we don't
	// need to have in the Standard(s) toolbar.
	config.removeButtons = 'Cut,Copy,Styles,Underline,Subscript,Superscript,Strike,Anchor,HorizontalRule,SpecialChar,Save,Print,Preview,NewPage,Font,Iframe,PageBreak,Smiley';

	// Se the most common block elements.
	config.format_tags = 'h2;h3;h4;h5;h6;p';

	// Make dialogs simpler.
	config.removeDialogTabs = 'image:advanced;link:advanced,document:advanced;link:advanced';
};
<commit_msg>Removed flash from CKEditor<commit_after>/**
 * @license Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.html or http://ckeditor.com/license
 */

CKEDITOR.editorConfig = function( config ) {
	config.extraPlugins 								 = 'oembed,showblocks';

 	config.filebrowserBrowseUrl          = '/admin/documents/new';
  config.filebrowserUploadUrl          = '/admin/documents/new';
  config.filebrowserImageBrowseUrl     = '/admin/images/new';
  config.filebrowserImageUploadUrl     = '/admin/images/new';
  config.filebrowserImageBrowseLinkUrl = '/admin/documents/new';
  config.filebrowserImageUploadLinkUrl = '/admin/documents/new';
  config.filebrowserWindowWidth        = 950;
  config.filebrowserWindowHeight       = 750;

	config.autoGrow_onStartup    				 = true;
	config.forcePasteAsPlainText 				 = true;
	config.allowedContent        				 = true;

	// The toolbar groups arrangement, optimized for two toolbar rows.
	config.toolbarGroups = [
		{ name: 'document',	   groups: [ 'mode', 'document', 'showblocks' ] },
		{ name: 'clipboard',   groups: [ 'clipboard' ] },
		{ name: 'styles' },
		{ name: 'list' },
		{ name: 'indent' },
		{ name: 'basicstyles', groups: [ 'basicstyles' ] },
		{ name: 'links',       groups: [ 'links', 'insert', 'oembed' ] },
	];

	// Remove some buttons, provided by the standard plugins, which we don't
	// need to have in the Standard(s) toolbar.
	config.removeButtons = 'Cut,Copy,Styles,Underline,Subscript,Superscript,Strike,Anchor,HorizontalRule,SpecialChar,Save,Print,Preview,NewPage,Font,Iframe,PageBreak,Smiley,Flash';

	// Se the most common block elements.
	config.format_tags = 'h2;h3;h4;h5;h6;p';

	// Make dialogs simpler.
	config.removeDialogTabs = 'image:advanced;link:advanced,document:advanced;link:advanced';
};
<|endoftext|>


<commit_before>/*jslint browser: true, indent: 2, todo: true, unparam: true */
/*global jQuery,Ornament */

(function (document, window, $) {

  "use strict";

  $(document).on("ornament:tabs", function () {

    var $tabSets = $("[data-tabs]");
    var $tabPanes = $("[data-tab-for]");

    var getWidthOfTabRow = function($tabset) {
      var $links = $tabset.find("li");
      var widthOfTabs = 0;
      $links.each(function(){
        widthOfTabs = widthOfTabs + $(this).outerWidth();
      });
      return widthOfTabs;
    }

    var areTabsGoingToWrap = function($tabset) {
      var tabWidth = getWidthOfTabRow($tabset);
      var tabPanesWidth = $tabset.outerWidth() - 10; // some buffer for good measure

      if( !$tabset.is("[data-tab-width]") ) {
        $tabset.attr("data-tab-width", tabWidth);
      }

      return $tabset.attr("data-tab-width") > tabPanesWidth;
    }

    // Push the current pane to the select menu
    // Used for two-way binding of select and desktop tabs
    var updateSelect = function($tabset) {
      var $fallbackSelect = $tabset.find(".tabs--fallback-select");
      if($fallbackSelect.length) {
        var activePane = $tabPanes.filter(".tabs--pane__active").attr("data-toggle");
        if(activePane) {
          $fallbackSelect.val(activePane);
        }
      }

    }

    // Check if a select menu should be visible or not as a fallback for tabs
    // on smaller screen sizes
    var checkIfTabsNeedSelectMenu = function($tabset) {
      var $tabLinks = $tabset.children("ul");

      // check if there's already a select menu ready to be used
      var $fallbackSelect = $tabset.find(".tabs--fallback-select");

      // scaffold up a new select menu
      if( $fallbackSelect.length < 1 ) {
        $fallbackSelect = $("<select class='tabs--fallback-select' />");
        // build the options
        $tabLinks.find("li").each(function(){
          var $thisLink = $(this).children("[data-toggle-anchor]");
          var tabID = $thisLink.attr("data-toggle-anchor");
          var tabLabel = $thisLink.text();
          var $optionElement = $("<option />");
          $optionElement.attr({
            "data-tab-option": tabID,
            "value": tabID
          }).text(tabLabel);
          $optionElement.appendTo($fallbackSelect);
        });
        $tabset.prepend($fallbackSelect);
        // on change functionality to update tabs
        $fallbackSelect.on("change", function(){
          var tabPaneId = $fallbackSelect.val();
          var $toggleAnchor = $tabLinks.find("[data-toggle-anchor=" + tabPaneId + "]");
          $toggleAnchor.click();
          // loadTab($tabset, pane);
          // pushHashToLocation($tabset, pane);
        });
        // update selected option if required
        updateSelect($tabset);
      }

      // show the select menu if the tabs need to wrap
      if(areTabsGoingToWrap($tabset)) {
        $tabLinks.hide();
        $fallbackSelect.show();
      } else {
        $tabLinks.show();
        $fallbackSelect.hide();
      }
    }

    $tabSets.each(function(i){
      var $tabs = $(this);
      var $tabLinks = $tabs.find("[data-tab]");
      var tabGroup = "tab-group-" + i;

      if($tabs.attr("data-tabs")) {
        tabGroup = $tabs.attr("data-tabs") + tabGroup;
      }

      // Update link attributes to use toggle attributes
      $tabLinks.each(function(){
        var $tabLink = $(this);
        $tabLink.attr({
          "data-toggle-anchor": $tabLink.attr("data-tab"),
          "data-toggle-one-way": "",
          "data-toggle-speed": "0",
          "data-toggle-group": tabGroup,
          "data-toggle-tab": ""
        }).removeAttr("data-tab");

        if($tabs.is("[data-tabs-deeplink]")) {
          $tabLink.attr({
            "data-toggle-deeplink-tab": ""
          });
        }

        // after change
        $tabLink.on("toggle:toggled", function(){
          $(document).trigger("ornament:tab-change");
          updateSelect($tabs);

          if($tabs.is("[data-tabs-deeplink]")) {
            // prevent scrolling by finding the current scroll position
            var scrollmem = $(document).scrollTop();
            // send value to hash
            document.location.hash = $tabLink.attr("data-toggle-anchor");
            // scroll to where we were
            $(document).scrollTop(scrollmem);
          }
        });
      });

      // Set first as active
      $tabLinks.first().addClass("active");

      // Fallback to select menu if necessary
      checkIfTabsNeedSelectMenu($(this));

    });

    // Update pane attributes to use toggle attributes
    $tabPanes.each(function(){
      var $pane = $(this);
      $pane.attr({
        "data-toggle": $pane.attr("data-tab-for"),
        "data-toggle-tab-pane": ""
      }).removeAttr("data-tab-for");
    });

    // Set first as active
    $tabPanes.first().addClass("tabs--pane__active");

    var loadTab = function(paneId){
      var $pane = $tabPanes.filter("[data-toggle-tab-pane][data-toggle=" + paneId + "]");
      if($pane.length) {
        // click the appropriate toggle
        var $anchor = $("[data-toggle-tab][data-toggle-anchor=" + paneId + "]");
        $anchor.trigger("ornament:toggle-on");
      }
    }

    // Deeplinking
    var loadTabFromHash = function(){
      var hash = document.location.hash;
      if(hash) {
        // remove hash symbol from hash
        // (#thing = thing)
        var hash = hash.substr(1,hash.length);
        loadTab(hash);
      }
    }

    $(document).on("ornament:toggles", function(){
      loadTabFromHash();
    });

    // On resize
    $(window).on("resize", function(){
      $tabSets.each(function(){
        var $tabset = $(this);
        // Check if a select menu is needed
        checkIfTabsNeedSelectMenu($tabset);
      });
    });

    // Reopening tabs on popstate (browser back)
    $(window).on("popstate", function(){
      loadTabFromHash();
    });

  });

  $(document).on("ornament:refresh", function () {
    $(document).trigger("ornament:tabs");
  });

}(document, window, jQuery));
// <commit_msg>Deeplinked tab history now works for initial tab (when there's no hash available)<commit_after>/*jslint browser: true, indent: 2, todo: true, unparam: true */
/*global jQuery,Ornament */

(function (document, window, $) {

  "use strict";

  $(document).on("ornament:tabs", function () {

    var $tabSets = $("[data-tabs]");
    var $tabPanes = $("[data-tab-for]");

    var getWidthOfTabRow = function($tabset) {
      var $links = $tabset.find("li");
      var widthOfTabs = 0;
      $links.each(function(){
        widthOfTabs = widthOfTabs + $(this).outerWidth();
      });
      return widthOfTabs;
    }

    var areTabsGoingToWrap = function($tabset) {
      var tabWidth = getWidthOfTabRow($tabset);
      var tabPanesWidth = $tabset.outerWidth() - 10; // some buffer for good measure

      if( !$tabset.is("[data-tab-width]") ) {
        $tabset.attr("data-tab-width", tabWidth);
      }

      return $tabset.attr("data-tab-width") > tabPanesWidth;
    }

    // Push the current pane to the select menu
    // Used for two-way binding of select and desktop tabs
    var updateSelect = function($tabset) {
      var $fallbackSelect = $tabset.find(".tabs--fallback-select");
      if($fallbackSelect.length) {
        var activePane = $tabPanes.filter(".tabs--pane__active").attr("data-toggle");
        if(activePane) {
          $fallbackSelect.val(activePane);
        }
      }

    }

    // Check if a select menu should be visible or not as a fallback for tabs
    // on smaller screen sizes
    var checkIfTabsNeedSelectMenu = function($tabset) {
      var $tabLinks = $tabset.children("ul");

      // check if there's already a select menu ready to be used
      var $fallbackSelect = $tabset.find(".tabs--fallback-select");

      // scaffold up a new select menu
      if( $fallbackSelect.length < 1 ) {
        $fallbackSelect = $("<select class='tabs--fallback-select' />");
        // build the options
        $tabLinks.find("li").each(function(){
          var $thisLink = $(this).children("[data-toggle-anchor]");
          var tabID = $thisLink.attr("data-toggle-anchor");
          var tabLabel = $thisLink.text();
          var $optionElement = $("<option />");
          $optionElement.attr({
            "data-tab-option": tabID,
            "value": tabID
          }).text(tabLabel);
          $optionElement.appendTo($fallbackSelect);
        });
        $tabset.prepend($fallbackSelect);
        // on change functionality to update tabs
        $fallbackSelect.on("change", function(){
          var tabPaneId = $fallbackSelect.val();
          var $toggleAnchor = $tabLinks.find("[data-toggle-anchor=" + tabPaneId + "]");
          $toggleAnchor.click();
          // loadTab($tabset, pane);
          // pushHashToLocation($tabset, pane);
        });
        // update selected option if required
        updateSelect($tabset);
      }

      // show the select menu if the tabs need to wrap
      if(areTabsGoingToWrap($tabset)) {
        $tabLinks.hide();
        $fallbackSelect.show();
      } else {
        $tabLinks.show();
        $fallbackSelect.hide();
      }
    }

    $tabSets.each(function(i){
      var $tabs = $(this);
      var $tabLinks = $tabs.find("[data-tab]");
      var tabGroup = "tab-group-" + i;

      if($tabs.attr("data-tabs")) {
        tabGroup = $tabs.attr("data-tabs") + tabGroup;
      }

      // Update link attributes to use toggle attributes
      $tabLinks.each(function(){
        var $tabLink = $(this);
        $tabLink.attr({
          "data-toggle-anchor": $tabLink.attr("data-tab"),
          "data-toggle-one-way": "",
          "data-toggle-speed": "0",
          "data-toggle-group": tabGroup,
          "data-toggle-tab": ""
        }).removeAttr("data-tab");

        if($tabs.is("[data-tabs-deeplink]")) {
          $tabLink.attr({
            "data-toggle-deeplink-tab": ""
          });
        }

        // after change
        $tabLink.on("toggle:toggled", function(){
          $(document).trigger("ornament:tab-change");
          updateSelect($tabs);

          if($tabs.is("[data-tabs-deeplink]")) {
            // prevent scrolling by finding the current scroll position
            var scrollmem = $(document).scrollTop();
            // send value to hash
            document.location.hash = $tabLink.attr("data-toggle-anchor");
            // scroll to where we were
            $(document).scrollTop(scrollmem);
          }
        });
      });

      // Set first as active
      $tabLinks.first().addClass("active");

      // Fallback to select menu if necessary
      checkIfTabsNeedSelectMenu($(this));

    });

    // Update pane attributes to use toggle attributes
    $tabPanes.each(function(){
      var $pane = $(this);
      $pane.attr({
        "data-toggle": $pane.attr("data-tab-for"),
        "data-toggle-tab-pane": ""
      }).removeAttr("data-tab-for");
    });

    // Set first as active
    $tabPanes.first().addClass("tabs--pane__active");

    var loadTab = function(paneId){
      var $pane = $tabPanes.filter("[data-toggle-tab-pane][data-toggle=" + paneId + "]");
      if($pane.length) {
        // click the appropriate toggle
        var $anchor = $("[data-toggle-tab][data-toggle-anchor=" + paneId + "]");
        $anchor.trigger("ornament:toggle-on");
      }
    }

    // Deeplinking
    var loadTabFromHash = function(){
      var hash = document.location.hash;
      if(hash) {
        // remove hash symbol from hash
        // (#thing = thing)
        var hash = hash.substr(1,hash.length);
        loadTab(hash);
      }
    }

    $(document).on("ornament:toggles", function(){
      loadTabFromHash();
    });

    // On resize
    $(window).on("resize", function(){
      $tabSets.each(function(){
        var $tabset = $(this);
        // Check if a select menu is needed
        checkIfTabsNeedSelectMenu($tabset);
      });
    });

    // Reopening tabs on popstate (browser back)
    $(window).on("popstate", function(){
      var hash = document.location.hash;
      if(hash) {
        loadTabFromHash();
      } else if($tabPanes.length) {
        loadTab($tabPanes.first().attr("data-toggle"));
      }
    });

  });

  $(document).on("ornament:refresh", function () {
    $(document).trigger("ornament:tabs");
  });

}(document, window, jQuery));
// <|endoftext|>


<commit_before>'use strict';

var util = require( '../util' );
var is = require( '../is' );
var math = require( '../math' );

var styfn = {};

// a caching layer for property parsing
styfn.parse = function( name, value, propIsBypass, propIsFlat ){
  var self = this;

  // function values can't be cached in all cases, and there isn't much benefit of caching them anyway
  if( is.fn( value ) ){
    return self.parseImplWarn( name, value, propIsBypass, propIsFlat );
  }

  var flatKey = ( propIsFlat === 'mapping' || propIsFlat === true || propIsFlat === false || propIsFlat == null ) ? 'dontcare' : propIsFlat;
  var argHash = [ name, value, propIsBypass, flatKey ].join( '$' );
  var propCache = self.propCache = self.propCache || {};
  var ret;

  if( !(ret = propCache[ argHash ]) ){
    ret = propCache[ argHash ] = self.parseImplWarn( name, value, propIsBypass, propIsFlat );
  }

  // - bypasses can't be shared b/c the value can be changed by animations or otherwise overridden
  // - mappings can't be shared b/c mappings are per-element
  if( propIsBypass || propIsFlat === 'mapping' ){
    // need a copy since props are mutated later in their lifecycles
    ret = util.copy( ret );

    if( ret ){
      ret.value = util.copy( ret.value ); // because it could be an array, e.g. colour
    }
  }

  return ret;
};

styfn.parseImplWarn = function( name, value, propIsBypass, propIsFlat ){
  var prop = this.parseImpl( name, value, propIsBypass, propIsFlat );

  if( !prop && value != null ){
    util.error('The style property `%s: %s` is invalid', name, value);
  }

  return prop;
};

// parse a property; return null on invalid; return parsed property otherwise
// fields :
// - name : the name of the property
// - value : the parsed, native-typed value of the property
// - strValue : a string value that represents the property value in valid css
// - bypass : true iff the property is a bypass property
styfn.parseImpl = function( name, value, propIsBypass, propIsFlat ){
  var self = this;

  name = util.camel2dash( name ); // make sure the property name is in dash form (e.g. 'property-name' not 'propertyName')

  var property = self.properties[ name ];
  var passedValue = value;
  var types = self.types;

  if( !property ){ return null; } // return null on property of unknown name
  if( value === undefined || value === null ){ return null; } // can't assign null

  // the property may be an alias
  if( property.alias ){
    property = property.pointsTo;
    name = property.name;
  }

  var valueIsString = is.string( value );
  if( valueIsString ){ // trim the value to make parsing easier
    value = value.trim();
  }

  var type = property.type;
  if( !type ){ return null; } // no type, no luck

  // check if bypass is null or empty string (i.e. indication to delete bypass property)
  if( propIsBypass && (value === '' || value === null) ){
    return {
      name: name,
      value: value,
      bypass: true,
      deleteBypass: true
    };
  }

  // check if value is a function used as a mapper
  if( is.fn( value ) ){
    return {
      name: name,
      value: value,
      strValue: 'fn',
      mapped: types.fn,
      bypass: propIsBypass
    };
  }

  // check if value is mapped
  var data, mapData, layoutData, mapLayoutData, scratch, mapScratch;
  if( !valueIsString || propIsFlat ){
    // then don't bother to do the expensive regex checks

  } else if(
    ( data = new RegExp( types.data.regex ).exec( value ) ) ||
    ( layoutData = new RegExp( types.layoutData.regex ).exec( value ) ) ||
    ( scratch = new RegExp( types.scratch.regex ).exec( value ) )
  ){
    if( propIsBypass ){ return false; } // mappers not allowed in bypass

    var mapped;
    if( data ){
      mapped = types.data;
    } else if( layoutData ){
      mapped = types.layoutData;
    } else {
      mapped = types.scratch;
    }

    data = data || layoutData || scratch;

    return {
      name: name,
      value: data,
      strValue: '' + value,
      mapped: mapped,
      field: data[1],
      bypass: propIsBypass
    };

  } else if(
    ( mapData = new RegExp( types.mapData.regex ).exec( value ) ) ||
    ( mapLayoutData = new RegExp( types.mapLayoutData.regex ).exec( value ) ) ||
    ( mapScratch = new RegExp( types.mapScratch.regex ).exec( value ) )
  ){
    if( propIsBypass ){ return false; } // mappers not allowed in bypass
    if( type.multiple ){ return false; } // impossible to map to num

    var mapped;
    if( mapData ){
      mapped = types.mapData;
    } else if( mapLayoutData ){
      mapped = types.mapLayoutData;
    } else {
      mapped = types.mapScratch;
    }

    mapData = mapData || mapLayoutData || mapScratch;

    // we can map only if the type is a colour or a number
    if( !(type.color || type.number) ){ return false; }

    var valueMin = this.parse( name, mapData[4] ); // parse to validate
    if( !valueMin || valueMin.mapped ){ return false; } // can't be invalid or mapped

    var valueMax = this.parse( name, mapData[5] ); // parse to validate
    if( !valueMax || valueMax.mapped ){ return false; } // can't be invalid or mapped

    // check if valueMin and valueMax are the same
    if( valueMin.value === valueMax.value ){
      return false; // can't make much of a mapper without a range

    } else if( type.color ){
      var c1 = valueMin.value;
      var c2 = valueMax.value;

      var same = c1[0] === c2[0] // red
        && c1[1] === c2[1] // green
        && c1[2] === c2[2] // blue
        && ( // optional alpha
          c1[3] === c2[3] // same alpha outright
          || (
            (c1[3] == null || c1[3] === 1) // full opacity for colour 1?
            &&
            (c2[3] == null || c2[3] === 1) // full opacity for colour 2?
          )
        )
      ;

      if( same ){ return false; } // can't make a mapper without a range
    }

    return {
      name: name,
      value: mapData,
      strValue: '' + value,
      mapped: mapped,
      field: mapData[1],
      fieldMin: parseFloat( mapData[2] ), // min & max are numeric
      fieldMax: parseFloat( mapData[3] ),
      valueMin: valueMin.value,
      valueMax: valueMax.value,
      bypass: propIsBypass
    };
  }

  if( type.multiple && propIsFlat !== 'multiple' ){
    var vals;

    if( valueIsString ){
      vals = value.split( /\s+/ );
    } else if( is.array( value ) ){
      vals = value;
    } else {
      vals = [ value ];
    }

    if( type.evenMultiple && vals.length % 2 !== 0 ){ return null; }

    var valArr = vals.map( function( v ){
      var p = self.parse( name, v, propIsBypass, 'multiple' );

      if( p.pfValue != null ){
        return p.pfValue;
      } else {
        return p.value;
      }
    } );

    return {
      name: name,
      value: valArr,
      pfValue: valArr,
      strValue: valArr.join( ' ' ),
      bypass: propIsBypass,
      units: type.number && !type.unitless ? type.implicitUnits || 'px' : undefined
    };
  }

  // several types also allow enums
  var checkEnums = function(){
    for( var i = 0; i < type.enums.length; i++ ){
      var en = type.enums[ i ];

      if( en === value ){
        return {
          name: name,
          value: value,
          strValue: '' + value,
          bypass: propIsBypass
        };
      }
    }

    return null;
  };

  // check the type and return the appropriate object
  if( type.number ){
    var units;
    var implicitUnits = 'px'; // not set => px

    if( type.units ){ // use specified units if set
      units = type.units;
    }

    if( type.implicitUnits ){
      implicitUnits = type.implicitUnits;
    }

    if( !type.unitless ){
      if( valueIsString ){
        var unitsRegex = 'px|em' + (type.allowPercent ? '|\\%' : '');
        if( units ){ unitsRegex = units; } // only allow explicit units if so set
        var match = value.match( '^(' + util.regex.number + ')(' + unitsRegex + ')?' + '$' );

        if( match ){
          value = match[1];
          units = match[2] || implicitUnits;
        }

      } else if( !units || type.implicitUnits ){
        units = implicitUnits; // implicitly px if unspecified
      }
    }

    value = parseFloat( value );

    // if not a number and enums not allowed, then the value is invalid
    if( isNaN( value ) && type.enums === undefined ){
      return null;
    }

    // check if this number type also accepts special keywords in place of numbers
    // (i.e. `left`, `auto`, etc)
    if( isNaN( value ) && type.enums !== undefined ){
      value = passedValue;

      return checkEnums();
    }

    // check if value must be an integer
    if( type.integer && !is.integer( value ) ){
      return null;
    }

    // check value is within range
    if( (type.min !== undefined && value < type.min)
    || (type.max !== undefined && value > type.max)
    ){
      return null;
    }

    var ret = {
      name: name,
      value: value,
      strValue: '' + value + (units ? units : ''),
      units: units,
      bypass: propIsBypass
    };

    // normalise value in pixels
    if( type.unitless || (units !== 'px' && units !== 'em') ){
      ret.pfValue = value;
    } else {
      ret.pfValue = ( units === 'px' || !units ? (value) : (this.getEmSizeInPixels() * value) );
    }

    // normalise value in ms
    if( units === 'ms' || units === 's' ){
      ret.pfValue = units === 'ms' ? value : 1000 * value;
    }

    // normalise value in rad
    if( units === 'deg' || units === 'rad' ){
      ret.pfValue = units === 'rad' ? value : math.deg2rad( value );
    }

    return ret;

  } else if( type.propList ){

    var props = [];
    var propsStr = '' + value;

    if( propsStr === 'none' ){
      // leave empty

    } else { // go over each prop

      var propsSplit = propsStr.split( ',' );
      for( var i = 0; i < propsSplit.length; i++ ){
        var propName = propsSplit[ i ].trim();

        if( self.properties[ propName ] ){
          props.push( propName );
        }
      }

      if( props.length === 0 ){ return null; }
    }

    return {
      name: name,
      value: props,
      strValue: props.length === 0 ? 'none' : props.join( ', ' ),
      bypass: propIsBypass
    };

  } else if( type.color ){
    var tuple = util.color2tuple( value );

    if( !tuple ){ return null; }

    return {
      name: name,
      value: tuple,
      strValue: '' + value,
      bypass: propIsBypass,
      roundValue: true
    };

  } else if( type.regex || type.regexes ){

    // first check enums
    if( type.enums ){
      var enumProp = checkEnums();

      if( enumProp ){ return enumProp; }
    }

    var regexes = type.regexes ? type.regexes : [ type.regex ];

    for( var i = 0; i < regexes.length; i++ ){
      var regex = new RegExp( regexes[ i ] ); // make a regex from the type string
      var m = regex.exec( value );

      if( m ){ // regex matches
        return {
          name: name,
          value: m,
          strValue: '' + value,
          bypass: propIsBypass
        };

      }
    }

    return null; // didn't match any

  } else if( type.string ){
    // just return
    return {
      name: name,
      value: value,
      strValue: '' + value,
      bypass: propIsBypass
    };

  } else if( type.enums ){ // check enums last because it's a combo type in others
    return checkEnums();

  } else {
    return null; // not a type we can handle
  }

};

module.exports = styfn;
<commit_msg>Allow non-string values to be specified as string property values (e.g. `label`) #1620<commit_after>'use strict';

var util = require( '../util' );
var is = require( '../is' );
var math = require( '../math' );

var styfn = {};

// a caching layer for property parsing
styfn.parse = function( name, value, propIsBypass, propIsFlat ){
  var self = this;

  // function values can't be cached in all cases, and there isn't much benefit of caching them anyway
  if( is.fn( value ) ){
    return self.parseImplWarn( name, value, propIsBypass, propIsFlat );
  }

  var flatKey = ( propIsFlat === 'mapping' || propIsFlat === true || propIsFlat === false || propIsFlat == null ) ? 'dontcare' : propIsFlat;
  var argHash = [ name, value, propIsBypass, flatKey ].join( '$' );
  var propCache = self.propCache = self.propCache || {};
  var ret;

  if( !(ret = propCache[ argHash ]) ){
    ret = propCache[ argHash ] = self.parseImplWarn( name, value, propIsBypass, propIsFlat );
  }

  // - bypasses can't be shared b/c the value can be changed by animations or otherwise overridden
  // - mappings can't be shared b/c mappings are per-element
  if( propIsBypass || propIsFlat === 'mapping' ){
    // need a copy since props are mutated later in their lifecycles
    ret = util.copy( ret );

    if( ret ){
      ret.value = util.copy( ret.value ); // because it could be an array, e.g. colour
    }
  }

  return ret;
};

styfn.parseImplWarn = function( name, value, propIsBypass, propIsFlat ){
  var prop = this.parseImpl( name, value, propIsBypass, propIsFlat );

  if( !prop && value != null ){
    util.error('The style property `%s: %s` is invalid', name, value);
  }

  return prop;
};

// parse a property; return null on invalid; return parsed property otherwise
// fields :
// - name : the name of the property
// - value : the parsed, native-typed value of the property
// - strValue : a string value that represents the property value in valid css
// - bypass : true iff the property is a bypass property
styfn.parseImpl = function( name, value, propIsBypass, propIsFlat ){
  var self = this;

  name = util.camel2dash( name ); // make sure the property name is in dash form (e.g. 'property-name' not 'propertyName')

  var property = self.properties[ name ];
  var passedValue = value;
  var types = self.types;

  if( !property ){ return null; } // return null on property of unknown name
  if( value === undefined || value === null ){ return null; } // can't assign null

  // the property may be an alias
  if( property.alias ){
    property = property.pointsTo;
    name = property.name;
  }

  var valueIsString = is.string( value );
  if( valueIsString ){ // trim the value to make parsing easier
    value = value.trim();
  }

  var type = property.type;
  if( !type ){ return null; } // no type, no luck

  // check if bypass is null or empty string (i.e. indication to delete bypass property)
  if( propIsBypass && (value === '' || value === null) ){
    return {
      name: name,
      value: value,
      bypass: true,
      deleteBypass: true
    };
  }

  // check if value is a function used as a mapper
  if( is.fn( value ) ){
    return {
      name: name,
      value: value,
      strValue: 'fn',
      mapped: types.fn,
      bypass: propIsBypass
    };
  }

  // check if value is mapped
  var data, mapData, layoutData, mapLayoutData, scratch, mapScratch;
  if( !valueIsString || propIsFlat ){
    // then don't bother to do the expensive regex checks

  } else if(
    ( data = new RegExp( types.data.regex ).exec( value ) ) ||
    ( layoutData = new RegExp( types.layoutData.regex ).exec( value ) ) ||
    ( scratch = new RegExp( types.scratch.regex ).exec( value ) )
  ){
    if( propIsBypass ){ return false; } // mappers not allowed in bypass

    var mapped;
    if( data ){
      mapped = types.data;
    } else if( layoutData ){
      mapped = types.layoutData;
    } else {
      mapped = types.scratch;
    }

    data = data || layoutData || scratch;

    return {
      name: name,
      value: data,
      strValue: '' + value,
      mapped: mapped,
      field: data[1],
      bypass: propIsBypass
    };

  } else if(
    ( mapData = new RegExp( types.mapData.regex ).exec( value ) ) ||
    ( mapLayoutData = new RegExp( types.mapLayoutData.regex ).exec( value ) ) ||
    ( mapScratch = new RegExp( types.mapScratch.regex ).exec( value ) )
  ){
    if( propIsBypass ){ return false; } // mappers not allowed in bypass
    if( type.multiple ){ return false; } // impossible to map to num

    var mapped;
    if( mapData ){
      mapped = types.mapData;
    } else if( mapLayoutData ){
      mapped = types.mapLayoutData;
    } else {
      mapped = types.mapScratch;
    }

    mapData = mapData || mapLayoutData || mapScratch;

    // we can map only if the type is a colour or a number
    if( !(type.color || type.number) ){ return false; }

    var valueMin = this.parse( name, mapData[4] ); // parse to validate
    if( !valueMin || valueMin.mapped ){ return false; } // can't be invalid or mapped

    var valueMax = this.parse( name, mapData[5] ); // parse to validate
    if( !valueMax || valueMax.mapped ){ return false; } // can't be invalid or mapped

    // check if valueMin and valueMax are the same
    if( valueMin.value === valueMax.value ){
      return false; // can't make much of a mapper without a range

    } else if( type.color ){
      var c1 = valueMin.value;
      var c2 = valueMax.value;

      var same = c1[0] === c2[0] // red
        && c1[1] === c2[1] // green
        && c1[2] === c2[2] // blue
        && ( // optional alpha
          c1[3] === c2[3] // same alpha outright
          || (
            (c1[3] == null || c1[3] === 1) // full opacity for colour 1?
            &&
            (c2[3] == null || c2[3] === 1) // full opacity for colour 2?
          )
        )
      ;

      if( same ){ return false; } // can't make a mapper without a range
    }

    return {
      name: name,
      value: mapData,
      strValue: '' + value,
      mapped: mapped,
      field: mapData[1],
      fieldMin: parseFloat( mapData[2] ), // min & max are numeric
      fieldMax: parseFloat( mapData[3] ),
      valueMin: valueMin.value,
      valueMax: valueMax.value,
      bypass: propIsBypass
    };
  }

  if( type.multiple && propIsFlat !== 'multiple' ){
    var vals;

    if( valueIsString ){
      vals = value.split( /\s+/ );
    } else if( is.array( value ) ){
      vals = value;
    } else {
      vals = [ value ];
    }

    if( type.evenMultiple && vals.length % 2 !== 0 ){ return null; }

    var valArr = vals.map( function( v ){
      var p = self.parse( name, v, propIsBypass, 'multiple' );

      if( p.pfValue != null ){
        return p.pfValue;
      } else {
        return p.value;
      }
    } );

    return {
      name: name,
      value: valArr,
      pfValue: valArr,
      strValue: valArr.join( ' ' ),
      bypass: propIsBypass,
      units: type.number && !type.unitless ? type.implicitUnits || 'px' : undefined
    };
  }

  // several types also allow enums
  var checkEnums = function(){
    for( var i = 0; i < type.enums.length; i++ ){
      var en = type.enums[ i ];

      if( en === value ){
        return {
          name: name,
          value: value,
          strValue: '' + value,
          bypass: propIsBypass
        };
      }
    }

    return null;
  };

  // check the type and return the appropriate object
  if( type.number ){
    var units;
    var implicitUnits = 'px'; // not set => px

    if( type.units ){ // use specified units if set
      units = type.units;
    }

    if( type.implicitUnits ){
      implicitUnits = type.implicitUnits;
    }

    if( !type.unitless ){
      if( valueIsString ){
        var unitsRegex = 'px|em' + (type.allowPercent ? '|\\%' : '');
        if( units ){ unitsRegex = units; } // only allow explicit units if so set
        var match = value.match( '^(' + util.regex.number + ')(' + unitsRegex + ')?' + '$' );

        if( match ){
          value = match[1];
          units = match[2] || implicitUnits;
        }

      } else if( !units || type.implicitUnits ){
        units = implicitUnits; // implicitly px if unspecified
      }
    }

    value = parseFloat( value );

    // if not a number and enums not allowed, then the value is invalid
    if( isNaN( value ) && type.enums === undefined ){
      return null;
    }

    // check if this number type also accepts special keywords in place of numbers
    // (i.e. `left`, `auto`, etc)
    if( isNaN( value ) && type.enums !== undefined ){
      value = passedValue;

      return checkEnums();
    }

    // check if value must be an integer
    if( type.integer && !is.integer( value ) ){
      return null;
    }

    // check value is within range
    if( (type.min !== undefined && value < type.min)
    || (type.max !== undefined && value > type.max)
    ){
      return null;
    }

    var ret = {
      name: name,
      value: value,
      strValue: '' + value + (units ? units : ''),
      units: units,
      bypass: propIsBypass
    };

    // normalise value in pixels
    if( type.unitless || (units !== 'px' && units !== 'em') ){
      ret.pfValue = value;
    } else {
      ret.pfValue = ( units === 'px' || !units ? (value) : (this.getEmSizeInPixels() * value) );
    }

    // normalise value in ms
    if( units === 'ms' || units === 's' ){
      ret.pfValue = units === 'ms' ? value : 1000 * value;
    }

    // normalise value in rad
    if( units === 'deg' || units === 'rad' ){
      ret.pfValue = units === 'rad' ? value : math.deg2rad( value );
    }

    return ret;

  } else if( type.propList ){

    var props = [];
    var propsStr = '' + value;

    if( propsStr === 'none' ){
      // leave empty

    } else { // go over each prop

      var propsSplit = propsStr.split( ',' );
      for( var i = 0; i < propsSplit.length; i++ ){
        var propName = propsSplit[ i ].trim();

        if( self.properties[ propName ] ){
          props.push( propName );
        }
      }

      if( props.length === 0 ){ return null; }
    }

    return {
      name: name,
      value: props,
      strValue: props.length === 0 ? 'none' : props.join( ', ' ),
      bypass: propIsBypass
    };

  } else if( type.color ){
    var tuple = util.color2tuple( value );

    if( !tuple ){ return null; }

    return {
      name: name,
      value: tuple,
      strValue: '' + value,
      bypass: propIsBypass,
      roundValue: true
    };

  } else if( type.regex || type.regexes ){

    // first check enums
    if( type.enums ){
      var enumProp = checkEnums();

      if( enumProp ){ return enumProp; }
    }

    var regexes = type.regexes ? type.regexes : [ type.regex ];

    for( var i = 0; i < regexes.length; i++ ){
      var regex = new RegExp( regexes[ i ] ); // make a regex from the type string
      var m = regex.exec( value );

      if( m ){ // regex matches
        return {
          name: name,
          value: m,
          strValue: '' + value,
          bypass: propIsBypass
        };

      }
    }

    return null; // didn't match any

  } else if( type.string ){
    // just return
    return {
      name: name,
      value: '' + value,
      strValue: '' + value,
      bypass: propIsBypass
    };

  } else if( type.enums ){ // check enums last because it's a combo type in others
    return checkEnums();

  } else {
    return null; // not a type we can handle
  }

};

module.exports = styfn;
<|endoftext|>


<commit_before>// ------------------------------------ UI tools -----------------------------------------
var Ui = {
  // Select record id attribute form grid - shouldn't this be an extension of Grid ? Why in Ui? Ui == User interface?
  selectIds: function(grid){
    var selectedIndexes = grid.getSelectedRows();
    var ids, item;
    if (grid == null) return false;
    if (selectedIndexes.length > 0) {
      ids = $.map(selectedIndexes,function(n, i) {
        item = grid.loader.data[n];
        return item['id'];
        }).join();
        return ids;
    } else {
        return false;
    }
  },

    // return true if the dialog of grid with "name" is open, unless return false
  isOpen: function() {
    return ($(".ui-dialog:visible").size() > 0);
  },

  // check if the grid is being edited
  isEditing: function() {
    var editing = false;
    $.each(gridManager.grids, function(){
      if(this.isEditing()) editing = true;
    });
    return editing;
  },

  //check if filter panel is open
  filterPanelOpen: function() {
    return ($('.slick-headerrow-columns:visible').size() > 0 && $( document.activeElement ).parent().attr('class') === 'slick-headerrow-columns');
  },

  // Select grid names
  selectGridNames: function() {
    var gridContainers = $(".grid_container"), gridName;
    return $.map( gridContainers, function(container){
      gridName = $.trim($(container).attr("id").split("grid_")[1]);
      if (gridName) {
        return gridName;
      }
    });
  },

  // Reset form
  resetForm: function(name) {
    $(':input','#new_' + name).not(':button, :submit, :reset, :hidden').val('').removeAttr('checked').removeAttr('selected');
    // For chosen
    $('ul.chzn-choices li.search-choice').remove();
  },

  // Create and open dialog
  openDialog: function(name,options) {
    var width, height;
    if (options) {
      width = options.form_dialog_width || 600;
      height = options.form_dialog_height || 300;
    } else {
      width = 600;
      height = 300;
    }

    $( '#' + name + '-form:first' ).dialog({
      height: height,
      width: width,
      show: "blind",
      modal: true,
      create: function(event, ui) {
        Ui.setupForm(name, $(this), false);
			},
      close: function(event, ui) {
        Ui.closeDialog(name);
      }
    });
  },

  setupForm: function(name, monitor) {
    // Fetch options of select box by ajax
    var  remotePath = $('#remote_paths').val().split(',');
    window._jsonData = window._jsonData || {};
    $.each(remotePath, function(i,path){
      var first_input, target = $("select[data-remote-path='" + path + "']"),
      textAttr = target.attr('data-text-attr');

      if ($.isEmptyObject(window._jsonData[path])) {
        $.getJSON(path, function(itemdata){
          window._jsonData[path] = itemdata;
          $.each(itemdata, function(index, value) {
            target.append("<option value='" + value.id + "'>" + value[textAttr] + "</option>");
          });
          Ui.setupChosen(path, monitor);
        });
      } else {
        $.each(window._jsonData[path], function(index, value) {
          target.append("<option value='" + value.id + "'>" + value[textAttr] + "</option>");
        });
        Ui.setupChosen(path, monitor);
      }
    });

    first_input = $( '#' + name + '-form input:text' ).first();
    if ($.isEmptyObject(first_input.attr('data-date'))) {
      first_input.focus();
    }
  },

  setupChosen: function(path, monitor) {
    setTimeout(function(){
      if (monitor) {
        $("select[data-remote-path='" + path + "']").chosen().change(function(){
          $('input:checkbox[date-target="' + $(this).attr('name') + '"]').attr('checked', 'checked');
        });
      } else {
        $("select[data-remote-path='" + path + "']").chosen();
      }
    }, 100);
  },

  // Close dialog
  closeDialog: function(name) {
    var $form = $( '#' + name + '-form' );

    $form.find("input:text").val("");
    $form.find(".field_error").text("");
    setTimeout(function(){
      Ui.highlightCreatedRows(name);
      gridManager.createdIds = [];
    }, 300);
    window._focused = {};
    $form.dialog("destroy");
    if ($('#screen_content #' + name + '-form').size() == 0) {
      $('body > #' + name + '-form:first').prependTo($('#screen_content'));
      $('body > #' + name + '-form').remove();
    }
  },

  // Handle delete confirm with dialog
  deleteGrids: function(ids) {
    $( "#confirm_dialog" ).dialog({
      modal: true,
      buttons: {
        Yes: function() {
          Requests.deleteByAjax(Ui.findCurrentGrid(), ids);
          $( this ).dialog( "destroy" );
        },
        Cancel: function() {
          $( this ).dialog( "destroy" );
        }
      },
      close: function() {
        $(this).dialog("destroy");
      }
    });
  },

  // Highlight the created rows after close the dialog
  highlightCreatedRows: function(name) {
    var grid = gridManager.getGrid(name),
    createdRows = [];
    $.each(gridManager.createdIds, function(){
      if (grid.getRowByRecordId(this) && grid.getRowByRecordId(this).row) {
        createdRows.push(grid.getRowByRecordId(this).row);
      }
    });
    $.each(createdRows, function(){
      $(this).effect( 'highlight', {}, 5000 );
    });
  },

  // Flash the notification
  flashNotice: function(ids, action) {
    var recordSize = $.isArray(ids) ? ids.length : ids.split(',').length,
    recordUnit = recordSize > 1 ? 'records' : 'record',
    actionDesc = action === 'delete' ? 'has been deleted!' : 'has been created!';

    if (recordSize > 0) {
      $('.notice_flash').remove();
      $('#indicators').before('
' + recordSize + ' ' + recordUnit + ' ' + actionDesc + '
');
      $('.notice_flash').fadeOut(7000);
    }
  },

  // Find the selected grid
  findCurrentGrid: function() {
    var currentGrid = null;
    currentGridContainer = $('.grid_container:visible');
    if (currentGridContainer.size() == 0) {
      return null;
    }
    gridName = currentGridContainer.attr('id').split('grid_')[1];

    if (gridManager.grids.length == 1) {
      currentGrid = gridManager.grids[0]
    } else {
      if (currentGridContainer.size() == 1) {
        currentGrid = gridManager.getGrid(gridName);
      } else {
        $.each(gridManager.grids, function(){
          if(this.getSelectedRows().length > 0) currentGrid = this;
        });
      }
    }
    return currentGrid;
  },

  addAble: function(grid) {
    return grid.actions.indexOf('add') != -1;
  },

  deleteAble: function(grid) {
    return grid.actions.indexOf('delete') != -1;
	},

	formatData: function(grid, arrayData) {
	  var data = {}, columns;
    columns = grid.loader.getColumns();
	  $.each(columns, function(index, column){
	    data[column['id']] = arrayData[index];
	  })
	  return data;
	}

};

// ------------------------- keypress action --------------------------------------
(function($) {
  $(document).keypress(function(e){
    var isEditing = Ui.isEditing(),
    isOpen = Ui.isOpen(),
    filterPanelOpen = Ui.filterPanelOpen(),
    grid = Ui.findCurrentGrid();
    if (grid) {
      var ids = Ui.selectIds(grid),
      gridSize = gridManager.grids.length;

      if (isOpen || isEditing || filterPanelOpen) {
        return true;
      } else {
        if (Ui.deleteAble(grid) && (e.which == 100 || e.which == 68)) {  // keypress 'D' for delete
          if (ids) {
            Ui.deleteGrids(ids);
            return false;
          }
          return false;
        } else if (Ui.addAble(grid) && (e.which == 99 || e.which == 67)) {  // keypress 'C' for show dialog
          if (gridSize > 0 && grid) {
            Ui.openDialog(grid.name, grid.extend_options);
            return false;
          }
          return false;
        } else {
          return true;
        }
      }
    }
  });
})(jQuery);
<commit_msg>MISC - Dialog form bugfix<commit_after>// ------------------------------------ UI tools -----------------------------------------
var Ui = {
  // Select record id attribute form grid - shouldn't this be an extension of Grid ? Why in Ui? Ui == User interface?
  selectIds: function(grid){
    var selectedIndexes = grid.getSelectedRows();
    var ids, item;
    if (grid == null) return false;
    if (selectedIndexes.length > 0) {
      ids = $.map(selectedIndexes,function(n, i) {
        item = grid.loader.data[n];
        return item['id'];
        }).join();
        return ids;
    } else {
        return false;
    }
  },

    // return true if the dialog of grid with "name" is open, unless return false
  isOpen: function() {
    return ($(".ui-dialog:visible").size() > 0);
  },

  // check if the grid is being edited
  isEditing: function() {
    var editing = false;
    $.each(gridManager.grids, function(){
      if(this.isEditing()) editing = true;
    });
    return editing;
  },

  //check if filter panel is open
  filterPanelOpen: function() {
    return ($('.slick-headerrow-columns:visible').size() > 0 && $( document.activeElement ).parent().attr('class') === 'slick-headerrow-columns');
  },

  // Select grid names
  selectGridNames: function() {
    var gridContainers = $(".grid_container"), gridName;
    return $.map( gridContainers, function(container){
      gridName = $.trim($(container).attr("id").split("grid_")[1]);
      if (gridName) {
        return gridName;
      }
    });
  },

  // Reset form
  resetForm: function(name) {
    $(':input','#new_' + name).not(':button, :submit, :reset, :hidden').val('').removeAttr('checked').removeAttr('selected');
    // For chosen
    $('ul.chzn-choices li.search-choice').remove();
  },

  // Create and open dialog
  openDialog: function(name,options) {
    var width, height;
    if (options) {
      width = options.form_dialog_width || 600;
      height = options.form_dialog_height || 300;
    } else {
      width = 600;
      height = 300;
    }

    $( '#' + name + '-form:first' ).dialog({
      height: height,
      width: width,
      show: "blind",
      modal: true,
      create: function(event, ui) {
        Ui.setupForm(name, $(this), false);
			},
      close: function(event, ui) {
        Ui.closeDialog(name);
      }
    });
  },

  setupForm: function(name, monitor) {
    // Fetch options of select box by ajax
    var  remotePath = $('#' + name + '-form #remote_paths').val().split(',');
    window._jsonData = window._jsonData || {};
    $.each(remotePath, function(i,path){
      var first_input, target = $("select[data-remote-path='" + path + "']"),
      textAttr = target.attr('data-text-attr');

      if ($.isEmptyObject(window._jsonData[path])) {
        $.getJSON(path, function(itemdata){
          window._jsonData[path] = itemdata;
          $.each(itemdata, function(index, value) {
            target.append("<option value='" + value.id + "'>" + value[textAttr] + "</option>");
          });
          Ui.setupChosen(path, monitor);
        });
      } else {
        $.each(window._jsonData[path], function(index, value) {
          target.append("<option value='" + value.id + "'>" + value[textAttr] + "</option>");
        });
        Ui.setupChosen(path, monitor);
      }
    });

    first_input = $( '#' + name + '-form input:text' ).first();
    if ($.isEmptyObject(first_input.attr('data-date'))) {
      first_input.focus();
    }
  },

  setupChosen: function(path, monitor) {
    setTimeout(function(){
      if (monitor) {
        $("select[data-remote-path='" + path + "']").chosen().change(function(){
          $('input:checkbox[date-target="' + $(this).attr('name') + '"]').attr('checked', 'checked');
        });
      } else {
        $("select[data-remote-path='" + path + "']").chosen();
      }
    }, 100);
  },

  // Close dialog
  closeDialog: function(name) {
    var $form = $( '#' + name + '-form' );

    $form.find("input:text").val("");
    $form.find(".field_error").text("");
    setTimeout(function(){
      Ui.highlightCreatedRows(name);
      gridManager.createdIds = [];
    }, 300);
    window._focused = {};
    $form.dialog("destroy");
    if ($('#screen_content #' + name + '-form').size() == 0) {
      $('body > #' + name + '-form:first').prependTo($('#screen_content'));
      $('body > #' + name + '-form').remove();
    }
  },

  // Handle delete confirm with dialog
  deleteGrids: function(ids) {
    $( "#confirm_dialog" ).dialog({
      modal: true,
      buttons: {
        Yes: function() {
          Requests.deleteByAjax(Ui.findCurrentGrid(), ids);
          $( this ).dialog( "destroy" );
        },
        Cancel: function() {
          $( this ).dialog( "destroy" );
        }
      },
      close: function() {
        $(this).dialog("destroy");
      }
    });
  },

  // Highlight the created rows after close the dialog
  highlightCreatedRows: function(name) {
    var grid = gridManager.getGrid(name),
    createdRows = [];
    $.each(gridManager.createdIds, function(){
      if (grid.getRowByRecordId(this) && grid.getRowByRecordId(this).row) {
        createdRows.push(grid.getRowByRecordId(this).row);
      }
    });
    $.each(createdRows, function(){
      $(this).effect( 'highlight', {}, 5000 );
    });
  },

  // Flash the notification
  flashNotice: function(ids, action) {
    var recordSize = $.isArray(ids) ? ids.length : ids.split(',').length,
    recordUnit = recordSize > 1 ? 'records' : 'record',
    actionDesc = action === 'delete' ? 'has been deleted!' : 'has been created!';

    if (recordSize > 0) {
      $('.notice_flash').remove();
      $('#indicators').before('
' + recordSize + ' ' + recordUnit + ' ' + actionDesc + '
');
      $('.notice_flash').fadeOut(7000);
    }
  },

  // Find the selected grid
  findCurrentGrid: function() {
    var currentGrid = null;
    currentGridContainer = $('.grid_container:visible');
    if (currentGridContainer.size() == 0) {
      return null;
    }
    gridName = currentGridContainer.attr('id').split('grid_')[1];

    if (gridManager.grids.length == 1) {
      currentGrid = gridManager.grids[0]
    } else {
      if (currentGridContainer.size() == 1) {
        currentGrid = gridManager.getGrid(gridName);
      } else {
        $.each(gridManager.grids, function(){
          if(this.getSelectedRows().length > 0) currentGrid = this;
        });
      }
    }
    return currentGrid;
  },

  addAble: function(grid) {
    return grid.actions.indexOf('add') != -1;
  },

  deleteAble: function(grid) {
    return grid.actions.indexOf('delete') != -1;
	},

	formatData: function(grid, arrayData) {
	  var data = {}, columns;
    columns = grid.loader.getColumns();
	  $.each(columns, function(index, column){
	    data[column['id']] = arrayData[index];
	  })
	  return data;
	}

};

// ------------------------- keypress action --------------------------------------
(function($) {
  $(document).keypress(function(e){
    var isEditing = Ui.isEditing(),
    isOpen = Ui.isOpen(),
    filterPanelOpen = Ui.filterPanelOpen(),
    grid = Ui.findCurrentGrid();
    if (grid) {
      var ids = Ui.selectIds(grid),
      gridSize = gridManager.grids.length;

      if (isOpen || isEditing || filterPanelOpen) {
        return true;
      } else {
        if (Ui.deleteAble(grid) && (e.which == 100 || e.which == 68)) {  // keypress 'D' for delete
          if (ids) {
            Ui.deleteGrids(ids);
            return false;
          }
          return false;
        } else if (Ui.addAble(grid) && (e.which == 99 || e.which == 67)) {  // keypress 'C' for show dialog
          if (gridSize > 0 && grid) {
            Ui.openDialog(grid.name, grid.extend_options);
            return false;
          }
          return false;
        } else {
          return true;
        }
      }
    }
  });
})(jQuery);
<|endoftext|>