/** * Color form view * * - It is used in 'Marker fill', 'Polygon fill',... * */ cdb.forms.Color = cdb.core.View.extend({ className: 'form-view form_color', events: { 'click .image-picker' : '_openImagePicker', 'click .color-picker' : '_openColorPicker' }, initialize: function() { this.template = cdb.templates.getTemplate('old_common/views/color_form'); this.property = this.options.property; this.model.bind('change', this.render, this); this.image_property = this.options.extra ? this.options.extra.image_property: null; this.image_kind = this.options.extra ? this.options.extra.image_kind: null; this.image_kind = this.image_kind || 'marker'; }, render: function() { this.$el.html( this.template({ image_kind: this.image_kind, image_property: this.image_property, image_value: this.model.get(this.image_property), color: this.model.get(this.property) }) ); if (this.image_property) this._createTooltips(); return this; }, _createTooltips: function() { this.addView(new cdb.common.TipsyTooltip({ el: this.$(".image-picker"), delayIn: 100 })); }, _createPicker: function() { var tick, vertical_position, horizontal_position; if (this.options.extra) { if (this.options.extra.tick) { tick = this.options.extra.tick; } if (this.options.extra.picker_vertical_position) { vertical_position = this.options.extra.picker_vertical_position; } if (this.options.extra.picker_horizontal_position) { horizontal_position = this.options.extra.picker_horizontal_position; } } this.color_picker = new cdb.admin.ColorPicker({ target: this.$el, colors: this.options.colors, extra_colors: this.options.extra_colors, tick: tick, vertical_position: vertical_position, horizontal_position: horizontal_position }).bind("colorChosen", function(color, close) { if (this.image_property == this.property) { this.model.set(this.property, color); } else { this.model.unset(this.image_property, { silent: true }); this.model.set(this.property, color); } if (close) this._destroyPicker(); }, this); this._bindColorPicker(); this.addView(this.color_picker); }, _destroyPicker: function() { if (this.color_picker) { this._unbindColorPicker(); this.removeView(this.color_picker); this.color_picker.hide(); delete this.color_picker; } }, _bindColorPicker: function() { cdb.god.bind("closeDialogs", this._destroyPicker, this); cdb.god.bind("closeDialogs:color", this._destroyPicker, this); }, _unbindColorPicker: function() { cdb.god.unbind("closeDialogs", this._destroyPicker, this); cdb.god.unbind("closeDialogs:color", this._destroyPicker, this); }, setExtraColors: function(colors) { if (this.color_picker) this.color_picker.setColors('extra_colors', colors); }, setColors: function(colors) { if (this.color_picker) this.color_picker.setColors('colors', colors); }, _openImagePicker: function(e) { this.killEvent(e); if (!this.image_property) return this; cdb.god.trigger("closeDialogs:color"); this.user = new cdb.admin.User(window.user_data); var dialog = new cdb.editor.ImagePickerView({ user: this.user, kind: this.image_kind }); dialog.appendToBody(); dialog.bind('fileChosen', this._onImageFileChosen, this); }, _onImageFileChosen: function(url) { if (this.image_property) { if (this.image_property !== this.property) { this.model.unset(this.property, { silent: true }); } this.model.set(this.image_property, 'url(' + url + ')'); } }, _openColorPicker: function(e) { this.killEvent(e); if (this.color_picker) this._destroyPicker(); cdb.god.trigger("closeDialogs:color"); if (!this.color_picker) { this._createPicker(); $('body').append(this.color_picker.render().el); this.color_picker.init(this.model.get(this.property)); } } }); /** * Color widget with color picker showing * all colors applied in the style. */ cdb.forms.ColorWizard = cdb.forms.Color.extend({ _createPicker: function() { // Get wizard applied colors if (this.model.layer && this.model.layer.get('tile_style')) { var style = this.model.layer.get("tile_style"); var cartoParser = new cdb.admin.CartoParser(style); this.options.extra_colors = cartoParser.colorsUsed({ mode: "hex" }); } cdb.forms.Color.prototype._createPicker.call(this); }, }); /** * dummy view for hidden fields */ cdb.forms.Hidden = cdb.core.View.extend({ className: 'form-view form_hidden', initialize: function() { this.add_related_model(this.model); } }); cdb.forms.SimpleNumber = cdb.core.View.extend({ className: 'form-view form_spinner', defaults: { max: 999999999999, min: -999999999999, inc: 1, width: 25, pattern: /^-?[0-9]+\.?[0-9]*$/, debounce_time: 200, disable_triggering: false }, events: { 'click .plus': '_plus', 'click .minus': '_minus', 'keypress input.value': '_checkInputPress', 'keydown input.value': '_checkInputPress', 'keyup input.value': '_checkInputUp', 'change .value': '_checkValueChange', 'click': '_showSlider' }, initialize: function() { _.bindAll(this, '_fireChange', '_checkNumber'); this.property = this.options.property; this.model.bind('change', this.render, this); // Check pattern, if it is empty or not valid, // delete the option before extending defaults if (!this.options.pattern || typeof this.options.pattern !== "object" || (typeof this.options.pattern === "object" && !this.options.pattern.test) ) { delete this.options.pattern; } _.defaults(this.options, this.defaults); // Create slider if(!this.options.noSlider) { this._initSlider(); } if(this.options.debounce_time > 0) { this._fireChange = _.debounce(this._fireChange, this.options.debounce_time); } }, render: function(prop) { var value = this.options.initValue || this.model.get(this.property); if (prop && _.isNumber(prop)) { value = prop; } this.$el.html('+-'); this.$('.value').val(value); if (this.options.classes) this.$el.addClass(this.options.classes); if (this.options.disabled) { this.undelegateEvents(); this.$el .addClass('disabled') .find('a').bind('click', this.killEvent); } return this; }, _fireChange: function() { this.model.change(); }, _changeValue: function(a) { this.model.set(a, { silent: true }); this._fireChange(); }, inc: function(c) { var a = {}; var v = a[this.property] = parseFloat(this.model.get(this.property)) + c; v = a[this.property] = Math.min(this.options.max, v.toFixed? v.toFixed(1): 1*v); a[this.property] = Math.max(this.options.min, v); this._changeValue(a); // don't wait to be notified by model, render as fast as the user changes the value this.render(a[this.property]); }, _plus: function(e) { e && e.preventDefault(); this.trigger("saved", this); this.inc(this.options.inc); return false; }, _minus: function(e) { e && e.preventDefault(); this.trigger("saved", this); this.inc(-this.options.inc); return false; }, _initSlider: function() { var self = this; this.spinner_slider = new cdb.admin.SpinnerSlider({ target: this.$el, template_base: 'old_common/views/spinner_slider' }).bind("valueSet", function(value) { // Set new model var a = {}; a[self.property] = value; self.model.set(a); }).bind("valueChanged", function(value) { // Set new value self.$el.find(".value").val(value); }); this.addView(this.spinner_slider); }, _checkNumber: function(number) { return this.options.pattern.test(number); }, _checkInputPress: function(ev) { var newChar = String.fromCharCode(ev.charCode); if(newChar == '-' || newChar == '.' || 1*newChar !== NaN) { return true; } else { ev.preventDefault(); ev.stopPropagation(); return false; } }, _checkInputUp: function(ev) { this.value? null : this.value = this.model.get(this.property); var number = $(ev.target).val(); if (ev.keyCode == 40) { ev.preventDefault(); ev.stopPropagation(); this.inc(-this.options.inc); this._saveValue(ev); this.$el.find("input").focus(); return false; } if (ev.keyCode == 38) { ev.preventDefault(); ev.stopPropagation(); this.inc(this.options.inc); this._saveValue(ev); this.$el.find("input").focus(); return false; } // If it is an ENTER -> saves! if (ev.keyCode === 13) { this._saveValue(ev, true); return false; } // If not, check the key if (!this._checkNumber(number) && number != '-' && number != '') { this.$el.find("input.value").val(this.value); // ev.stopPropagation(); // ev.preventDefault(); } else { if(number != '-' && number != '') { this.value = $(ev.target).val(); } } return true; }, _checkValueChange: function(ev) { var number = $(ev.target).val(); number = (number == '' || number == '-')? 0 : 1*number if (!this._checkNumber(number)) { this.$el.find("input.value").val(this.value); } else { this._saveValue(ev, true); this.value = $(ev.target).val(); } return true; }, _saveValue: function(ev, close) { var a = {}; var val = this.$el.find("input.value").val() var baseNumber = (this.options.min < 0 && this.options.max > 0)? 0: this.options.min; var number = (val == '' || val == '-') ? baseNumber : 1*val; if (number < this.options.min) number = this.options.min; if (number > this.options.max) number = this.options.max; this.$el.find("input.value").val(number); a[this.property] = number; this.model.set(a); this.trigger("saved", this); if (close && !this.options.disable_triggering) { cdb.god.trigger("closeDialogs"); } }, _showSlider: function(ev) { ev.preventDefault(); ev.stopPropagation(); this.$el.find("input").focus(); } }); cdb.forms.SimpleNumberWithLabel = cdb.forms.SimpleNumber.extend({ className: 'form-view form_spinner with-label', render: function(prop) { var value = this.options.initValue || this.model.get(this.property); if (prop && _.isNumber(prop)) { value = prop; } this.$el.html( this.getTemplate('old_common/forms/widget_simple_number_with_label')({ label: this.options.label, isDisabled: this.options.disabled, width: this.options.width }) ); this.$('.value').val(value); if (this.options.classes) this.$el.addClass(this.options.classes); if (this.options.disabled) { this.undelegateEvents(); this.$el .addClass('disabled') .find('a').bind('click', this.killEvent); } return this; } }); cdb.forms.Spinner = cdb.core.View.extend({ className: 'form-view form_spinner', defaults: { max: 999999999999, min: -999999999999, inc: 1, width: 25, pattern: /^-?[0-9]+\.?[0-9]*$/, debounce_time: 200 }, events: { 'click .plus': '_plus', 'click .minus': '_minus', 'keypress input.value': '_checkInputPress', 'keydown input.value': '_checkInputPress', 'keyup input.value': '_checkInputUp', 'change .value': '_checkValueChange', 'click': '_showSlider' }, initialize: function() { _.bindAll(this, '_fireChange', '_checkNumber'); this.property = this.options.property; this.model.bind('change', this.render, this); // Check pattern, if it is empty or not valid, // delete the option before extending defaults if (!this.options.pattern || typeof this.options.pattern !== "object" || (typeof this.options.pattern === "object" && !this.options.pattern.test) ) { delete this.options.pattern; } _.defaults(this.options, this.defaults); // Create slider if(!this.options.noSlider) { this._initSlider(); } if(this.options.debounce_time > 0) { this._fireChange = _.debounce(this._fireChange, this.options.debounce_time); } }, render: function(prop) { var value = this.options.initValue || this.model.get(this.property); if (prop && _.isNumber(prop)) { value = prop; } this.$el.html('+-'); this.$('.value').val(value); if (this.options.disabled) { this.undelegateEvents(); this.$el .addClass('disabled') .find('a').bind('click', this.killEvent); } return this; }, _fireChange: function() { this.model.change(); }, _changeValue: function(a) { this.model.set(a, { silent: true }); this._fireChange(); }, inc: function(c) { var a = {}; var v = a[this.property] = this.model.get(this.property) + c; v = a[this.property] = Math.min(this.options.max, v.toFixed? v.toFixed(1): 1*v); a[this.property] = Math.max(this.options.min, v); this._changeValue(a); // don't wait to be notified by model, render as fast as the user changes the value this.render(a[this.property]); }, _plus: function(e) { e && e.preventDefault(); this.inc(this.options.inc); return false; }, _minus: function(e) { e && e.preventDefault(); this.inc(-this.options.inc); return false; }, _initSlider: function() { var self = this; this.spinner_slider = new cdb.admin.SpinnerSlider({ target: this.$el, template_base: 'old_common/views/spinner_slider' }).bind("valueSet", function(value) { // Set new model var a = {}; a[self.property] = value; self.model.set(a); }).bind("valueChanged", function(value) { // Set new value self.$el.find(".value").val(value); }); this.addView(this.spinner_slider); }, _checkNumber: function(number) { return this.options.pattern.test(number); }, _checkInputPress: function(ev) { var newChar = String.fromCharCode(ev.charCode); if(newChar == '-' || newChar == '.' || 1*newChar !== NaN) { return true; } else { ev.preventDefault(); ev.stopPropagation(); return false; } }, _checkInputUp: function(ev) { this.value? null : this.value = this.model.get(this.property); var number = $(ev.target).val(); // If it is an ENTER -> saves! if (ev.keyCode === 13) { this._saveValue(ev); return false; } // If not, check the key if (!this._checkNumber(number) && number != '-' && number != '') { this.$el.find("input.value").val(this.value); // ev.stopPropagation(); // ev.preventDefault(); } else { if(number != '-' && number != '') { this.value = $(ev.target).val(); } } return true; }, _checkValueChange: function(ev) { var number = $(ev.target).val(); number = (number == '' || number == '-')? 0 : 1*number if (!this._checkNumber(number)) { this.$el.find("input.value").val(this.value); } else { this._saveValue(ev); this.value = $(ev.target).val(); } return true; }, _saveValue: function(ev) { var a = {}; var val = this.$el.find("input.value").val() var baseNumber = (this.options.min < 0 && this.options.max > 0)? 0: this.options.min; var number = (val == '' || val == '-') ? baseNumber : 1*val; this.$el.find("input.value").val(number); a[this.property] = number; this.model.set(a); cdb.god.trigger("closeDialogs"); }, _showSlider: function(ev) { if(!this.options.noSlider) { ev.stopPropagation(); cdb.god.unbind("closeDialogs", this.spinner_slider.hide, this.spinner_slider); cdb.god.trigger("closeDialogs"); if (!this.spinner_slider.el.parentElement) { $('body').append(this.spinner_slider.render().el); this.spinner_slider.init(this.options.max, this.options.min, this.options.inc, this.$el.find("input.value").val()); cdb.god.bind("closeDialogs", this.spinner_slider.hide, this.spinner_slider); cdb.god.bind("closeDialogs:color", this.spinner_slider.hide, this.spinner_slider); } this.$el.find("input.value").focus(); } } }); cdb.forms.Opacity = cdb.forms.Spinner.extend({ initialize: function() { _.defaults(this.options, { max: 1, min: 0, inc: 0.1 }); // Added correct class to the spinner this.$el.addClass("opacity"); cdb.forms.Spinner.prototype.initialize.call(this); } }); cdb.forms.SimpleOpacity = cdb.forms.SimpleNumber.extend({ initialize: function() { _.defaults(this.options, { max: 1, min: 0, inc: 0.1 }); // Added correct class to the spinner this.$el.addClass("opacity"); cdb.forms.Spinner.prototype.initialize.call(this); } }); // same as Opacity but manages the case when the cartocss // contains a polygon-pattern cdb.forms.OpacityPolygon = cdb.forms.Spinner.extend({ initialize: function() { _.defaults(this.options, { max: 1, min: 0, inc: 0.1 }); // Added correct class to the spinner this.$el.addClass("opacity"); this.model.bind('change', function() { this.switchProperty(); }, this); cdb.forms.Spinner.prototype.initialize.call(this); //this.switchProperty(); }, switchProperty: function() { if(this.model.get('polygon-pattern-file')) { if(!this.originalProperty) { this.originalProperty = this.property; this.property = 'polygon-pattern-opacity'; var val = this.model.get(this.property); this.model.set(this.property, val === undefined ? this.model.get(this.originalProperty): val); this.model.unset(this.originalProperty); } } else { if(this.property === 'polygon-pattern-opacity') { this.property = this.originalProperty; this.originalProperty = null; this.model.set(this.property, this.model.get('polygon-pattern-opacity')); this.model.unset('polygon-pattern-opacity'); } } } }); cdb.forms.Width = cdb.forms.Spinner.extend({ initialize: function() { _.defaults(this.options, { max: 40, min: 0, inc: 0.5 }); cdb.forms.Spinner.prototype.initialize.call(this); } }); cdb.forms.Combo = cdb.core.View.extend({ className: 'form-view form_combo', options: { minimumResultsForSearch: 20, placeholder: '', formatResult: false, formatSelection: false, matcher: false, dropdownCssClass: '' }, events: { 'change select': '_changeSelection' }, initialize: function() { _.bindAll(this, "_onUpdate", "_changeSelection"); this.data = this.options.extra; if (this.model) { this.add_related_model(this.model); this.model.bind("change:" + this.options.property, this._onUpdate, this); } }, deselect: function() { this.$el.find("select").val("").change(); }, updateData: function(data) { this.data = data; this._onUpdate(); }, _onUpdate: function() { this.render(); }, _getOptions: function() { var options = _.map(this.data, function(option) { if (_.isArray(option)) { return ''; } else { return ''; } }).join(""); if (this.options.placeholder) options = "" + options; return options; }, _setValue: function(value) { this.$select.val(value); }, render: function() { var self = this; // Options this.$select = $(''); // Method var method = this.model && this.model.get("method") && this.model.get("method").replace(/ /g,"_").toLowerCase(); // Attributes this.$select.attr({ style: (this.options.width ? "width:" + this.options.width : '') }); this.$select.addClass(this.options.property + (method ? ' ' + method : '')); // Disabled? if (this.options.disabled) this.$select.attr("disabled", ''); // Sets the value this._setValue(this.model && this.model.get(this.options.property) || this.options.property); // Append this.$el.html(this.$select); // Apply select2, but before destroy the bindings if (!this.options || !this.options.plainSelect) { var $select = this.$("select"); $select.select2("destroy"); var combo_options = { minimumResultsForSearch: this.options.minimumResultsForSearch, placeholder: this.options.placeholder, dropdownCssClass: this.options.dropdownCssClass }; if (this.options.formatResult) combo_options.formatResult = this._formatResult; if (this.options.formatSelection) combo_options.formatSelection = this._formatSelection; if (this.options.matcher) combo_options.matcher = this._matcher; $select.select2(combo_options); } return this; }, _changeSelection: function(e) { var a = {}; var val = this.$('select').val(); a[this.options.property] = val; if (this.model) { if (val) this.model.set(a); else this.model.set(a, { silent: true }); } // Send trigger if (val) this.trigger('change', a[this.options.property]); }, _formatResult: function(data) { return data.id || data.text; }, _matcher: function(term, text, option) { return text.toUpperCase().indexOf(term.toUpperCase())>=0; }, clean: function() { this.$select.select2("destroy"); cdb.core.View.prototype.clean.call(this); } }); cdb.forms.Switch = cdb.core.View.extend({ events: { 'click': '_onClick' }, tagName: 'a', className: 'form-view form_switch', initialize: function() { this.property = this.options.property; this.model.bind('change:' + this.property, this._change, this); }, _onClick: function(e) { e.preventDefault(); if (!this.$el.hasClass("inactive")) { var a = {}; var value = !this.model.get(this.property); a[this.property] = value; this.model.set(a); this.trigger("switched", this.property, value); } return false; }, _change: function() { if(this.model.get(this.property)) { this.$el.removeClass('disabled').addClass('enabled'); } else { this.$el.removeClass('enabled').addClass('disabled'); } }, render: function() { this.$el.append(""); this._change(); return this; } }); cdb.forms.TextAlign = cdb.core.View.extend({ className: 'form-view form_align', defaults: { debounce_time: 200 }, events: { 'click .align': '_align' }, initialize: function() { _.bindAll(this, '_fireChange'); this.property = this.options.property; this.template = cdb.templates.getTemplate('old_common/views/text_align'); this.model.bind('change', this.render, this); // Check pattern, if it is empty or not valid, // delete the option before extending defaults if (!this.options.pattern || typeof this.options.pattern !== "object" || (typeof this.options.pattern === "object" && !this.options.pattern.test) ) { delete this.options.pattern; } _.defaults(this.options, this.defaults); if(this.options.debounce_time > 0) { this._fireChange = _.debounce(this._fireChange, this.options.debounce_time); } }, _fireChange: function() { this.model.change(); }, _align: function(e) { e && e.preventDefault(); var align = $(e.target).attr("data-align"); var a = {}; a[this.property] = align; this.model.set(a, { silent: true }); this._fireChange(); }, render: function(prop) { var value = this.options.initValue || this.model.get(this.property); var alignments = this.options.alignments || {}; var left = alignments.left === undefined ? true : alignments.left; var right = alignments.right === undefined ? true : alignments.right; var center = alignments.center === undefined ? true : alignments.center; this.$el.html(this.template({ left: left, right: right, center: center })); this.$el.find("a[data-align='"+ value +"']").addClass("selected"); if (this.options.disabled) { this.undelegateEvents(); this.$el .addClass('disabled') .find('a').bind('click', this.killEvent); } return this; }, });