All files / web/bundles/pimui/js/product/field field.js

84.72% Statements 61/72
71.43% Branches 20/28
83.87% Functions 26/31
84.72% Lines 61/72

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364                  347x                     347x       347x         3593x                                           3593x 3593x 3593x 3593x   3593x                 5980x 5980x 5980x 5980x 5980x   5980x     5971x 5971x   5971x 5971x 5971x     5980x             5971x 2446x       2446x   2446x 2446x 166x   2280x                                                         73x   73x       73x 73x 73x 73x 73x   73x                   6046x   6046x                           6046x                               6070x       6070x                 6070x                     2541x 2495x   2541x                   11x                             6073x                               57x                 6884x                                   11x                 60x                 2424x                 6046x 5165x   881x                                       7181x                           1050x   1050x       1050x 1050x                 6119x          
'use strict';
/**
 * Field abstract class
 *
 * @author    Julien Sanchez <julien@akeneo.com>
 * @author    Filips Alpe <filips@akeneo.com>
 * @copyright 2015 Akeneo SAS (http://www.akeneo.com)
 * @license   http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 */
define(
    [
        'jquery',
        'backbone',
        'underscore',
        'pim/template/product/field/field',
        'pim/attribute-manager',
        'pim/i18n',
        'oro/mediator'
    ],
    function ($, Backbone, _, fieldTemplate, AttributeManager, i18n, mediator) {
        var FieldModel = Backbone.Model.extend({
            values: []
        });
 
        return Backbone.View.extend({
            tagName: 'div',
            className: 'AknComparableFields field-container',
            options: {},
            attributes: function () {
                return {
                    'data-attribute': this.options ? this.options.code : null
                };
            },
            attribute: null,
            context: {},
            model: FieldModel,
            template: _.template(fieldTemplate),
            elements: {},
            editable: true,
            ready: true,
            valid: true,
            locked: false,
 
            /**
             * Initialize this field
             *
             * @param {Object} attribute
             *
             * @returns {Object}
             */
            initialize: function (attribute) {
                this.attribute = attribute;
                this.model = new FieldModel({values: []});
                this.elements = {};
                this.context = {};
 
                return this;
            },
 
            /**
             * Render this field
             *
             * @returns {Object}
             */
            render: function () {
                this.setEditable(!this.locked);
                this.setValid(true);
                this.elements = {};
                var promises = [];
                mediator.trigger('pim_enrich:form:field:extension:add', {'field': this, 'promises': promises});
 
                $.when.apply($, promises)
                    .then(this.getTemplateContext.bind(this))
                    .then(function (templateContext) {
                        this.$el.html(this.template(templateContext));
                        this.$('.original-field .field-input').append(this.renderInput(templateContext));
 
                        this.renderElements();
                        this.postRender();
                        this.delegateEvents();
                    }.bind(this));
 
                return this;
            },
 
            /**
             * Render elements of this field in different available positions
             */
            renderElements: function () {
                _.each(this.elements, function (elements, position) {
                    var $container = 'field-input' === position ?
                        this.$('.original-field .field-input') :
                        this.$('.' + position + '-elements-container');
 
                    $container.empty();
 
                    _.each(elements, function (element) {
                        if (typeof element.render === 'function') {
                            $container.append(element.render().$el);
                        } else {
                            $container.append(element);
                        }
                    }.bind(this));
 
                }.bind(this));
            },
 
            /**
             * Render the input inside the field area
             *
             * @throws {Error} if this method is not implemented
             */
            renderInput: function () {
                throw new Error('You should implement your field template');
            },
 
            /**
             * Is called after rendering the input
             */
            postRender: function () {},
 
            /**
             * Render this input in copy mode
             *
             * @param {Object} value
             *
             * @returns {Promise}
             */
            renderCopyInput: function (value) {
                return this.getTemplateContext()
                    .then(function (context) {
                        Iif (undefined === value) {
                            return null;
                        }
 
                        var copyContext = $.extend(true, {}, context);
                        copyContext.value = value;
                        copyContext.context.locale = value.locale;
                        copyContext.context.scope = value.scope;
                        copyContext.editMode = 'view';
 
                        return this.renderInput(copyContext);
                    }.bind(this));
            },
 
            /**
             * Get the template context
             *
             * @returns {Promise}
             */
            getTemplateContext: function () {
                var deferred = $.Deferred();
 
                deferred.resolve({
                    type: this.attribute.field_type,
                    label: this.getLabel(),
                    value: this.getCurrentValue(),
                    fieldId: 'field-' + Math.random().toString(10).substring(2),
                    context: this.context,
                    attribute: this.attribute,
                    info: this.elements,
                    editMode: this.getEditMode(),
                    i18n: i18n,
                    locale: this.attribute.localizable ? this.context.locale : null,
                    scope: this.attribute.scopable ? this.context.scope : null
                });
 
                return deferred.promise();
            },
 
            /**
             * Update the model linked to this field
             */
            updateModel: function () {
                this.valid = true;
            },
 
            /**
             * Set values to the model linked to this field
             *
             * @param {Array} values
             */
            setValues: function (values) {
                Iif (_.isUndefined(values) || values.length === 0) {
                    console.error('Value array is empty');
                }
 
                this.model.set('values', values);
            },
 
            /**
             * Set the context of this field
             *
             * @param {Object} context
             */
            setContext: function (context) {
                this.context = context;
            },
 
            /**
             * Add an element to this field block
             *
             * @param {string} position 'footer', 'label' or 'comparison'
             * @param {string} code
             * @param {Object} element
             */
            addElement: function (position, code, element) {
                if (!this.elements[position]) {
                    this.elements[position] = {};
                }
                this.elements[position][code] = element;
            },
 
            /**
             * Remove an element of this field block, with the given position & code
             *
             * @param {string} position
             * @param {string} code
             */
            removeElement: function (position, code) {
                Iif (this.elements[position] && this.elements[position][code]) {
                    delete this.elements[position][code];
 
                    if (_.isEmpty(this.elements[position])) {
                        delete this.elements[position];
                    }
                }
            },
 
            /**
             * Set as valid
             *
             * @param {boolean} valid
             */
            setValid: function (valid) {
                this.valid = valid;
            },
 
            /**
             * Return whether is valid
             *
             * @returns {boolean}
             */
            isValid: function () {
                return this.valid;
            },
 
            /**
             * Set the focus on the input of this field
             */
            setFocus: function () {
                this.$('input:first').focus();
            },
 
            /**
             * Set this field as editable
             *
             * @param {boolean} editable
             */
            setEditable: function (editable) {
                this.editable = editable;
            },
 
            /**
             * Set this field as locked
             *
             * @param {boolean} locked
             */
            setLocked: function (locked) {
                this.locked = locked;
            },
 
            /**
             * Return whether this field is editable
             *
             * @returns {boolean}
             */
            isEditable: function () {
                return this.editable;
            },
 
            /**
             * Set this field as ready
             *
             * @param {boolean} ready
             */
            setReady: function (ready) {
                this.ready = ready;
            },
 
            /**
             * Return whether this field is ready
             *
             * @returns {boolean}
             */
            isReady: function () {
                return this.ready;
            },
 
            /**
             * Get the current edit mode (can be 'edit' or 'view')
             *
             * @returns {string}
             */
            getEditMode: function () {
                if (this.editable) {
                    return 'edit';
                } else {
                    return 'view';
                }
            },
 
            /**
             * Return whether this field can be seen
             *
             * @returns {boolean}
             */
            canBeSeen: function () {
                return true;
            },
 
            /**
             * Get current model value for this field, in this format:
             * {locale: 'en_US', scope: null, data: 'stuff'}
             *
             * @returns {Object}
             */
            getCurrentValue: function () {
                return AttributeManager.getValue(
                    this.model.get('values'),
                    this.attribute,
                    this.context.locale,
                    this.context.scope
                );
            },
 
            /**
             * Set current model value for this field
             *
             * @param {*} value
             */
            setCurrentValue: function (value) {
                var productValue = this.getCurrentValue();
 
                Iif (undefined === productValue) {
                    return;
                }
 
                productValue.data = value;
                mediator.trigger('pim_enrich:form:entity:update_state');
            },
 
            /**
             * Get the label of this field (default is code surrounded by brackets)
             *
             * @returns {string}
             */
            getLabel: function () {
                return i18n.getLabel(this.attribute.labels, this.context.uiLocale, this.attribute.code);
            }
        });
    }
);