diff --git a/app/assets/stylesheets/pageflow/ui/forms.scss b/app/assets/stylesheets/pageflow/ui/forms.scss index ebb0fd7100..305aaa105e 100644 --- a/app/assets/stylesheets/pageflow/ui/forms.scss +++ b/app/assets/stylesheets/pageflow/ui/forms.scss @@ -219,7 +219,7 @@ textarea.short { text-decoration: underline; } -.input-hidden_via_binding { +.hidden_via_binding { display: none; } diff --git a/package/spec/editor/views/InfoBoxView-spec.js b/package/spec/editor/views/InfoBoxView-spec.js new file mode 100644 index 0000000000..f33d41144d --- /dev/null +++ b/package/spec/editor/views/InfoBoxView-spec.js @@ -0,0 +1,31 @@ +import Backbone from 'backbone'; + +import {InfoBoxView} from 'editor/views/InfoBoxView'; + +describe('InfoBoxView', () => { + describe('with visibleBindingValue option', () => { + it('hides element when value of attribute does not match', () => { + var view = new InfoBoxView({ + model: new Backbone.Model({hidden: true}), + visibleBinding: 'hidden', + visibleBindingValue: false + }); + + view.render(); + + expect(view.$el).toHaveClass('hidden_via_binding'); + }); + + it('does not set hidden class when value of attribute matches', () => { + var view = new InfoBoxView({ + model: new Backbone.Model({hidden: false}), + visibleBinding: 'hidden', + visibleBindingValue: false + }); + + view.render(); + + expect(view.$el).not.toHaveClass('hidden_via_binding'); + }); + }); +}); diff --git a/package/spec/ui/views/mixins/inputView-spec.js b/package/spec/ui/views/mixins/inputView-spec.js index 28c5a1998c..44048a9dc8 100644 --- a/package/spec/ui/views/mixins/inputView-spec.js +++ b/package/spec/ui/views/mixins/inputView-spec.js @@ -509,7 +509,7 @@ describe('pageflow.inputView', () => { view.render(); - expect(view.$el).not.toHaveClass('input-hidden_via_binding'); + expect(view.$el).not.toHaveClass('hidden_via_binding'); }); it('sets hidden class when attribute is false', () => { @@ -520,7 +520,7 @@ describe('pageflow.inputView', () => { view.render(); - expect(view.$el).toHaveClass('input-hidden_via_binding'); + expect(view.$el).toHaveClass('hidden_via_binding'); }); it('does not set hidden class when attribute is true', () => { @@ -531,7 +531,7 @@ describe('pageflow.inputView', () => { view.render(); - expect(view.$el).not.toHaveClass('input-hidden_via_binding'); + expect(view.$el).not.toHaveClass('hidden_via_binding'); }); it('sets hidden class when attribute changes to false', () => { @@ -544,7 +544,7 @@ describe('pageflow.inputView', () => { view.model.set('active', false); - expect(view.$el).toHaveClass('input-hidden_via_binding'); + expect(view.$el).toHaveClass('hidden_via_binding'); }); it('allows overriding updateVisible method for custom behavior', () => { @@ -583,7 +583,7 @@ describe('pageflow.inputView', () => { view.render(); - expect(view.$el).toHaveClass('input-hidden_via_binding'); + expect(view.$el).toHaveClass('hidden_via_binding'); }); it('does not set hidden class when value of attribute matches', () => { @@ -595,7 +595,7 @@ describe('pageflow.inputView', () => { view.render(); - expect(view.$el).not.toHaveClass('input-hidden_via_binding'); + expect(view.$el).not.toHaveClass('hidden_via_binding'); }); }); @@ -609,7 +609,7 @@ describe('pageflow.inputView', () => { view.render(); - expect(view.$el).toHaveClass('input-hidden_via_binding'); + expect(view.$el).toHaveClass('hidden_via_binding'); }); it('does not set hidden class when function returns true', () => { @@ -621,7 +621,7 @@ describe('pageflow.inputView', () => { view.render(); - expect(view.$el).not.toHaveClass('input-hidden_via_binding'); + expect(view.$el).not.toHaveClass('hidden_via_binding'); }); describe('with multiple binding attributes', () => { @@ -648,7 +648,7 @@ describe('pageflow.inputView', () => { view.render(); view.model.set('active', false); - expect(view.$el).toHaveClass('input-hidden_via_binding'); + expect(view.$el).toHaveClass('hidden_via_binding'); }); }); }); @@ -663,7 +663,7 @@ describe('pageflow.inputView', () => { view.render(); - expect(view.$el).toHaveClass('input-hidden_via_binding'); + expect(view.$el).toHaveClass('hidden_via_binding'); }); it('does not set hidden if true', () => { @@ -675,7 +675,7 @@ describe('pageflow.inputView', () => { view.render(); - expect(view.$el).not.toHaveClass('input-hidden_via_binding'); + expect(view.$el).not.toHaveClass('hidden_via_binding'); }); }); }); diff --git a/package/src/editor/views/InfoBoxView.js b/package/src/editor/views/InfoBoxView.js index 209100c133..ddaa5f4b9c 100644 --- a/package/src/editor/views/InfoBoxView.js +++ b/package/src/editor/views/InfoBoxView.js @@ -1,8 +1,21 @@ import Marionette from 'backbone.marionette'; +import {attributeBinding} from 'pageflow/ui'; + export const InfoBoxView = Marionette.View.extend({ className: 'info_box', + mixins: [attributeBinding], + + initialize() { + this.setupBooleanAttributeBinding('visible', this.updateVisible); + }, + + updateVisible: function() { + this.$el.toggleClass('hidden_via_binding', + this.getBooleanAttributBoundOption('visible') === false); + }, + render: function() { this.$el.addClass(this.options.level) this.$el.html(this.options.text); diff --git a/package/src/testHelpers/dominos/ui/ConfigurationEditorTab.js b/package/src/testHelpers/dominos/ui/ConfigurationEditorTab.js index f5eec63f6b..e06a0bc00d 100644 --- a/package/src/testHelpers/dominos/ui/ConfigurationEditorTab.js +++ b/package/src/testHelpers/dominos/ui/ConfigurationEditorTab.js @@ -12,7 +12,7 @@ export const ConfigurationEditorTab = Base.extend({ }, visibleInputPropertyNames: function() { - return this.$el.find('.input:not(.input-hidden_via_binding)').map(function() { + return this.$el.find('.input:not(.hidden_via_binding)').map(function() { return $(this).data('inputPropertyName'); }).get(); }, diff --git a/package/src/ui/index.js b/package/src/ui/index.js index e7cd73dff6..bce2a4ec47 100644 --- a/package/src/ui/index.js +++ b/package/src/ui/index.js @@ -53,6 +53,7 @@ export * from './views/tableCells/PresenceTableCellView'; export * from './views/tableCells/IconTableCellView'; export * from './views/tableCells/TextTableCellView'; +export * from './views/mixins/attributeBinding'; export * from './views/mixins/inputWithPlaceholderText'; export * from './views/mixins/subviewContainer'; export * from './views/mixins/tooltipContainer'; diff --git a/package/src/ui/views/mixins/attributeBinding.js b/package/src/ui/views/mixins/attributeBinding.js new file mode 100644 index 0000000000..ea9c5c0ba9 --- /dev/null +++ b/package/src/ui/views/mixins/attributeBinding.js @@ -0,0 +1,50 @@ +import _ from 'underscore'; + +export const attributeBinding = { + setupBooleanAttributeBinding(optionName, updateMethod) { + this.setupAttributeBinding(optionName, updateMethod, Boolean); + }, + + getBooleanAttributBoundOption(optionName) { + return this.getAttributeBoundOption(optionName, Boolean); + }, + + setupAttributeBinding: function(optionName, updateMethod, normalize = value => value) { + const binding = this.options[`${optionName}Binding`]; + const view = this; + + if (binding) { + _.flatten([binding]).forEach(attribute => { + this.listenTo(this.model, 'change:' + attribute, update); + }); + } + + update(); + + function update() { + updateMethod.call(view, view.getAttributeBoundOption(optionName, normalize)); + } + }, + + getAttributeBoundOption(optionName, normalize = value => value) { + const binding = this.options[`${optionName}Binding`]; + const bindingValueOptionName = `${optionName}BindingValue`; + + const value = Array.isArray(binding) ? + binding.map(attribute => this.model.get(attribute)) : + this.model.get(binding); + + if (bindingValueOptionName in this.options) { + return value === this.options[bindingValueOptionName]; + } + else if (typeof this.options[optionName] === 'function') { + return normalize(this.options[optionName](value)); + } + else if (optionName in this.options) { + return normalize(this.options[optionName]); + } + else if (binding) { + return normalize(value); + } + } +}; diff --git a/package/src/ui/views/mixins/inputView.js b/package/src/ui/views/mixins/inputView.js index 5df3fbbe85..5e7241307c 100644 --- a/package/src/ui/views/mixins/inputView.js +++ b/package/src/ui/views/mixins/inputView.js @@ -1,6 +1,7 @@ import _ from 'underscore'; import {attributeTranslationKeys, findTranslation, translationKeysWithSuffix} from '../../utils/i18nUtils'; +import {attributeBinding} from './attributeBinding'; /** * Mixin for input views handling common concerns like labels, @@ -131,6 +132,8 @@ import {attributeTranslationKeys, findTranslation, translationKeysWithSuffix} fr * @mixin */ export const inputView = { + ...attributeBinding, + ui: { label: 'label', labelText: 'label .name', @@ -262,54 +265,7 @@ export const inputView = { }, updateVisible: function() { - this.$el.toggleClass('input-hidden_via_binding', + this.$el.toggleClass('hidden_via_binding', this.getBooleanAttributBoundOption('visible') === false); - }, - - setupBooleanAttributeBinding(optionName, updateMethod) { - this.setupAttributeBinding(optionName, updateMethod, Boolean); - }, - - getBooleanAttributBoundOption(optionName) { - return this.getAttributeBoundOption(optionName, Boolean); - }, - - setupAttributeBinding: function(optionName, updateMethod, normalize = value => value) { - const binding = this.options[`${optionName}Binding`]; - const view = this; - - if (binding) { - _.flatten([binding]).forEach(attribute => { - this.listenTo(this.model, 'change:' + attribute, update); - }); - } - - update(); - - function update() { - updateMethod.call(view, view.getAttributeBoundOption(optionName, normalize)); - } - }, - - getAttributeBoundOption(optionName, normalize = value => value) { - const binding = this.options[`${optionName}Binding`]; - const bindingValueOptionName = `${optionName}BindingValue`; - - const value = Array.isArray(binding) ? - binding.map(attribute => this.model.get(attribute)) : - this.model.get(binding); - - if (bindingValueOptionName in this.options) { - return value === this.options[bindingValueOptionName]; - } - else if (typeof this.options[optionName] === 'function') { - return normalize(this.options[optionName](value)); - } - else if (optionName in this.options) { - return normalize(this.options[optionName]); - } - else if (binding) { - return normalize(value); - } } };