arrays.js 4.6 KB
Newer Older
Ketan's avatar
Ketan committed
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
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

define([
    'underscore',
    './strings'
], function (_, utils) {
    'use strict';

    /**
     * Defines index of an item in a specified container.
     *
     * @param {*} item - Item whose index should be defined.
     * @param {Array} container - Container upon which to perform search.
     * @returns {Number}
     */
    function getIndex(item, container) {
        var index = container.indexOf(item);

        if (~index) {
            return index;
        }

        return _.findIndex(container, function (value) {
            return value && value.name === item;
        });
    }

    return {
        /**
         * Facade method to remove/add value from/to array
         * without creating a new instance.
         *
         * @param {Array} arr - Array to be modified.
         * @param {*} value - Value to add/remove.
         * @param {Boolean} add - Flag that specfies operation.
         * @returns {Utils} Chainable.
         */
        toggle: function (arr, value, add) {
            return add ?
                this.add(arr, value) :
                this.remove(arr, value);
        },

        /**
         * Removes the incoming value from array in case
         * without creating a new instance of it.
         *
         * @param {Array} arr - Array to be modified.
         * @param {*} value - Value to be removed.
         * @returns {Utils} Chainable.
         */
        remove: function (arr, value) {
            var index = arr.indexOf(value);

            if (~index) {
                arr.splice(index, 1);
            }

            return this;
        },

        /**
         * Adds the incoming value to array if
         * it's not alredy present in there.
         *
         * @param {Array} arr - Array to be modifed.
         * @param {...*} arguments - Values to be added.
         * @returns {Utils} Chainable.
         */
        add: function (arr) {
            var values = _.toArray(arguments).slice(1);

            values.forEach(function (value) {
                if (!~arr.indexOf(value)) {
                    arr.push(value);
                }
            });

            return this;
        },

        /**
         * Inserts specified item into container at a specified position.
         *
         * @param {*} item - Item to be inserted into container.
         * @param {Array} container - Container of items.
         * @param {*} [position=-1] - Position at which item should be inserted.
         *      Position can represent:
         *          - specific index in container
         *          - item which might already be present in container
         *          - structure with one of these properties: after, before
         * @returns {Boolean|*}
         *      - true if element has changed its' position
         *      - false if nothing has changed
         *      - inserted value if it wasn't present in container
         */
        insert: function (item, container, position) {
            var currentIndex = getIndex(item, container),
                newIndex,
                target;

            if (typeof position === 'undefined') {
                position = -1;
            } else if (typeof position === 'string') {
                position = isNaN(+position) ? position : +position;
            }

            newIndex = position;

            if (~currentIndex) {
                target = container.splice(currentIndex, 1)[0];

                if (typeof item === 'string') {
                    item = target;
                }
            }

            if (typeof position !== 'number') {
                target = position.after || position.before || position;

                newIndex = getIndex(target, container);

                if (~newIndex && (position.after || newIndex >= currentIndex)) {
                    newIndex++;
                }
            }

            if (newIndex < 0) {
                newIndex += container.length + 1;
            }

            container[newIndex] ?
                container.splice(newIndex, 0, item) :
                container[newIndex] = item;

            return !~currentIndex ? item : currentIndex !== newIndex;
        },

        /**
         * @param {Array} elems
         * @param {Number} offset
         * @return {Number|*}
         */
        formatOffset: function (elems, offset) {
            if (utils.isEmpty(offset)) {
                offset = -1;
            }

            offset = +offset;

            if (offset < 0) {
                offset += elems.length + 1;
            }

            return offset;
        }
    };
});