From eae6346e1d7df68d90199978bcae363fe92fcebc Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor Date: Tue, 9 Jun 2015 16:15:47 -0700 Subject: [PATCH 01/12] Rework attachment attribute field to extend editAttributeField Just restructures this attribute field model a bit to better follow the general pattern of Backbone views. --- js/build/field-attachment.js | 221 +++++++++++++++++----------------- js/src/field-attachment.js | 223 ++++++++++++++++++----------------- 2 files changed, 231 insertions(+), 213 deletions(-) diff --git a/js/build/field-attachment.js b/js/build/field-attachment.js index 0468bb0b..3099de78 100644 --- a/js/build/field-attachment.js +++ b/js/build/field-attachment.js @@ -35,158 +35,167 @@ module.exports = Shortcodes; },{"./../models/shortcode.js":6}],3:[function(require,module,exports){ (function (global){ var sui = require('./utils/sui.js'), - editAttributeField = require('./views/edit-attribute-field.js'), - $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null); + $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null), + editAttributeField = require('./views/edit-attribute-field.js'); // Cache attachment IDs for quicker loading. var iDCache = {}; sui.views.editAttributeFieldAttachment = editAttributeField.extend( { - render: function() { + events: { + 'click .add' : '_openMediaFrame', + 'click .remove' : '_removeAttachment', + 'selectAttachment' : '_selectAttachment', + }, - var model = this.model; + /** + * Update the field attachment. + * Re-renders UI. + * If ID is empty - does nothing. + * + * @param {int} id Attachment ID + */ + updateValue: function( id ) { - // Set model default values. - for ( var arg in ShortcakeImageFieldData.defaultArgs ) { - if ( ! model.get( arg ) ) { - model.set( arg, ShortcakeImageFieldData.defaultArgs[ arg ] ); - } + if ( ! id ) { + return; } - this.$el.html( this.template( model.toJSON() ) ); + this.model.set( 'value', id ); - var $container = this.$el.find( '.shortcake-attachment-preview' ); - var $addButton = $container.find( 'button.add' ); - var $removeButton = $container.find( 'button.remove' ); + var self = this; - var frame = wp.media( { - multiple: false, - title: model.get( 'frameTitle' ), - library: { - type: model.get( 'libraryType' ), - }, - } ); + if ( iDCache[ id ] ) { + self._renderPreview( iDCache[ id ] ); + return; + } - /** - * Update the field attachment. - * Re-renders UI. - * If ID is empty - does nothing. - * - * @param {int} id Attachment ID - */ - var updateAttachment = function( id ) { + this.$container.addClass( 'loading' ); - if ( ! id ) { - return; - } + wp.ajax.post( 'get-attachment', { + 'id': id + } ).done( function( attachment ) { + // Cache for later. + iDCache[ id ] = attachment; + self._renderPreview( attachment ); + self.$container.removeClass( 'loading' ); + } ); - model.set( 'value', id ); + }, - if ( iDCache[ id ] ) { - renderPreview( iDCache[ id ] ); - return; + render: function() { + + // Set model default values. + for ( var arg in ShortcakeImageFieldData.defaultArgs ) { + if ( ! this.model.get( arg ) ) { + this.model.set( arg, ShortcakeImageFieldData.defaultArgs[ arg ] ); } + } - $container.addClass( 'loading' ); + this.$el.html( this.template( this.model.toJSON() ) ); - wp.ajax.post( 'get-attachment', { - 'id': id - } ).done( function( attachment ) { - // Cache for later. - iDCache[ id ] = attachment; - renderPreview( attachment ); - $container.removeClass( 'loading' ); - } ); + this.$container = this.$el.find( '.shortcake-attachment-preview' ); + var $addButton = this.$container.find( 'button.add' ); - } + this.frame = wp.media( { + multiple: false, + title: this.model.get( 'frameTitle' ), + library: { + type: this.model.get( 'libraryType' ), + }, + } ); - /** - * Renders attachment preview in field. - * @param {object} attachment model - * @return null - */ - var renderPreview = function( attachment ) { + // Add initial Attachment if available. + this.updateValue( this.model.get( 'value' ) ); - var $thumbnail = $('
'); + }, - if ( 'image' !== attachment.type ) { + /** + * Renders attachment preview in field. + * @param {object} attachment model + * @return null + */ + _renderPreview: function( attachment ) { - $( '', { - src: attachment.icon, - alt: attachment.title, - } ).appendTo( $thumbnail ); + var $thumbnail = $('
'); - $( '
', { - class: 'filename', - html: '
' + attachment.title + '
', - } ).appendTo( $thumbnail ); + if ( 'image' !== attachment.type ) { - } else { + $( '', { + src: attachment.icon, + alt: attachment.title, + } ).appendTo( $thumbnail ); - attachmentThumb = (typeof attachment.sizes.thumbnail !== 'undefined') ? - attachment.sizes.thumbnail : - _.first( _.sortBy( attachment.sizes, 'width' ) ); + $( '
', { + class: 'filename', + html: '
' + attachment.title + '
', + } ).appendTo( $thumbnail ); - $( '', { - src: attachmentThumb.url, - width: attachmentThumb.width, - height: attachmentThumb.height, - alt: attachment.alt, - } ) .appendTo( $thumbnail ) + } else { - } + attachmentThumb = (typeof attachment.sizes.thumbnail !== 'undefined') ? + attachment.sizes.thumbnail : + _.first( _.sortBy( attachment.sizes, 'width' ) ); - $thumbnail.find( 'img' ).wrap( '
' ); - $container.append( $thumbnail ); - $container.toggleClass( 'has-attachment', true ); + $( '', { + src: attachmentThumb.url, + width: attachmentThumb.width, + height: attachmentThumb.height, + alt: attachment.alt, + } ) .appendTo( $thumbnail ) } - /** - * Remove the attachment. - * Render preview & Update the model. - */ - var removeAttachment = function() { + $thumbnail.find( 'img' ).wrap( '
' ); + this.$container.append( $thumbnail ); + this.$container.toggleClass( 'has-attachment', true ); - model.set( 'value', null ); + }, - $container.toggleClass( 'has-attachment', false ); - $container.toggleClass( 'has-attachment', false ); - $container.find( '.thumbnail' ).remove(); - } + /** + * Open media frame when add button is clicked. + * + */ + _openMediaFrame: function(e) { + e.preventDefault(); + this.frame.open(); - // Add initial Attachment if available. - updateAttachment( model.get( 'value' ) ); - - // Remove file when the button is clicked. - $removeButton.click( function(e) { - e.preventDefault(); - removeAttachment(); - }); - - // Open media frame when add button is clicked - $addButton.click( function(e) { - e.preventDefault(); - frame.open(); + var self = this; + this.frame.on( 'select', function() { + self.$el.trigger( 'selectAttachment' ); } ); - // Update the attachment when an item is selected. - frame.on( 'select', function() { + }, - var selection = frame.state().get('selection'); - attachment = selection.first(); + /** + * When an attachment is selected from the media frame, update the model value. + * + */ + _selectAttachment: function(e) { + var selection = this.frame.state().get('selection'); + attachment = selection.first(); - updateAttachment( attachment.id ); + this.updateValue( attachment.id ); + this.frame.close(); + }, - frame.close(); + /** + * Remove the attachment. + * Render preview & Update the model. + */ + _removeAttachment: function(e) { + e.preventDefault(); - }); + this.model.set( 'value', null ); + this.$container.toggleClass( 'has-attachment', false ); + this.$container.toggleClass( 'has-attachment', false ); + this.$container.find( '.thumbnail' ).remove(); } - } ); + }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./utils/sui.js":7,"./views/edit-attribute-field.js":8}],4:[function(require,module,exports){ (function (global){ diff --git a/js/src/field-attachment.js b/js/src/field-attachment.js index e14d9daf..46b0e02d 100644 --- a/js/src/field-attachment.js +++ b/js/src/field-attachment.js @@ -1,152 +1,161 @@ var sui = require('sui-utils/sui'), - editAttributeField = require( 'sui-views/edit-attribute-field' ), - $ = require('jquery'); + $ = require('jquery'), + editAttributeField = require( 'sui-views/edit-attribute-field' ); // Cache attachment IDs for quicker loading. var iDCache = {}; sui.views.editAttributeFieldAttachment = editAttributeField.extend( { - render: function() { + events: { + 'click .add' : '_openMediaFrame', + 'click .remove' : '_removeAttachment', + 'selectAttachment' : '_selectAttachment', + }, + + /** + * Update the field attachment. + * Re-renders UI. + * If ID is empty - does nothing. + * + * @param {int} id Attachment ID + */ + updateValue: function( id ) { + + if ( ! id ) { + return; + } - var model = this.model; + this.model.set( 'value', id ); - // Set model default values. - for ( var arg in ShortcakeImageFieldData.defaultArgs ) { - if ( ! model.get( arg ) ) { - model.set( arg, ShortcakeImageFieldData.defaultArgs[ arg ] ); - } - } + var self = this; - this.$el.html( this.template( model.toJSON() ) ); + if ( iDCache[ id ] ) { + self._renderPreview( iDCache[ id ] ); + return; + } - var $container = this.$el.find( '.shortcake-attachment-preview' ); - var $addButton = $container.find( 'button.add' ); - var $removeButton = $container.find( 'button.remove' ); + this.$container.addClass( 'loading' ); - var frame = wp.media( { - multiple: false, - title: model.get( 'frameTitle' ), - library: { - type: model.get( 'libraryType' ), - }, + wp.ajax.post( 'get-attachment', { + 'id': id + } ).done( function( attachment ) { + // Cache for later. + iDCache[ id ] = attachment; + self._renderPreview( attachment ); + self.$container.removeClass( 'loading' ); } ); - /** - * Update the field attachment. - * Re-renders UI. - * If ID is empty - does nothing. - * - * @param {int} id Attachment ID - */ - var updateAttachment = function( id ) { - - if ( ! id ) { - return; - } + }, - model.set( 'value', id ); + render: function() { - if ( iDCache[ id ] ) { - renderPreview( iDCache[ id ] ); - return; + // Set model default values. + for ( var arg in ShortcakeImageFieldData.defaultArgs ) { + if ( ! this.model.get( arg ) ) { + this.model.set( arg, ShortcakeImageFieldData.defaultArgs[ arg ] ); } + } - $container.addClass( 'loading' ); + this.$el.html( this.template( this.model.toJSON() ) ); - wp.ajax.post( 'get-attachment', { - 'id': id - } ).done( function( attachment ) { - // Cache for later. - iDCache[ id ] = attachment; - renderPreview( attachment ); - $container.removeClass( 'loading' ); - } ); + this.$container = this.$el.find( '.shortcake-attachment-preview' ); + var $addButton = this.$container.find( 'button.add' ); - } + this.frame = wp.media( { + multiple: false, + title: this.model.get( 'frameTitle' ), + library: { + type: this.model.get( 'libraryType' ), + }, + } ); - /** - * Renders attachment preview in field. - * @param {object} attachment model - * @return null - */ - var renderPreview = function( attachment ) { + // Add initial Attachment if available. + this.updateValue( this.model.get( 'value' ) ); - var $thumbnail = $('
'); + }, - if ( 'image' !== attachment.type ) { + /** + * Renders attachment preview in field. + * @param {object} attachment model + * @return null + */ + _renderPreview: function( attachment ) { - $( '', { - src: attachment.icon, - alt: attachment.title, - } ).appendTo( $thumbnail ); + var $thumbnail = $('
'); - $( '
', { - class: 'filename', - html: '
' + attachment.title + '
', - } ).appendTo( $thumbnail ); + if ( 'image' !== attachment.type ) { - } else { + $( '', { + src: attachment.icon, + alt: attachment.title, + } ).appendTo( $thumbnail ); - attachmentThumb = (typeof attachment.sizes.thumbnail !== 'undefined') ? - attachment.sizes.thumbnail : - _.first( _.sortBy( attachment.sizes, 'width' ) ); + $( '
', { + class: 'filename', + html: '
' + attachment.title + '
', + } ).appendTo( $thumbnail ); - $( '', { - src: attachmentThumb.url, - width: attachmentThumb.width, - height: attachmentThumb.height, - alt: attachment.alt, - } ) .appendTo( $thumbnail ) + } else { - } + attachmentThumb = (typeof attachment.sizes.thumbnail !== 'undefined') ? + attachment.sizes.thumbnail : + _.first( _.sortBy( attachment.sizes, 'width' ) ); - $thumbnail.find( 'img' ).wrap( '
' ); - $container.append( $thumbnail ); - $container.toggleClass( 'has-attachment', true ); + $( '', { + src: attachmentThumb.url, + width: attachmentThumb.width, + height: attachmentThumb.height, + alt: attachment.alt, + } ) .appendTo( $thumbnail ) } - /** - * Remove the attachment. - * Render preview & Update the model. - */ - var removeAttachment = function() { + $thumbnail.find( 'img' ).wrap( '
' ); + this.$container.append( $thumbnail ); + this.$container.toggleClass( 'has-attachment', true ); - model.set( 'value', null ); + }, - $container.toggleClass( 'has-attachment', false ); - $container.toggleClass( 'has-attachment', false ); - $container.find( '.thumbnail' ).remove(); - } + /** + * Open media frame when add button is clicked. + * + */ + _openMediaFrame: function(e) { + e.preventDefault(); + this.frame.open(); - // Add initial Attachment if available. - updateAttachment( model.get( 'value' ) ); - - // Remove file when the button is clicked. - $removeButton.click( function(e) { - e.preventDefault(); - removeAttachment(); - }); - - // Open media frame when add button is clicked - $addButton.click( function(e) { - e.preventDefault(); - frame.open(); + var self = this; + this.frame.on( 'select', function() { + self.$el.trigger( 'selectAttachment' ); } ); - // Update the attachment when an item is selected. - frame.on( 'select', function() { + }, - var selection = frame.state().get('selection'); - attachment = selection.first(); + /** + * When an attachment is selected from the media frame, update the model value. + * + */ + _selectAttachment: function(e) { + var selection = this.frame.state().get('selection'); + attachment = selection.first(); - updateAttachment( attachment.id ); + this.updateValue( attachment.id ); + this.frame.close(); + }, - frame.close(); + /** + * Remove the attachment. + * Render preview & Update the model. + */ + _removeAttachment: function(e) { + e.preventDefault(); - }); + this.model.set( 'value', null ); + this.$container.toggleClass( 'has-attachment', false ); + this.$container.toggleClass( 'has-attachment', false ); + this.$container.find( '.thumbnail' ).remove(); } - } ); + From aa09b572f474d48e8c1feb3d8a8d1eb0fa4aef0e Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor Date: Tue, 9 Jun 2015 19:23:36 -0700 Subject: [PATCH 02/12] Allow custom fields to trigger callback. Abstracts triggerCallbacks to its own method, so it can be called from attribute fields that extend `editAttributeField` but override its `updateValue` method. --- js/build/field-attachment.js | 10 +++++++++- js/build/field-color.js | 5 +++++ js/build/shortcode-ui.js | 5 +++++ js/src/field-attachment.js | 5 ++++- js/src/views/edit-attribute-field.js | 5 +++++ 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/js/build/field-attachment.js b/js/build/field-attachment.js index 3099de78..8f3d8487 100644 --- a/js/build/field-attachment.js +++ b/js/build/field-attachment.js @@ -82,12 +82,15 @@ sui.views.editAttributeFieldAttachment = editAttributeField.extend( { self.$container.removeClass( 'loading' ); } ); + // Call the updateValue() function, to trigger any listeners + // hooked on it. + this.triggerCallbacks(); }, render: function() { // Set model default values. - for ( var arg in ShortcakeImageFieldData.defaultArgs ) { +for ( var arg in ShortcakeImageFieldData.defaultArgs ) { if ( ! this.model.get( arg ) ) { this.model.set( arg, ShortcakeImageFieldData.defaultArgs[ arg ] ); } @@ -432,6 +435,11 @@ var editAttributeField = Backbone.View.extend( { this.model.set( 'value', $el.val() ); } + this.triggerCallbacks(); + }, + + triggerCallbacks: function() { + var shortcodeName = this.shortcode.attributes.shortcode_tag, attributeName = this.model.get( 'attr' ), hookName = [ shortcodeName, attributeName ].join( '.' ), diff --git a/js/build/field-color.js b/js/build/field-color.js index 0d5d663c..7e7b9c69 100644 --- a/js/build/field-color.js +++ b/js/build/field-color.js @@ -290,6 +290,11 @@ var editAttributeField = Backbone.View.extend( { this.model.set( 'value', $el.val() ); } + this.triggerCallbacks(); + }, + + triggerCallbacks: function() { + var shortcodeName = this.shortcode.attributes.shortcode_tag, attributeName = this.model.get( 'attr' ), hookName = [ shortcodeName, attributeName ].join( '.' ), diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index 42f9b410..a34858bd 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -680,6 +680,11 @@ var editAttributeField = Backbone.View.extend( { this.model.set( 'value', $el.val() ); } + this.triggerCallbacks(); + }, + + triggerCallbacks: function() { + var shortcodeName = this.shortcode.attributes.shortcode_tag, attributeName = this.model.get( 'attr' ), hookName = [ shortcodeName, attributeName ].join( '.' ), diff --git a/js/src/field-attachment.js b/js/src/field-attachment.js index 46b0e02d..cea8b31c 100644 --- a/js/src/field-attachment.js +++ b/js/src/field-attachment.js @@ -46,12 +46,15 @@ sui.views.editAttributeFieldAttachment = editAttributeField.extend( { self.$container.removeClass( 'loading' ); } ); + // Call the updateValue() function, to trigger any listeners + // hooked on it. + this.triggerCallbacks(); }, render: function() { // Set model default values. - for ( var arg in ShortcakeImageFieldData.defaultArgs ) { +for ( var arg in ShortcakeImageFieldData.defaultArgs ) { if ( ! this.model.get( arg ) ) { this.model.set( arg, ShortcakeImageFieldData.defaultArgs[ arg ] ); } diff --git a/js/src/views/edit-attribute-field.js b/js/src/views/edit-attribute-field.js index a1fb86a4..a5f7f7e3 100644 --- a/js/src/views/edit-attribute-field.js +++ b/js/src/views/edit-attribute-field.js @@ -75,6 +75,11 @@ var editAttributeField = Backbone.View.extend( { this.model.set( 'value', $el.val() ); } + this.triggerCallbacks(); + }, + + triggerCallbacks: function() { + var shortcodeName = this.shortcode.attributes.shortcode_tag, attributeName = this.model.get( 'attr' ), hookName = [ shortcodeName, attributeName ].join( '.' ), From 84b0ef416eba8dcfbca337e4098ad39e5ff1e4ce Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor Date: Wed, 10 Jun 2015 07:28:38 -0700 Subject: [PATCH 03/12] Remove duplicate toggleClass call. --- js/src/field-attachment.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/src/field-attachment.js b/js/src/field-attachment.js index cea8b31c..4a7f005c 100644 --- a/js/src/field-attachment.js +++ b/js/src/field-attachment.js @@ -156,7 +156,6 @@ for ( var arg in ShortcakeImageFieldData.defaultArgs ) { this.model.set( 'value', null ); - this.$container.toggleClass( 'has-attachment', false ); this.$container.toggleClass( 'has-attachment', false ); this.$container.find( '.thumbnail' ).remove(); } From 82fe715e929c270aebdb578640a3982253740001 Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor Date: Wed, 10 Jun 2015 08:20:32 -0700 Subject: [PATCH 04/12] Un-browserify the attachment field view I can't see any reason to build in an extra 10K of scripts into this file which are already being included elsewhere on the page just for the purpose of encapsulation. I tried to remove all the browserify dependencies and set this field up as a model for how plugin users could register their own fields in a more typical Backbone view structure. I like it a lot better. I am exposing one additional global, the `iDCache` variable, and that's somewhat intentional - I'd like for filters on updating attachment to have access to that data to avoid having to make additional ajax calls to look it up. The variable name and the way in which it's exposed is pretty ugly though, and I think it would do better as a public method on the view... Also, browserify is still processing this file, I'm just loading the version from `src` rather than the browserified `build` file. It would be good to come up with an organizational structure that made more sense for these view files. --- inc/fields/class-field-attachment.php | 2 +- js/build/field-attachment.js | 329 ++------------------------ js/src/field-attachment.js | 38 +-- 3 files changed, 41 insertions(+), 328 deletions(-) diff --git a/inc/fields/class-field-attachment.php b/inc/fields/class-field-attachment.php index e405c381..8b8a2f76 100644 --- a/inc/fields/class-field-attachment.php +++ b/inc/fields/class-field-attachment.php @@ -37,7 +37,7 @@ public function filter_shortcode_ui_fields( $fields ) { public function action_enqueue_shortcode_ui() { - $script = plugins_url( 'js/build/field-attachment.js', dirname( dirname( __FILE__ ) ) ); + $script = plugins_url( 'js/src/field-attachment.js', dirname( dirname( __FILE__ ) ) ); wp_enqueue_script( 'shortcake-field-attachment', $script, array( 'shortcode-ui' ) ); diff --git a/js/build/field-attachment.js b/js/build/field-attachment.js index 8f3d8487..04a94ba4 100644 --- a/js/build/field-attachment.js +++ b/js/build/field-attachment.js @@ -1,47 +1,7 @@ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o
'); + var $thumbnail = jQuery('
'); if ( 'image' !== attachment.type ) { - $( '', { + jQuery( '', { src: attachment.icon, alt: attachment.title, } ).appendTo( $thumbnail ); - $( '
', { + jQuery( '
', { class: 'filename', html: '
' + attachment.title + '
', } ).appendTo( $thumbnail ); @@ -141,7 +101,7 @@ for ( var arg in ShortcakeImageFieldData.defaultArgs ) { attachment.sizes.thumbnail : _.first( _.sortBy( attachment.sizes, 'width' ) ); - $( '', { + jQuery( '', { src: attachmentThumb.url, width: attachmentThumb.width, height: attachmentThumb.height, @@ -192,282 +152,25 @@ for ( var arg in ShortcakeImageFieldData.defaultArgs ) { this.model.set( 'value', null ); - this.$container.toggleClass( 'has-attachment', false ); this.$container.toggleClass( 'has-attachment', false ); this.$container.find( '.thumbnail' ).remove(); - } -} ); - - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./utils/sui.js":7,"./views/edit-attribute-field.js":8}],4:[function(require,module,exports){ -(function (global){ -var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null); - -/** - * Shortcode Attribute Model. - */ -var InnerContent = Backbone.Model.extend({ - defaults : { - label: shortcodeUIData.strings.insert_content_label, - type: 'textarea', - value: '', - placeholder: '', - }, -}); - -module.exports = InnerContent; - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],5:[function(require,module,exports){ -(function (global){ -var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null); - -var ShortcodeAttribute = Backbone.Model.extend({ - defaults: { - attr: '', - label: '', - type: '', - value: '', - description: '', - meta: { - placeholder: '', - }, - }, -}); - -module.exports = ShortcodeAttribute; - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],6:[function(require,module,exports){ -(function (global){ -var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null); -var ShortcodeAttributes = require('./../collections/shortcode-attributes.js'); -var InnerContent = require('./inner-content.js'); - -Shortcode = Backbone.Model.extend({ - - defaults: { - label: '', - shortcode_tag: '', - attrs: new ShortcodeAttributes, - }, - - /** - * Custom set method. - * Handles setting the attribute collection. - */ - set: function( attributes, options ) { - - if ( attributes.attrs !== undefined && ! ( attributes.attrs instanceof ShortcodeAttributes ) ) { - attributes.attrs = new ShortcodeAttributes( attributes.attrs ); - } - - if ( attributes.inner_content && ! ( attributes.inner_content instanceof InnerContent ) ) { - attributes.inner_content = new InnerContent( attributes.inner_content ); - } - - return Backbone.Model.prototype.set.call(this, attributes, options); - }, - - /** - * Custom toJSON. - * Handles converting the attribute collection to JSON. - */ - toJSON: function( options ) { - options = Backbone.Model.prototype.toJSON.call(this, options); - if ( options.attrs && ( options.attrs instanceof ShortcodeAttributes ) ) { - options.attrs = options.attrs.toJSON(); - } - if ( options.inner_content && ( options.inner_content instanceof InnerContent ) ) { - options.inner_content = options.inner_content.toJSON(); - } - return options; - }, - - /** - * Custom clone - * Make sure we don't clone a reference to attributes. - */ - clone: function() { - var clone = Backbone.Model.prototype.clone.call( this ); - clone.set( 'attrs', clone.get( 'attrs' ).clone() ); - if ( clone.get( 'inner_content' ) ) { - clone.set( 'inner_content', clone.get( 'inner_content' ).clone() ); - } - return clone; - }, - - /** - * Get the shortcode as... a shortcode! - * - * @return string eg [shortcode attr1=value] - */ - formatShortcode: function() { - - var template, shortcodeAttributes, attrs = [], content, self = this; - - this.get( 'attrs' ).each( function( attr ) { - - // Skip empty attributes. - if ( ! attr.get( 'value' ) || attr.get( 'value' ).length < 1 ) { - return; - } - - attrs.push( attr.get( 'attr' ) + '="' + attr.get( 'value' ) + '"' ); - - } ); - - if ( this.get( 'inner_content' ) ) { - content = this.get( 'inner_content' ).get( 'value' ); - } - - if ( attrs.length > 0 ) { - template = "[{{ shortcode }} {{ attributes }}]" - } else { - template = "[{{ shortcode }}]" - } - - if ( content && content.length > 0 ) { - template += "{{ content }}[/{{ shortcode }}]" - } - - template = template.replace( /{{ shortcode }}/g, this.get('shortcode_tag') ); - template = template.replace( /{{ attributes }}/g, attrs.join( ' ' ) ); - template = template.replace( /{{ content }}/g, content ); - - return template; - - } - -}); - -module.exports = Shortcode; - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../collections/shortcode-attributes.js":1,"./inner-content.js":4}],7:[function(require,module,exports){ -var Shortcodes = require('./../collections/shortcodes.js'); - -window.Shortcode_UI = window.Shortcode_UI || { - shortcodes: new Shortcodes, - views: {}, - controllers: {}, -}; - -module.exports = window.Shortcode_UI; - -},{"./../collections/shortcodes.js":2}],8:[function(require,module,exports){ -(function (global){ -var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null), - sui = require('./../utils/sui.js'), - $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null); - -var editAttributeField = Backbone.View.extend( { - - tagName: "div", - - events: { - 'keyup input[type="text"]': 'updateValue', - 'keyup textarea': 'updateValue', - 'change select': 'updateValue', - 'change input[type=checkbox]': 'updateValue', - 'change input[type=radio]': 'updateValue', - 'change input[type=email]': 'updateValue', - 'change input[type=number]': 'updateValue', - 'change input[type=date]': 'updateValue', - 'change input[type=url]': 'updateValue', }, - render: function() { - - var data = jQuery.extend( { - id: 'shortcode-ui-' + this.model.get( 'attr' ) + '-' + this.model.cid, - }, this.model.toJSON() ); - - // Convert meta JSON to attribute string. - var _meta = []; - for ( var key in data.meta ) { - - // Boolean attributes can only require attribute key, not value. - if ( 'boolean' === typeof( data.meta[ key ] ) ) { - - // Only set truthy boolean attributes. - if ( data.meta[ key ] ) { - _meta.push( _.escape( key ) ); - } - - } else { - - _meta.push( _.escape( key ) + '="' + _.escape( data.meta[ key ] ) + '"' ); - - } - - } - - data.meta = _meta.join( ' ' ); - - this.$el.html( this.template( data ) ); - this.updateValue(); - - return this - }, /** - * Input Changed Update Callback. - * - * If the input field that has changed is for content or a valid attribute, - * then it should update the model. If a callback function is registered - * for this attribute, it should be called as well. + * Store attachments in a cache for quicker loading. */ - updateValue: function( e ) { - - if ( this.model.get( 'attr' ) ) { - var $el = $( this.el ).find( '[name=' + this.model.get( 'attr' ) + ']' ); - } else { - var $el = $( this.el ).find( '[name="inner_content"]' ); - } - - if ( 'radio' === this.model.attributes.type ) { - this.model.set( 'value', $el.filter(':checked').first().val() ); - } else if ( 'checkbox' === this.model.attributes.type ) { - this.model.set( 'value', $el.is( ':checked' ) ); - } else { - this.model.set( 'value', $el.val() ); + _getFromCache: function( id ){ + if ( 'undefined' === typeof iDCache[ id ] ) { + return false; } - - this.triggerCallbacks(); + return iDCache[ id ]; }, - triggerCallbacks: function() { - - var shortcodeName = this.shortcode.attributes.shortcode_tag, - attributeName = this.model.get( 'attr' ), - hookName = [ shortcodeName, attributeName ].join( '.' ), - changed = this.model.changed, - collection = _.flatten( _.values( this.views.parent.views._views ) ), - shortcode = this.shortcode; - - /* - * Action run when an attribute value changes on a shortcode - * - * Called as `{shortcodeName}.{attributeName}`. - * - * @param changed (object) - * The update, ie. { "changed": "newValue" } - * @param viewModels (array) - * The collections of views (editAttributeFields) - * which make up this shortcode UI form - * @param shortcode (object) - * Reference to the shortcode model which this attribute belongs to. - */ - wp.shortcake.hooks.doAction( hookName, changed, collection, shortcode ); - + _setInCache: function( id, attachment ) { + iDCache[ id ] = attachment; } } ); -sui.views.editAttributeField = editAttributeField; -module.exports = editAttributeField; - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../utils/sui.js":7}]},{},[3]); +},{}]},{},[1]); diff --git a/js/src/field-attachment.js b/js/src/field-attachment.js index 4a7f005c..333a4ecd 100644 --- a/js/src/field-attachment.js +++ b/js/src/field-attachment.js @@ -1,11 +1,6 @@ -var sui = require('sui-utils/sui'), - $ = require('jquery'), - editAttributeField = require( 'sui-views/edit-attribute-field' ); - -// Cache attachment IDs for quicker loading. var iDCache = {}; -sui.views.editAttributeFieldAttachment = editAttributeField.extend( { +sui.views.editAttributeFieldAttachment = sui.views.editAttributeField.extend( { events: { 'click .add' : '_openMediaFrame', @@ -30,7 +25,7 @@ sui.views.editAttributeFieldAttachment = editAttributeField.extend( { var self = this; - if ( iDCache[ id ] ) { + if ( this._getFromCache( id ) ) { self._renderPreview( iDCache[ id ] ); return; } @@ -41,7 +36,7 @@ sui.views.editAttributeFieldAttachment = editAttributeField.extend( { 'id': id } ).done( function( attachment ) { // Cache for later. - iDCache[ id ] = attachment; + self._setInCache( id, attachment ); self._renderPreview( attachment ); self.$container.removeClass( 'loading' ); } ); @@ -54,7 +49,7 @@ sui.views.editAttributeFieldAttachment = editAttributeField.extend( { render: function() { // Set model default values. -for ( var arg in ShortcakeImageFieldData.defaultArgs ) { + for ( var arg in ShortcakeImageFieldData.defaultArgs ) { if ( ! this.model.get( arg ) ) { this.model.set( arg, ShortcakeImageFieldData.defaultArgs[ arg ] ); } @@ -85,16 +80,16 @@ for ( var arg in ShortcakeImageFieldData.defaultArgs ) { */ _renderPreview: function( attachment ) { - var $thumbnail = $('
'); + var $thumbnail = jQuery('
'); if ( 'image' !== attachment.type ) { - $( '', { + jQuery( '', { src: attachment.icon, alt: attachment.title, } ).appendTo( $thumbnail ); - $( '
', { + jQuery( '
', { class: 'filename', html: '
' + attachment.title + '
', } ).appendTo( $thumbnail ); @@ -105,7 +100,7 @@ for ( var arg in ShortcakeImageFieldData.defaultArgs ) { attachment.sizes.thumbnail : _.first( _.sortBy( attachment.sizes, 'width' ) ); - $( '', { + jQuery( '', { src: attachmentThumb.url, width: attachmentThumb.width, height: attachmentThumb.height, @@ -158,6 +153,21 @@ for ( var arg in ShortcakeImageFieldData.defaultArgs ) { this.$container.toggleClass( 'has-attachment', false ); this.$container.find( '.thumbnail' ).remove(); + }, + + + /** + * Store attachments in a cache for quicker loading. + */ + _getFromCache: function( id ){ + if ( 'undefined' === typeof iDCache[ id ] ) { + return false; + } + return iDCache[ id ]; + }, + + _setInCache: function( id, attachment ) { + iDCache[ id ] = attachment; } -} ); +} ); From 300e1186358988b5f2ae5d9732b242e8e509cd01 Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor Date: Sun, 28 Jun 2015 18:48:55 -0600 Subject: [PATCH 05/12] Move editAttributeField into main browserified bundle Following @jitendraharpalani's comments, it makes sense for this to be bundled into the main plugin js file and avoid the extra unnecessary HTTP request. It's still architected basically as a standalone view, which I think is a good thing. If we keep the pattern used for composing views fairly standard and standalone, it will be easier to give examples for extending these views. Everything needed to extend a view should already be accessible through extending the `sui.views.editAttributeField` field. --- inc/fields/class-field-attachment.php | 6 +- js/build/shortcode-ui.js | 224 +++++++++++++++++- js/src/field-attachment.js | 173 -------------- .../views/edit-attribute-field-attachment.js} | 31 ++- js/src/views/edit-shortcode-form.js | 11 +- 5 files changed, 243 insertions(+), 202 deletions(-) delete mode 100644 js/src/field-attachment.js rename js/{build/field-attachment.js => src/views/edit-attribute-field-attachment.js} (82%) diff --git a/inc/fields/class-field-attachment.php b/inc/fields/class-field-attachment.php index 8b8a2f76..ed4b3a6a 100644 --- a/inc/fields/class-field-attachment.php +++ b/inc/fields/class-field-attachment.php @@ -37,11 +37,7 @@ public function filter_shortcode_ui_fields( $fields ) { public function action_enqueue_shortcode_ui() { - $script = plugins_url( 'js/src/field-attachment.js', dirname( dirname( __FILE__ ) ) ); - - wp_enqueue_script( 'shortcake-field-attachment', $script, array( 'shortcode-ui' ) ); - - wp_localize_script( 'shortcake-field-attachment', 'ShortcakeImageFieldData', array( + wp_localize_script( 'shortcode-ui', 'ShortcakeImageFieldData', array( 'defaultArgs' => array( 'libraryType' => null, // array of mime types. eg image, image/jpg, application, application/pdf. 'addButton' => __( 'Select Attachment', 'shortcode-ui' ), diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index a34858bd..e5ba8230 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -264,7 +264,7 @@ $(document).ready(function(){ }); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./collections/shortcodes.js":2,"./utils/shortcode-view-constructor.js":8,"./utils/sui.js":9,"./views/media-frame.js":14}],8:[function(require,module,exports){ +},{"./collections/shortcodes.js":2,"./utils/shortcode-view-constructor.js":8,"./utils/sui.js":9,"./views/media-frame.js":15}],8:[function(require,module,exports){ (function (global){ var sui = require('./sui.js'), wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null), @@ -602,6 +602,199 @@ window.Shortcode_UI = window.Shortcode_UI || { module.exports = window.Shortcode_UI; },{"./../collections/shortcodes.js":2}],10:[function(require,module,exports){ +var sui = require('./../utils/sui.js'); + +var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { + + events: { + 'click .add' : '_openMediaFrame', + 'click .remove' : '_removeAttachment', + 'selectAttachment' : '_selectAttachment', + }, + + /** + * Update the field attachment. + * Re-renders UI. + * If ID is empty - does nothing. + * + * @param {int} id Attachment ID + */ + updateValue: function( id ) { + + if ( ! id ) { + return; + } + + this.model.set( 'value', id ); + + var self = this; + + if ( this._getFromCache( id ) ) { + self._renderPreview( this._getFromCache( id ) ); + return; + } + + this.$container.addClass( 'loading' ); + + wp.ajax.post( 'get-attachment', { + 'id': id + } ).done( function( attachment ) { + // Cache for later. + self._setInCache( id, attachment ); + self._renderPreview( attachment ); + self.$container.removeClass( 'loading' ); + } ); + + // Call the updateValue() function, to trigger any listeners + // hooked on it. + this.triggerCallbacks(); + }, + + render: function() { + + // Set model default values. + for ( var arg in ShortcakeImageFieldData.defaultArgs ) { + if ( ! this.model.get( arg ) ) { + this.model.set( arg, ShortcakeImageFieldData.defaultArgs[ arg ] ); + } + } + + this.$el.html( this.template( this.model.toJSON() ) ); + + this.$container = this.$el.find( '.shortcake-attachment-preview' ); + var $addButton = this.$container.find( 'button.add' ); + + this.frame = wp.media( { + multiple: false, + title: this.model.get( 'frameTitle' ), + library: { + type: this.model.get( 'libraryType' ), + }, + } ); + + // Add initial Attachment if available. + this.updateValue( this.model.get( 'value' ) ); + + }, + + /** + * Renders attachment preview in field. + * @param {object} attachment model + * @return null + */ + _renderPreview: function( attachment ) { + + var $thumbnail = jQuery('
'); + + if ( 'image' !== attachment.type ) { + + jQuery( '', { + src: attachment.icon, + alt: attachment.title, + } ).appendTo( $thumbnail ); + + jQuery( '
', { + class: 'filename', + html: '
' + attachment.title + '
', + } ).appendTo( $thumbnail ); + + } else { + + attachmentThumb = (typeof attachment.sizes.thumbnail !== 'undefined') ? + attachment.sizes.thumbnail : + _.first( _.sortBy( attachment.sizes, 'width' ) ); + + jQuery( '', { + src: attachmentThumb.url, + width: attachmentThumb.width, + height: attachmentThumb.height, + alt: attachment.alt, + } ) .appendTo( $thumbnail ) + + } + + $thumbnail.find( 'img' ).wrap( '
' ); + this.$container.append( $thumbnail ); + this.$container.toggleClass( 'has-attachment', true ); + + }, + + /** + * Open media frame when add button is clicked. + * + */ + _openMediaFrame: function(e) { + e.preventDefault(); + this.frame.open(); + + var self = this; + this.frame.on( 'select', function() { + self.$el.trigger( 'selectAttachment' ); + } ); + + }, + + /** + * When an attachment is selected from the media frame, update the model value. + * + */ + _selectAttachment: function(e) { + var selection = this.frame.state().get('selection'); + attachment = selection.first(); + + this.updateValue( attachment.id ); + this.frame.close(); + }, + + /** + * Remove the attachment. + * Render preview & Update the model. + */ + _removeAttachment: function(e) { + e.preventDefault(); + + this.model.set( 'value', null ); + + this.$container.toggleClass( 'has-attachment', false ); + this.$container.find( '.thumbnail' ).remove(); + }, + + + /** + * Store attachments in a cache for quicker loading. + */ + _getFromCache: function( id ){ + this._prepCache(); + if ( 'undefined' === typeof window.sui.data.idCache[ id ] ) { + return false; + } + return window.sui.data.idCache[ id ]; + }, + + _setInCache: function( id, attachment ) { + this._prepCache(); + window.sui.data.idCache[ id ] = attachment; + }, + + + /** + * Expose a global for the attachement cache. + * + * This is useful in that plugins which hook into this field's events can + * grab data from it. + */ + _prepCache: function() { + window.sui = window.sui || {}; + window.sui.data = window.sui.data || {}; + window.sui.data.idCache = window.sui.data.idCache || {}; + } + +} ); + +module.exports = sui.views.editAttributeFieldAttachment = editAttributeFieldAttachment; + + +},{"./../utils/sui.js":9}],11:[function(require,module,exports){ (function (global){ var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null), sui = require('./../utils/sui.js'), @@ -715,12 +908,17 @@ sui.views.editAttributeField = editAttributeField; module.exports = editAttributeField; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../utils/sui.js":9}],11:[function(require,module,exports){ +},{"./../utils/sui.js":9}],12:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null), -sui = require('./../utils/sui.js'), -backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null), -editAttributeField = require('./edit-attribute-field.js'); + sui = require('./../utils/sui.js'), + backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null), + editAttributeField = require('./edit-attribute-field.js'), + + // Additional attribute field types: these fields are all standalone in functionality, + // but bundled here for simplicity to save an HTTP request. + editAttributeFieldAttachment = require('./edit-attribute-field-attachment.js'); + /** * Single edit shortcode content view. @@ -792,7 +990,7 @@ var EditShortcodeForm = wp.Backbone.View.extend({ module.exports = EditShortcodeForm; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../utils/sui.js":9,"./edit-attribute-field.js":10}],12:[function(require,module,exports){ +},{"./../utils/sui.js":9,"./edit-attribute-field-attachment.js":10,"./edit-attribute-field.js":11}],13:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null); @@ -826,7 +1024,7 @@ var insertShortcodeListItem = wp.Backbone.View.extend({ module.exports = insertShortcodeListItem; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],13:[function(require,module,exports){ +},{}],14:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null); var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null); @@ -872,7 +1070,7 @@ var insertShortcodeList = wp.Backbone.View.extend({ module.exports = insertShortcodeList; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../collections/shortcodes.js":2,"./insert-shortcode-list-item.js":12}],14:[function(require,module,exports){ +},{"./../collections/shortcodes.js":2,"./insert-shortcode-list-item.js":13}],15:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null), $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null), @@ -999,7 +1197,7 @@ var mediaFrame = postMediaFrame.extend( { module.exports = mediaFrame; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../controllers/media-controller.js":3,"./media-toolbar":15,"./shortcode-ui":18}],15:[function(require,module,exports){ +},{"./../controllers/media-controller.js":3,"./media-toolbar":16,"./shortcode-ui":19}],16:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null); @@ -1031,7 +1229,7 @@ var Toolbar = wp.media.view.Toolbar.extend({ module.exports = Toolbar; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],16:[function(require,module,exports){ +},{}],17:[function(require,module,exports){ (function (global){ var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null); sui = require('./../utils/sui.js'); @@ -1078,7 +1276,7 @@ var SearchShortcode = wp.media.view.Search.extend({ sui.views.SearchShortcode = SearchShortcode; module.exports = SearchShortcode; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../utils/sui.js":9}],17:[function(require,module,exports){ +},{"./../utils/sui.js":9}],18:[function(require,module,exports){ (function (global){ var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null), $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null); @@ -1266,7 +1464,7 @@ var ShortcodePreview = Backbone.View.extend({ module.exports = ShortcodePreview; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],18:[function(require,module,exports){ +},{}],19:[function(require,module,exports){ (function (global){ var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null), insertShortcodeList = require('./insert-shortcode-list.js'), @@ -1394,7 +1592,7 @@ var Shortcode_UI = Backbone.View.extend({ module.exports = Shortcode_UI; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./../utils/sui.js":9,"./edit-shortcode-form.js":11,"./insert-shortcode-list.js":13,"./media-toolbar.js":15,"./search-shortcode.js":16,"./shortcode-preview.js":17,"./tabbed-view.js":19}],19:[function(require,module,exports){ +},{"./../utils/sui.js":9,"./edit-shortcode-form.js":12,"./insert-shortcode-list.js":14,"./media-toolbar.js":16,"./search-shortcode.js":17,"./shortcode-preview.js":18,"./tabbed-view.js":20}],20:[function(require,module,exports){ (function (global){ var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null); var sui = require('./../utils/sui.js'); diff --git a/js/src/field-attachment.js b/js/src/field-attachment.js deleted file mode 100644 index 333a4ecd..00000000 --- a/js/src/field-attachment.js +++ /dev/null @@ -1,173 +0,0 @@ -var iDCache = {}; - -sui.views.editAttributeFieldAttachment = sui.views.editAttributeField.extend( { - - events: { - 'click .add' : '_openMediaFrame', - 'click .remove' : '_removeAttachment', - 'selectAttachment' : '_selectAttachment', - }, - - /** - * Update the field attachment. - * Re-renders UI. - * If ID is empty - does nothing. - * - * @param {int} id Attachment ID - */ - updateValue: function( id ) { - - if ( ! id ) { - return; - } - - this.model.set( 'value', id ); - - var self = this; - - if ( this._getFromCache( id ) ) { - self._renderPreview( iDCache[ id ] ); - return; - } - - this.$container.addClass( 'loading' ); - - wp.ajax.post( 'get-attachment', { - 'id': id - } ).done( function( attachment ) { - // Cache for later. - self._setInCache( id, attachment ); - self._renderPreview( attachment ); - self.$container.removeClass( 'loading' ); - } ); - - // Call the updateValue() function, to trigger any listeners - // hooked on it. - this.triggerCallbacks(); - }, - - render: function() { - - // Set model default values. - for ( var arg in ShortcakeImageFieldData.defaultArgs ) { - if ( ! this.model.get( arg ) ) { - this.model.set( arg, ShortcakeImageFieldData.defaultArgs[ arg ] ); - } - } - - this.$el.html( this.template( this.model.toJSON() ) ); - - this.$container = this.$el.find( '.shortcake-attachment-preview' ); - var $addButton = this.$container.find( 'button.add' ); - - this.frame = wp.media( { - multiple: false, - title: this.model.get( 'frameTitle' ), - library: { - type: this.model.get( 'libraryType' ), - }, - } ); - - // Add initial Attachment if available. - this.updateValue( this.model.get( 'value' ) ); - - }, - - /** - * Renders attachment preview in field. - * @param {object} attachment model - * @return null - */ - _renderPreview: function( attachment ) { - - var $thumbnail = jQuery('
'); - - if ( 'image' !== attachment.type ) { - - jQuery( '', { - src: attachment.icon, - alt: attachment.title, - } ).appendTo( $thumbnail ); - - jQuery( '
', { - class: 'filename', - html: '
' + attachment.title + '
', - } ).appendTo( $thumbnail ); - - } else { - - attachmentThumb = (typeof attachment.sizes.thumbnail !== 'undefined') ? - attachment.sizes.thumbnail : - _.first( _.sortBy( attachment.sizes, 'width' ) ); - - jQuery( '', { - src: attachmentThumb.url, - width: attachmentThumb.width, - height: attachmentThumb.height, - alt: attachment.alt, - } ) .appendTo( $thumbnail ) - - } - - $thumbnail.find( 'img' ).wrap( '
' ); - this.$container.append( $thumbnail ); - this.$container.toggleClass( 'has-attachment', true ); - - }, - - /** - * Open media frame when add button is clicked. - * - */ - _openMediaFrame: function(e) { - e.preventDefault(); - this.frame.open(); - - var self = this; - this.frame.on( 'select', function() { - self.$el.trigger( 'selectAttachment' ); - } ); - - }, - - /** - * When an attachment is selected from the media frame, update the model value. - * - */ - _selectAttachment: function(e) { - var selection = this.frame.state().get('selection'); - attachment = selection.first(); - - this.updateValue( attachment.id ); - this.frame.close(); - }, - - /** - * Remove the attachment. - * Render preview & Update the model. - */ - _removeAttachment: function(e) { - e.preventDefault(); - - this.model.set( 'value', null ); - - this.$container.toggleClass( 'has-attachment', false ); - this.$container.find( '.thumbnail' ).remove(); - }, - - - /** - * Store attachments in a cache for quicker loading. - */ - _getFromCache: function( id ){ - if ( 'undefined' === typeof iDCache[ id ] ) { - return false; - } - return iDCache[ id ]; - }, - - _setInCache: function( id, attachment ) { - iDCache[ id ] = attachment; - } - -} ); diff --git a/js/build/field-attachment.js b/js/src/views/edit-attribute-field-attachment.js similarity index 82% rename from js/build/field-attachment.js rename to js/src/views/edit-attribute-field-attachment.js index 04a94ba4..00910515 100644 --- a/js/build/field-attachment.js +++ b/js/src/views/edit-attribute-field-attachment.js @@ -1,7 +1,6 @@ -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o Date: Sun, 28 Jun 2015 19:46:02 -0600 Subject: [PATCH 06/12] Wait to load attachment before triggering update event Knowing that a field has updated seems less useful than actually retrieving the information from that field. This moves the event trigger into the ajax callback, so that it doesn't trigger until all of the attachment data has been retrieved. --- js/build/shortcode-ui.js | 12 ++++++++---- js/src/views/edit-attribute-field-attachment.js | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index e5ba8230..845eafd2 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -632,6 +632,10 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { if ( this._getFromCache( id ) ) { self._renderPreview( this._getFromCache( id ) ); return; + + // Call the updateValue() function, to trigger any listeners + // hooked on it. + this.triggerCallbacks(); } this.$container.addClass( 'loading' ); @@ -643,11 +647,11 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { self._setInCache( id, attachment ); self._renderPreview( attachment ); self.$container.removeClass( 'loading' ); - } ); - // Call the updateValue() function, to trigger any listeners - // hooked on it. - this.triggerCallbacks(); + // Call the updateValue() function, to trigger any listeners + // hooked on it. + this.triggerCallbacks(); + } ); }, render: function() { diff --git a/js/src/views/edit-attribute-field-attachment.js b/js/src/views/edit-attribute-field-attachment.js index 00910515..87cd089b 100644 --- a/js/src/views/edit-attribute-field-attachment.js +++ b/js/src/views/edit-attribute-field-attachment.js @@ -28,6 +28,10 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { if ( this._getFromCache( id ) ) { self._renderPreview( this._getFromCache( id ) ); return; + + // Call the updateValue() function, to trigger any listeners + // hooked on it. + this.triggerCallbacks(); } this.$container.addClass( 'loading' ); @@ -39,11 +43,11 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { self._setInCache( id, attachment ); self._renderPreview( attachment ); self.$container.removeClass( 'loading' ); - } ); - // Call the updateValue() function, to trigger any listeners - // hooked on it. - this.triggerCallbacks(); + // Call the updateValue() function, to trigger any listeners + // hooked on it. + this.triggerCallbacks(); + } ); }, render: function() { From 0aab4372002cf40fd3770438bd4b2dc6bb0edbac Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor Date: Mon, 29 Jun 2015 07:06:45 -0600 Subject: [PATCH 07/12] No longer build attachment field separately We're no longer loading it separately, so it doesn't need to be browserified separately. --- Gruntfile.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index c3d1581b..6a0beefa 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -93,7 +93,6 @@ module.exports = function( grunt ) { dist: { files : { 'js/build/shortcode-ui.js' : ['js/src/shortcode-ui.js'], - 'js/build/field-attachment.js' : ['js/src/field-attachment.js'], 'js/build/field-color.js' : ['js/src/field-color.js'], 'js/build/field-post-select.js' : ['js/src/field-post-select.js'], }, From 57ae7bf010ca847baede46874278986ba8c87981 Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor Date: Mon, 29 Jun 2015 07:07:18 -0600 Subject: [PATCH 08/12] var self was this, not that --- js/build/shortcode-ui.js | 4 ++-- js/src/views/edit-attribute-field-attachment.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index 845eafd2..77a77227 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -635,7 +635,7 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { // Call the updateValue() function, to trigger any listeners // hooked on it. - this.triggerCallbacks(); + self.triggerCallbacks(); } this.$container.addClass( 'loading' ); @@ -650,7 +650,7 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { // Call the updateValue() function, to trigger any listeners // hooked on it. - this.triggerCallbacks(); + self.triggerCallbacks(); } ); }, diff --git a/js/src/views/edit-attribute-field-attachment.js b/js/src/views/edit-attribute-field-attachment.js index 87cd089b..eeb3fe66 100644 --- a/js/src/views/edit-attribute-field-attachment.js +++ b/js/src/views/edit-attribute-field-attachment.js @@ -31,7 +31,7 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { // Call the updateValue() function, to trigger any listeners // hooked on it. - this.triggerCallbacks(); + self.triggerCallbacks(); } this.$container.addClass( 'loading' ); @@ -46,7 +46,7 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { // Call the updateValue() function, to trigger any listeners // hooked on it. - this.triggerCallbacks(); + self.triggerCallbacks(); } ); }, From d631032f387702c77d8df930a59f9799137b5be9 Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor Date: Mon, 29 Jun 2015 07:35:26 -0600 Subject: [PATCH 09/12] Use a class method for attachment cache object Setting the cache as a cache method and defining getter/setter helper functions for it makes it possible to get around using the sui.data fudge that I was using before. --- js/build/shortcode-ui.js | 39 +++++++------------ .../views/edit-attribute-field-attachment.js | 39 +++++++------------ 2 files changed, 30 insertions(+), 48 deletions(-) diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index 77a77227..54fe6a33 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -629,7 +629,7 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { var self = this; - if ( this._getFromCache( id ) ) { + if ( editAttributeFieldAttachment.getFromCache( id ) ) { self._renderPreview( this._getFromCache( id ) ); return; @@ -644,7 +644,7 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { 'id': id } ).done( function( attachment ) { // Cache for later. - self._setInCache( id, attachment ); + editAttributeFieldAttachment.setInCache( id, attachment ); self._renderPreview( attachment ); self.$container.removeClass( 'loading' ); @@ -763,37 +763,28 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { this.$container.find( '.thumbnail' ).remove(); }, +}, { + + _idCache: {}, /** * Store attachments in a cache for quicker loading. */ - _getFromCache: function( id ){ - this._prepCache(); - if ( 'undefined' === typeof window.sui.data.idCache[ id ] ) { - return false; - } - return window.sui.data.idCache[ id ]; + setInCache: function( id, attachment ) { + this._idCache[ id ] = attachment; }, - _setInCache: function( id, attachment ) { - this._prepCache(); - window.sui.data.idCache[ id ] = attachment; - }, - - /** - * Expose a global for the attachement cache. - * - * This is useful in that plugins which hook into this field's events can - * grab data from it. + * Retrieve an attachment from the cache. */ - _prepCache: function() { - window.sui = window.sui || {}; - window.sui.data = window.sui.data || {}; - window.sui.data.idCache = window.sui.data.idCache || {}; - } + getFromCache: function( id ){ + if ( 'undefined' === typeof this._idCache[ id ] ) { + return false; + } + return this._idCache[ id ]; + }, -} ); +}); module.exports = sui.views.editAttributeFieldAttachment = editAttributeFieldAttachment; diff --git a/js/src/views/edit-attribute-field-attachment.js b/js/src/views/edit-attribute-field-attachment.js index eeb3fe66..76fda911 100644 --- a/js/src/views/edit-attribute-field-attachment.js +++ b/js/src/views/edit-attribute-field-attachment.js @@ -25,7 +25,7 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { var self = this; - if ( this._getFromCache( id ) ) { + if ( editAttributeFieldAttachment.getFromCache( id ) ) { self._renderPreview( this._getFromCache( id ) ); return; @@ -40,7 +40,7 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { 'id': id } ).done( function( attachment ) { // Cache for later. - self._setInCache( id, attachment ); + editAttributeFieldAttachment.setInCache( id, attachment ); self._renderPreview( attachment ); self.$container.removeClass( 'loading' ); @@ -159,37 +159,28 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { this.$container.find( '.thumbnail' ).remove(); }, +}, { + + _idCache: {}, /** * Store attachments in a cache for quicker loading. */ - _getFromCache: function( id ){ - this._prepCache(); - if ( 'undefined' === typeof window.sui.data.idCache[ id ] ) { - return false; - } - return window.sui.data.idCache[ id ]; - }, - - _setInCache: function( id, attachment ) { - this._prepCache(); - window.sui.data.idCache[ id ] = attachment; + setInCache: function( id, attachment ) { + this._idCache[ id ] = attachment; }, - /** - * Expose a global for the attachement cache. - * - * This is useful in that plugins which hook into this field's events can - * grab data from it. + * Retrieve an attachment from the cache. */ - _prepCache: function() { - window.sui = window.sui || {}; - window.sui.data = window.sui.data || {}; - window.sui.data.idCache = window.sui.data.idCache || {}; - } + getFromCache: function( id ){ + if ( 'undefined' === typeof this._idCache[ id ] ) { + return false; + } + return this._idCache[ id ]; + }, -} ); +}); module.exports = sui.views.editAttributeFieldAttachment = editAttributeFieldAttachment; From 855d9a867d53ce11e4b60e318be8e40ef4f84d5e Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor Date: Tue, 30 Jun 2015 19:19:36 -0600 Subject: [PATCH 10/12] Add some sugar functions for working with callbacks Added getValue() and setValue() instance methods to editAttributeField, and a getField() class method for finding a field in a collection. --- js-tests/build/specs.js | 6 +- js/build/field-color.js | 66 ++++++++++++------ js/build/shortcode-ui.js | 68 +++++++++++++------ js/src/collections/shortcode-attributes.js | 3 +- js/src/models/shortcode.js | 3 +- .../views/edit-attribute-field-attachment.js | 2 +- js/src/views/edit-attribute-field.js | 60 +++++++++++----- 7 files changed, 143 insertions(+), 65 deletions(-) diff --git a/js-tests/build/specs.js b/js-tests/build/specs.js index d7f8f24c..11a40a67 100644 --- a/js-tests/build/specs.js +++ b/js-tests/build/specs.js @@ -320,7 +320,8 @@ var ShortcodeAttributes = Backbone.Collection.extend({ return new this.constructor(_.map(this.models, function(m) { return m.clone(); })); - } + }, + }); module.exports = ShortcodeAttributes; @@ -477,8 +478,7 @@ Shortcode = Backbone.Model.extend({ return template; - } - + }, }); module.exports = Shortcode; diff --git a/js/build/field-color.js b/js/build/field-color.js index 7e7b9c69..81c2081f 100644 --- a/js/build/field-color.js +++ b/js/build/field-color.js @@ -13,7 +13,8 @@ var ShortcodeAttributes = Backbone.Collection.extend({ return new this.constructor(_.map(this.models, function(m) { return m.clone(); })); - } + }, + }); module.exports = ShortcodeAttributes; @@ -193,8 +194,7 @@ Shortcode = Backbone.Model.extend({ return template; - } - + }, }); module.exports = Shortcode; @@ -222,15 +222,15 @@ var editAttributeField = Backbone.View.extend( { tagName: "div", events: { - 'keyup input[type="text"]': 'updateValue', - 'keyup textarea': 'updateValue', - 'change select': 'updateValue', - 'change input[type=checkbox]': 'updateValue', - 'change input[type=radio]': 'updateValue', - 'change input[type=email]': 'updateValue', - 'change input[type=number]': 'updateValue', - 'change input[type=date]': 'updateValue', - 'change input[type=url]': 'updateValue', + 'keyup input[type="text"]': 'inputChanged', + 'keyup textarea': 'inputChanged', + 'change select': 'inputChanged', + 'change input[type=checkbox]': 'inputChanged', + 'change input[type=radio]': 'inputChanged', + 'change input[type=email]': 'inputChanged', + 'change input[type=number]': 'inputChanged', + 'change input[type=date]': 'inputChanged', + 'change input[type=url]': 'inputChanged', }, render: function() { @@ -262,7 +262,7 @@ var editAttributeField = Backbone.View.extend( { data.meta = _meta.join( ' ' ); this.$el.html( this.template( data ) ); - this.updateValue(); + this.triggerCallbacks(); return this }, @@ -274,25 +274,33 @@ var editAttributeField = Backbone.View.extend( { * then it should update the model. If a callback function is registered * for this attribute, it should be called as well. */ - updateValue: function( e ) { + inputChanged: function( e ) { - if ( this.model.get( 'attr' ) ) { - var $el = $( this.el ).find( '[name=' + this.model.get( 'attr' ) + ']' ); + if ( this.getValue( 'attr' ) ) { + var $el = $( this.el ).find( '[name=' + this.getValue( 'attr' ) + ']' ); } else { var $el = $( this.el ).find( '[name="inner_content"]' ); } if ( 'radio' === this.model.attributes.type ) { - this.model.set( 'value', $el.filter(':checked').first().val() ); + this.setValue( 'value', $el.filter(':checked').first().val() ); } else if ( 'checkbox' === this.model.attributes.type ) { - this.model.set( 'value', $el.is( ':checked' ) ); + this.setValue( 'value', $el.is( ':checked' ) ); } else { - this.model.set( 'value', $el.val() ); + this.setValue( 'value', $el.val() ); } this.triggerCallbacks(); }, + getValue: function() { + return this.model.get( 'value' ); + }, + + setValue: function( val ) { + this.model.set( 'value', val ); + }, + triggerCallbacks: function() { var shortcodeName = this.shortcode.attributes.shortcode_tag, @@ -319,7 +327,25 @@ var editAttributeField = Backbone.View.extend( { } -} ); +}, { + + /** + * Get an attribute field from a shortcode by name. + * + * Usage: `sui.views.editAttributeField.getField( collection, 'title')` + * + * @param array collection of editAttributeFields + * @param string attribute name + * @return editAttributeField The view corresponding to the matching field + */ + getField: function( collection, attr ) { + return _.find( collection, + function( viewModel ) { + return attr === viewModel.model.get('attr'); + } + ); + } +}); sui.views.editAttributeField = editAttributeField; module.exports = editAttributeField; diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index 54fe6a33..40b21708 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -13,7 +13,8 @@ var ShortcodeAttributes = Backbone.Collection.extend({ return new this.constructor(_.map(this.models, function(m) { return m.clone(); })); - } + }, + }); module.exports = ShortcodeAttributes; @@ -226,8 +227,7 @@ Shortcode = Backbone.Model.extend({ return template; - } - + }, }); module.exports = Shortcode; @@ -625,7 +625,7 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { return; } - this.model.set( 'value', id ); + this.setValue( id ); var self = this; @@ -800,15 +800,15 @@ var editAttributeField = Backbone.View.extend( { tagName: "div", events: { - 'keyup input[type="text"]': 'updateValue', - 'keyup textarea': 'updateValue', - 'change select': 'updateValue', - 'change input[type=checkbox]': 'updateValue', - 'change input[type=radio]': 'updateValue', - 'change input[type=email]': 'updateValue', - 'change input[type=number]': 'updateValue', - 'change input[type=date]': 'updateValue', - 'change input[type=url]': 'updateValue', + 'keyup input[type="text"]': 'inputChanged', + 'keyup textarea': 'inputChanged', + 'change select': 'inputChanged', + 'change input[type=checkbox]': 'inputChanged', + 'change input[type=radio]': 'inputChanged', + 'change input[type=email]': 'inputChanged', + 'change input[type=number]': 'inputChanged', + 'change input[type=date]': 'inputChanged', + 'change input[type=url]': 'inputChanged', }, render: function() { @@ -840,7 +840,7 @@ var editAttributeField = Backbone.View.extend( { data.meta = _meta.join( ' ' ); this.$el.html( this.template( data ) ); - this.updateValue(); + this.triggerCallbacks(); return this }, @@ -852,25 +852,33 @@ var editAttributeField = Backbone.View.extend( { * then it should update the model. If a callback function is registered * for this attribute, it should be called as well. */ - updateValue: function( e ) { + inputChanged: function( e ) { - if ( this.model.get( 'attr' ) ) { - var $el = $( this.el ).find( '[name=' + this.model.get( 'attr' ) + ']' ); + if ( this.getValue( 'attr' ) ) { + var $el = $( this.el ).find( '[name=' + this.getValue( 'attr' ) + ']' ); } else { var $el = $( this.el ).find( '[name="inner_content"]' ); } if ( 'radio' === this.model.attributes.type ) { - this.model.set( 'value', $el.filter(':checked').first().val() ); + this.setValue( 'value', $el.filter(':checked').first().val() ); } else if ( 'checkbox' === this.model.attributes.type ) { - this.model.set( 'value', $el.is( ':checked' ) ); + this.setValue( 'value', $el.is( ':checked' ) ); } else { - this.model.set( 'value', $el.val() ); + this.setValue( 'value', $el.val() ); } this.triggerCallbacks(); }, + getValue: function() { + return this.model.get( 'value' ); + }, + + setValue: function( val ) { + this.model.set( 'value', val ); + }, + triggerCallbacks: function() { var shortcodeName = this.shortcode.attributes.shortcode_tag, @@ -897,7 +905,25 @@ var editAttributeField = Backbone.View.extend( { } -} ); +}, { + + /** + * Get an attribute field from a shortcode by name. + * + * Usage: `sui.views.editAttributeField.getField( collection, 'title')` + * + * @param array collection of editAttributeFields + * @param string attribute name + * @return editAttributeField The view corresponding to the matching field + */ + getField: function( collection, attr ) { + return _.find( collection, + function( viewModel ) { + return attr === viewModel.model.get('attr'); + } + ); + } +}); sui.views.editAttributeField = editAttributeField; module.exports = editAttributeField; diff --git a/js/src/collections/shortcode-attributes.js b/js/src/collections/shortcode-attributes.js index f8e68567..bd1f78e9 100644 --- a/js/src/collections/shortcode-attributes.js +++ b/js/src/collections/shortcode-attributes.js @@ -11,7 +11,8 @@ var ShortcodeAttributes = Backbone.Collection.extend({ return new this.constructor(_.map(this.models, function(m) { return m.clone(); })); - } + }, + }); module.exports = ShortcodeAttributes; diff --git a/js/src/models/shortcode.js b/js/src/models/shortcode.js index 52da7498..9a2f4a2b 100644 --- a/js/src/models/shortcode.js +++ b/js/src/models/shortcode.js @@ -95,8 +95,7 @@ Shortcode = Backbone.Model.extend({ return template; - } - + }, }); module.exports = Shortcode; diff --git a/js/src/views/edit-attribute-field-attachment.js b/js/src/views/edit-attribute-field-attachment.js index 76fda911..6a48e134 100644 --- a/js/src/views/edit-attribute-field-attachment.js +++ b/js/src/views/edit-attribute-field-attachment.js @@ -21,7 +21,7 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( { return; } - this.model.set( 'value', id ); + this.setValue( id ); var self = this; diff --git a/js/src/views/edit-attribute-field.js b/js/src/views/edit-attribute-field.js index a5f7f7e3..47719fa2 100644 --- a/js/src/views/edit-attribute-field.js +++ b/js/src/views/edit-attribute-field.js @@ -7,15 +7,15 @@ var editAttributeField = Backbone.View.extend( { tagName: "div", events: { - 'keyup input[type="text"]': 'updateValue', - 'keyup textarea': 'updateValue', - 'change select': 'updateValue', - 'change input[type=checkbox]': 'updateValue', - 'change input[type=radio]': 'updateValue', - 'change input[type=email]': 'updateValue', - 'change input[type=number]': 'updateValue', - 'change input[type=date]': 'updateValue', - 'change input[type=url]': 'updateValue', + 'keyup input[type="text"]': 'inputChanged', + 'keyup textarea': 'inputChanged', + 'change select': 'inputChanged', + 'change input[type=checkbox]': 'inputChanged', + 'change input[type=radio]': 'inputChanged', + 'change input[type=email]': 'inputChanged', + 'change input[type=number]': 'inputChanged', + 'change input[type=date]': 'inputChanged', + 'change input[type=url]': 'inputChanged', }, render: function() { @@ -47,7 +47,7 @@ var editAttributeField = Backbone.View.extend( { data.meta = _meta.join( ' ' ); this.$el.html( this.template( data ) ); - this.updateValue(); + this.triggerCallbacks(); return this }, @@ -59,25 +59,33 @@ var editAttributeField = Backbone.View.extend( { * then it should update the model. If a callback function is registered * for this attribute, it should be called as well. */ - updateValue: function( e ) { + inputChanged: function( e ) { - if ( this.model.get( 'attr' ) ) { - var $el = $( this.el ).find( '[name=' + this.model.get( 'attr' ) + ']' ); + if ( this.getValue( 'attr' ) ) { + var $el = $( this.el ).find( '[name=' + this.getValue( 'attr' ) + ']' ); } else { var $el = $( this.el ).find( '[name="inner_content"]' ); } if ( 'radio' === this.model.attributes.type ) { - this.model.set( 'value', $el.filter(':checked').first().val() ); + this.setValue( 'value', $el.filter(':checked').first().val() ); } else if ( 'checkbox' === this.model.attributes.type ) { - this.model.set( 'value', $el.is( ':checked' ) ); + this.setValue( 'value', $el.is( ':checked' ) ); } else { - this.model.set( 'value', $el.val() ); + this.setValue( 'value', $el.val() ); } this.triggerCallbacks(); }, + getValue: function() { + return this.model.get( 'value' ); + }, + + setValue: function( val ) { + this.model.set( 'value', val ); + }, + triggerCallbacks: function() { var shortcodeName = this.shortcode.attributes.shortcode_tag, @@ -104,7 +112,25 @@ var editAttributeField = Backbone.View.extend( { } -} ); +}, { + + /** + * Get an attribute field from a shortcode by name. + * + * Usage: `sui.views.editAttributeField.getField( collection, 'title')` + * + * @param array collection of editAttributeFields + * @param string attribute name + * @return editAttributeField The view corresponding to the matching field + */ + getField: function( collection, attr ) { + return _.find( collection, + function( viewModel ) { + return attr === viewModel.model.get('attr'); + } + ); + } +}); sui.views.editAttributeField = editAttributeField; module.exports = editAttributeField; From 714f1a48e09f5c7d2781f03853f4da38b628bf5c Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor Date: Wed, 1 Jul 2015 13:46:36 -0600 Subject: [PATCH 11/12] Setting every value to "value" isn't a good idea Fix rather silly bug. --- js/build/field-color.js | 14 +++++++------- js/build/shortcode-ui.js | 14 +++++++------- js/src/views/edit-attribute-field.js | 14 +++++++------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/js/build/field-color.js b/js/build/field-color.js index 81c2081f..5a32a14c 100644 --- a/js/build/field-color.js +++ b/js/build/field-color.js @@ -283,11 +283,11 @@ var editAttributeField = Backbone.View.extend( { } if ( 'radio' === this.model.attributes.type ) { - this.setValue( 'value', $el.filter(':checked').first().val() ); + this.setValue( $el.filter(':checked').first().val() ); } else if ( 'checkbox' === this.model.attributes.type ) { - this.setValue( 'value', $el.is( ':checked' ) ); + this.setValue( $el.is( ':checked' ) ); } else { - this.setValue( 'value', $el.val() ); + this.setValue( $el.val() ); } this.triggerCallbacks(); @@ -339,10 +339,10 @@ var editAttributeField = Backbone.View.extend( { * @return editAttributeField The view corresponding to the matching field */ getField: function( collection, attr ) { - return _.find( collection, - function( viewModel ) { - return attr === viewModel.model.get('attr'); - } + return _.find( collection, + function( viewModel ) { + return attr === viewModel.model.get('attr'); + } ); } }); diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index 40b21708..9ef6f89b 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -861,11 +861,11 @@ var editAttributeField = Backbone.View.extend( { } if ( 'radio' === this.model.attributes.type ) { - this.setValue( 'value', $el.filter(':checked').first().val() ); + this.setValue( $el.filter(':checked').first().val() ); } else if ( 'checkbox' === this.model.attributes.type ) { - this.setValue( 'value', $el.is( ':checked' ) ); + this.setValue( $el.is( ':checked' ) ); } else { - this.setValue( 'value', $el.val() ); + this.setValue( $el.val() ); } this.triggerCallbacks(); @@ -917,10 +917,10 @@ var editAttributeField = Backbone.View.extend( { * @return editAttributeField The view corresponding to the matching field */ getField: function( collection, attr ) { - return _.find( collection, - function( viewModel ) { - return attr === viewModel.model.get('attr'); - } + return _.find( collection, + function( viewModel ) { + return attr === viewModel.model.get('attr'); + } ); } }); diff --git a/js/src/views/edit-attribute-field.js b/js/src/views/edit-attribute-field.js index 47719fa2..18f3905d 100644 --- a/js/src/views/edit-attribute-field.js +++ b/js/src/views/edit-attribute-field.js @@ -68,11 +68,11 @@ var editAttributeField = Backbone.View.extend( { } if ( 'radio' === this.model.attributes.type ) { - this.setValue( 'value', $el.filter(':checked').first().val() ); + this.setValue( $el.filter(':checked').first().val() ); } else if ( 'checkbox' === this.model.attributes.type ) { - this.setValue( 'value', $el.is( ':checked' ) ); + this.setValue( $el.is( ':checked' ) ); } else { - this.setValue( 'value', $el.val() ); + this.setValue( $el.val() ); } this.triggerCallbacks(); @@ -124,10 +124,10 @@ var editAttributeField = Backbone.View.extend( { * @return editAttributeField The view corresponding to the matching field */ getField: function( collection, attr ) { - return _.find( collection, - function( viewModel ) { - return attr === viewModel.model.get('attr'); - } + return _.find( collection, + function( viewModel ) { + return attr === viewModel.model.get('attr'); + } ); } }); From 5018f3ba73d29fbb6a227643cac30af1b3e11aa5 Mon Sep 17 00:00:00 2001 From: Nathaniel Taintor Date: Wed, 1 Jul 2015 14:22:35 -0600 Subject: [PATCH 12/12] getValue wasn't designed to be used with other attributes I specifically wrote a function called getValue() which takes no arguments and gets a value. Overloading it by allowing it to get other attributes seems like it breaks consistency. Also, the way I was doing it just didn't work. --- js/build/field-color.js | 4 ++-- js/build/shortcode-ui.js | 4 ++-- js/src/views/edit-attribute-field.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/js/build/field-color.js b/js/build/field-color.js index 5a32a14c..6352eac4 100644 --- a/js/build/field-color.js +++ b/js/build/field-color.js @@ -277,9 +277,9 @@ var editAttributeField = Backbone.View.extend( { inputChanged: function( e ) { if ( this.getValue( 'attr' ) ) { - var $el = $( this.el ).find( '[name=' + this.getValue( 'attr' ) + ']' ); + var $el = this.$el.find( '[name="' + this.model.get( 'attr' ) + '"]' ); } else { - var $el = $( this.el ).find( '[name="inner_content"]' ); + var $el = this.$el.find( '[name="inner_content"]' ); } if ( 'radio' === this.model.attributes.type ) { diff --git a/js/build/shortcode-ui.js b/js/build/shortcode-ui.js index 9ef6f89b..dc6d9015 100644 --- a/js/build/shortcode-ui.js +++ b/js/build/shortcode-ui.js @@ -855,9 +855,9 @@ var editAttributeField = Backbone.View.extend( { inputChanged: function( e ) { if ( this.getValue( 'attr' ) ) { - var $el = $( this.el ).find( '[name=' + this.getValue( 'attr' ) + ']' ); + var $el = this.$el.find( '[name="' + this.model.get( 'attr' ) + '"]' ); } else { - var $el = $( this.el ).find( '[name="inner_content"]' ); + var $el = this.$el.find( '[name="inner_content"]' ); } if ( 'radio' === this.model.attributes.type ) { diff --git a/js/src/views/edit-attribute-field.js b/js/src/views/edit-attribute-field.js index 18f3905d..7d5b200b 100644 --- a/js/src/views/edit-attribute-field.js +++ b/js/src/views/edit-attribute-field.js @@ -62,9 +62,9 @@ var editAttributeField = Backbone.View.extend( { inputChanged: function( e ) { if ( this.getValue( 'attr' ) ) { - var $el = $( this.el ).find( '[name=' + this.getValue( 'attr' ) + ']' ); + var $el = this.$el.find( '[name="' + this.model.get( 'attr' ) + '"]' ); } else { - var $el = $( this.el ).find( '[name="inner_content"]' ); + var $el = this.$el.find( '[name="inner_content"]' ); } if ( 'radio' === this.model.attributes.type ) {