UNPKG

grapesjs_codeapps

Version:

Free and Open Source Web Builder Framework/SC Modification

186 lines (158 loc) 4.86 kB
import { isUndefined, isString } from 'underscore'; const Property = require('backbone').Model.extend( { defaults: { name: '', property: '', type: '', defaults: '', info: '', value: '', icon: '', functionName: '', status: '', visible: true, fixedValues: ['initial', 'inherit'], // If true, the property will be forced to be full width full: 0, // If true to the value will be added '!important' important: 0, // If true, will be hidden by default and will show up only for targets // which require this property (via `stylable-require`) // Use case: // you can add all SVG CSS properties with toRequire as true // and then require them on SVG Components toRequire: 0 }, initialize(props = {}, opts = {}) { const name = this.get('name'); const prop = this.get('property'); !this.get('id') && this.set('id', prop); if (!name) { this.set( 'name', prop.charAt(0).toUpperCase() + prop.slice(1).replace(/-/g, ' ') ); } Property.callInit(this, props, opts); }, init() {}, /** * Clear the value * @return {this} */ clearValue(opts = {}) { this.set({ value: undefined }, opts); return this; }, /** * Update value * @param {any} value * @param {Boolen} [complete=true] Indicates if it's a final state * @param {Object} [opts={}] Options */ setValue(value, complete = 1, opts = {}) { const parsed = this.parseValue(value); this.set(parsed, { ...opts, avoidStore: 1 }); // It's important to set an empty value, otherwise the // UndoManager won't see the change if (complete) { this.set('value', '', opts); this.set(parsed, opts); } this.trigger('changed'); }, /** * Like `setValue` but, in addition, prevents the update of the input element * as the changes should come from the input itself. * This method is useful with the definition of custom properties * @param {any} value * @param {Boolen} [complete=true] Indicates if it's a final state * @param {Object} [opts={}] Options */ setValueFromInput(value, complete, opts = {}) { this.setValue(value, complete, { ...opts, fromInput: 1 }); }, /** * Parse a raw value, generally fetched from the target, for this property * @param {string} value Raw value string * @return {Object} * @example * // example with an Input type * prop.parseValue('translateX(10deg)'); * // -> { value: 10, unit: 'deg', functionName: 'translateX' } * */ parseValue(value, opts = {}) { const result = { value }; const imp = '!important'; if (isString(value) && value.indexOf(imp) !== -1) { result.value = value.replace(imp, '').trim(); result.important = 1; } if (!this.get('functionName') && !opts.complete) { return result; } const args = []; let valueStr = `${result.value}`; let start = valueStr.indexOf('(') + 1; let end = valueStr.lastIndexOf(')'); const functionName = valueStr.substring(0, start - 1); if (functionName) result.functionName = functionName; args.push(start); // Will try even if the last closing parentheses is not found if (end >= 0) { args.push(end); } result.value = String.prototype.substring.apply(valueStr, args); if (opts.numeric) { const num = parseFloat(result.value); result.unit = result.value.replace(num, ''); result.value = num; } return result; }, /** * Get the default value * @return {string} * @private */ getDefaultValue() { return this.get('defaults'); }, /** * Get a complete value of the property. * This probably will replace the getValue when all * properties models will be splitted * @param {string} val Custom value to replace the one on the model * @return {string} * @private */ getFullValue(val) { const fn = this.get('functionName'); let value = isUndefined(val) ? this.get('value') : val; if (fn && !isUndefined(value)) { value = `${fn}(${value})`; } if (this.get('important')) { value = `${value} !important`; } return value || ''; } }, { callParentInit(property, ctx, props, opts = {}) { property.prototype.initialize.apply(ctx, [ props, { ...opts, skipInit: 1 } ]); }, callInit(context, props, opts = {}) { !opts.skipInit && context.init(props, opts); } } ); module.exports = Property;