window.butterbean = window.butterbean || {}; ( function() { // Bail if we don't have the JSON, which is passed in via `wp_localize_script()`. if ( _.isUndefined( butterbean_data ) ) { return; } /** * Our global object. The `butterbean` object is just a wrapper to house everything * in a single namespace. * * @since 1.0.0 * @access public * @var object */ var api = butterbean = { /** * Houses the manager, section, and control views based on the `type`. * * @since 1.0.0 * @access public * @var object */ views : { managers : {}, sections : {}, controls : {} }, /** * Houses the manager, section, and control templates based on the `type`. * * @since 1.0.0 * @access public * @var object */ templates : { managers : {}, sections : {}, controls : {} } }; /** * Creates a new manager view. * * @since 1.0.0 * @access public * @param string $type * @param object $args * @return void */ api.views.register_manager = function( type, args ) { if ( 'default' !== type ) this.managers[ type ] = this.managers.default.extend( args ); }; /** * Returns a manager view. * * @since 1.0.0 * @access public * @param string $type * @return object */ api.views.get_manager = function( type ) { if ( this.manager_exists( type ) ) return this.managers[ type ]; return this.managers.default; }; /** * Removes a manager view. * * @since 1.0.0 * @access public * @param string $type * @return void */ api.views.unregister_manager = function( type ) { if ( 'default' !== type && this.manager_exists( type ) ) delete this.managers[ type ]; }; /** * Checks if a manager view exists. * * @since 1.0.0 * @access public * @param string $type * @return bool */ api.views.manager_exists = function( type ) { return this.managers.hasOwnProperty( type ); }; /** * Creates a new section view. * * @since 1.0.0 * @access public * @param string $type * @param object $args * @return void */ api.views.register_section = function( type, args ) { if ( 'default' !== type ) this.sections[ type ] = this.sections.default.extend( args ); }; /** * Returns a section view. * * @since 1.0.0 * @access public * @param string $type * @return object */ api.views.get_section = function( type ) { if ( this.section_exists( type ) ) return this.sections[ type ]; return this.sections.default; }; /** * Removes a section view. * * @since 1.0.0 * @access public * @param string $type * @return void */ api.views.unregister_section = function( type ) { if ( 'default' !== type && this.section_exists( type ) ) delete this.sections[ type ]; }; /** * Checks if a section view exists. * * @since 1.0.0 * @access public * @param string $type * @return bool */ api.views.section_exists = function( type ) { return this.sections.hasOwnProperty( type ); }; /** * Creates a new control view. * * @since 1.0.0 * @access public * @param string $type * @param object $args * @return void */ api.views.register_control = function( type, args ) { if ( 'default' !== type ) this.controls[ type ] = this.controls.default.extend( args ); }; /** * Returns a control view. * * @since 1.0.0 * @access public * @param string $type * @return object */ api.views.get_control = function( type ) { if ( this.control_exists( type ) ) return this.controls[ type ]; return this.controls.default; }; /** * Removes a control view. * * @since 1.0.0 * @access public * @param string $type * @return void */ api.views.unregister_control = function( type ) { if ( 'default' !== type && this.control_exists( type ) ) delete this.controls[ type ]; }; /** * Checks if a control view exists. * * @since 1.0.0 * @access public * @param string $type * @return bool */ api.views.control_exists = function( type ) { return this.controls.hasOwnProperty( type ); }; /** * Creates a new manager template. * * @since 1.0.0 * @access public * @param string $type * @param object $args * @return void */ api.templates.register_manager = function( type ) { this.managers[ type ] = wp.template( 'butterbean-manager-' + type ); }; /** * Returns a manager template. * * @since 1.0.0 * @access public * @param string $type * @return function */ api.templates.get_manager = function( type ) { return this.manager_exists( type ) ? this.managers[ type ] : false; }; /** * Removes a manager template. * * @since 1.0.0 * @access public * @param string $type * @return void */ api.templates.unregister_manager = function( type ) { if ( this.manager_exists( type ) ) delete this.managers[ type ]; }; /** * Checks if a manager template exists. * * @since 1.0.0 * @access public * @param string $type * @return bool */ api.templates.manager_exists = function( type ) { return this.managers.hasOwnProperty( type ); }; /** * Creates a new section template. * * @since 1.0.0 * @access public * @param string $type * @param object $args * @return void */ api.templates.register_section = function( type ) { this.sections[ type ] = wp.template( 'butterbean-section-' + type ); }; /** * Returns a section template. * * @since 1.0.0 * @access public * @param string $type * @return function */ api.templates.get_section = function( type ) { return this.section_exists( type ) ? this.sections[ type ] : false; }; /** * Removes a section template. * * @since 1.0.0 * @access public * @param string $type * @return void */ api.templates.unregister_section = function( type ) { if ( this.section_exists( type ) ) delete this.sections[ type ]; }; /** * Checks if a section template exists. * * @since 1.0.0 * @access public * @param string $type * @return bool */ api.templates.section_exists = function( type ) { return this.sections.hasOwnProperty( type ); }; /** * Creates a new control template. * * @since 1.0.0 * @access public * @param string $type * @param object $args * @return void */ api.templates.register_control = function( type ) { this.controls[ type ] = wp.template( 'butterbean-control-' + type ); }; /** * Returns a control template. * * @since 1.0.0 * @access public * @param string $type * @return function */ api.templates.get_control = function( type ) { return this.control_exists( type ) ? this.controls[ type ] : false; }; /** * Removes a control template. * * @since 1.0.0 * @access public * @param string $type * @return void */ api.templates.unregister_control = function( type ) { if ( this.control_exists( type ) ) delete this.controls[ type ]; }; /** * Checks if a control template exists. * * @since 1.0.0 * @access public * @param string $type * @return bool */ api.templates.control_exists = function( type ) { return this.controls.hasOwnProperty( type ); }; /** * Renders our managers, sections, and controls. * * @since 1.0.0 * @access private * @return void */ api.render = function() { // Loop through each of the managers and render their api.views. _.each( butterbean_data.managers, function( data ) { // Create a new manager model with the JSON data for the manager. var manager = new Manager( data ); // Get the manager view callback. var callback = api.views.get_manager( data.type ); // Create a new manager view. var view = new callback( { model : manager } ); // Get the meta box element. var metabox = document.getElementById( 'butterbean-ui-' + manager.get( 'name' ) ); // Add the `.butterbean-ui` class to the meta box. metabox.className += ' butterbean-ui'; // Render the manager view. metabox.querySelector( '.inside' ).appendChild( view.render().el ); // Render the manager subviews. view.subview_render(); // Call the view's ready method. view.ready(); } ); }; /* === Templates === */ // Nav template. var nav_template = wp.template( 'butterbean-nav' ); /* === Models === */ // Manager model (each manager is housed within a meta box). var Manager = Backbone.Model.extend( { defaults : { name : '', type : '', sections : {}, controls : {} } } ); // Section model (each section belongs to a manager). var Section = Backbone.Model.extend( { defaults : { name : '', type : '', label : '', description : '', icon : '', manager : '', active : '', selected : false } } ); // Control model (each control belongs to a manager and section). var Control = Backbone.Model.extend( { defaults : { name : '', type : '', label : '', description : '', icon : '', value : '', choices : {}, attr : '', active : '', manager : '', section : '', setting : '' } } ); /* === Collections === */ /** * Stores our collection of section models. * * @since 1.0.0 * @access private * @var object */ var Sections = Backbone.Collection.extend( { model : Section } ); /* === Views === */ /** * The default manager view. Other views can extend this using the * `butterbean.views.register_manager()` function. * * @since 1.0.0 * @access public * @var object */ api.views.managers[ 'default' ] = Backbone.View.extend( { // Wrapper element for the manager view. tagName : 'div', // Adds some custom attributes to the wrapper. attributes : function() { return { 'id' : 'butterbean-manager-' + this.model.get( 'name' ), 'class' : 'butterbean-manager butterbean-manager-' + this.model.get( 'type' ) }; }, // Initializes the view. initialize : function() { var type = this.model.get( 'type' ); // If there's not yet a template for this manager type, create it. if ( ! api.templates.manager_exists( type ) ) api.templates.register_manager( type ); // Get the manager template. this.template = api.templates.get_manager( type ); }, // Renders the manager. render : function() { this.el.innerHTML = this.template( this.model.toJSON() ); return this; }, // Renders the manager's sections and controls. // Important! This may change drastically in the future, possibly even // taken out of the manager view altogether. It's for this reason that // it's not recommended to create custom views for managers right now. subview_render : function() { // Create a new section collection. var sections = new Sections(); // Loop through each section and add it to the collection. _.each( this.model.get( 'sections' ), function( data ) { sections.add( new Section( data ) ); } ); // Loop through each section in the collection and render its view. sections.forEach( function( section, i ) { // Create a new nav item view for the section. var nav_view = new Nav_View( { model : section } ); // Render the nav item view. document.querySelector( '#butterbean-ui-' + section.get( 'manager' ) + ' .butterbean-nav' ).appendChild( nav_view.render().el ); // Get the section view callback. var callback = api.views.get_section( section.attributes.type ); // Create a new section view. var view = new callback( { model : section } ); // Render the section view. document.querySelector( '#butterbean-ui-' + section.get( 'manager' ) + ' .butterbean-content' ).appendChild( view.render().el ); // Call the section view's ready method. view.ready(); // If the first model, set it to selected. section.set( 'selected', 0 === i ); }, this ); // Loop through each control for the manager and render its view. _.each( this.model.get( 'controls' ), function( data ) { // Create a new control model. var control = new Control( data ); // Get the control view callback. var callback = api.views.get_control( data.type ); // Create a new control view. var view = new callback( { model : control } ); // Render the view. document.getElementById( 'butterbean-' + control.get( 'manager' ) + '-section-' + control.get( 'section' ) ).appendChild( view.render().el ); // Call the view's ready method. view.ready(); } ); return this; }, // Function that is executed *after* the view has been rendered. // This is meant to be overwritten in sub-views. ready : function() {} } ); /** * The default section view. Other views can extend this using the * `butterbean.views.register_section()` function. * * @since 1.0.0 * @access public * @var object */ api.views.sections[ 'default' ] = Backbone.View.extend( { // Wrapper element for the section. tagName : 'div', // Adds custom attributes for the section wrapper. attributes : function() { return { 'id' : 'butterbean-' + this.model.get( 'manager' ) + '-section-' + this.model.get( 'name' ), 'class' : 'butterbean-section butterbean-section-' + this.model.get( 'type' ), 'aria-hidden' : ! this.model.get( 'selected' ) }; }, // Initializes the view. initialize : function() { // Add an event for when the model changes. this.model.on( 'change', this.onchange, this ); // Get the section type. var type = this.model.get( 'type' ); // If there's no template for this section type, create it. if ( ! api.templates.section_exists( type ) ) api.templates.register_section( type ); // Gets the section template. this.template = api.templates.get_section( type ); }, // Renders the section. render : function() { // Only render template if model is active. if ( this.model.get( 'active' ) ) this.el.innerHTML = this.template( this.model.toJSON() ); return this; }, // Executed when the model changes. onchange : function() { // Set the view's `aria-hidden` attribute based on whether the model is selected. this.el.setAttribute( 'aria-hidden', ! this.model.get( 'selected' ) ); }, // Function that is executed *after* the view has been rendered. // This is meant to be overwritten in sub-views. ready : function() {} } ); /** * The nav item view for each section. * * @since 1.0.0 * @access public * @var object */ var Nav_View = Backbone.View.extend( { // Sets the template used. template : nav_template, // Wrapper element for the nav item. tagName : 'li', // Sets some custom attributes for the nav item wrapper. attributes : function() { return { 'aria-selected' : this.model.get( 'selected' ) }; }, // Initializes the nav item view. initialize : function() { this.model.on( 'change', this.render, this ); this.model.on( 'change', this.onchange, this ); }, // Renders the nav item. render : function() { // Only render template if model is active. if ( this.model.get( 'active' ) ) this.el.innerHTML = this.template( this.model.toJSON() ); return this; }, // Custom events. events : { 'click a' : 'onselect' }, // Executed when the section model changes. onchange : function() { // Set the `aria-selected` attibute based on the model selected state. this.el.setAttribute( 'aria-selected', this.model.get( 'selected' ) ); }, // Executed when the link for the nav item is clicked. onselect : function( event ) { event.preventDefault(); // Loop through each of the models in the collection and set them to inactive. _.each( this.model.collection.models, function( m ) { m.set( 'selected', false ); }, this ); // Set this view's model to selected. this.model.set( 'selected', true ); } } ); /** * The default control view. Other views can extend this using the * `butterbean.views.register_control()` function. * * @since 1.0.0 * @access public * @var object */ api.views.controls[ 'default' ] = Backbone.View.extend( { // Wrapper element for the control. tagName : 'div', // Custom attributes for the control wrapper. attributes : function() { return { 'id' : 'butterbean-control-' + this.model.get( 'name' ), 'class' : 'butterbean-control butterbean-control-' + this.model.get( 'type' ) }; }, // Initiazlies the control view. initialize : function() { var type = this.model.get( 'type' ); // Only add a new control template if we have a different control type. if ( ! api.templates.control_exists( type ) ) api.templates.register_control( type ); // Get the control template. this.template = api.templates.get_control( type ); // Bind changes so that the view is re-rendered when the model changes. _.bindAll( this, 'render' ); this.model.bind( 'change', this.render ); }, // Renders the control template. render : function() { // Only render template if model is active. if ( this.model.get( 'active' ) ) this.el.innerHTML = this.template( this.model.toJSON() ); return this; }, // Function that is executed *after* the view has been rendered. // This is meant to be overwritten in sub-views. ready : function() {} } ); /** * Adds the color control view. * * @since 1.0.0 */ api.views.register_control( 'color', { // Calls the core WP color picker for the control's input. ready : function() { var options = this.model.attributes.options; jQuery( this.$el ).find( '.butterbean-color-picker' ).wpColorPicker( options ); } } ); /** * Adds the color palette view. * * @since 1.0.0 */ api.views.register_control( 'palette', { // Adds custom events. events : { 'change input' : 'onselect' }, // Executed when one of the color palette's value has changed. // These are radio inputs. onselect : function() { // Get the value of the input. var value = document.querySelector( '#' + this.el.id + ' input:checked' ).getAttribute( 'value' ); // Get all choices. var choices = this.model.get( 'choices' ); // Loop through choices and change the selected value. _.each( choices, function( choice, key ) { choice.selected = key === value; } ); // Because `choices` is an array, it's not recognized as a change. So, we // have to manually trigger a change here so that the view gets re-rendered. this.model.set( 'choices', choices ).trigger( 'change', this.model ); } } ); /** * Adds the image control view. * * @since 1.0.0 */ api.views.register_control( 'image', { // Adds custom events. events : { 'click .butterbean-add-media' : 'showmodal', 'click .butterbean-change-media' : 'showmodal', 'click .butterbean-remove-media' : 'removemedia' }, // Executed when the show modal button is clicked. showmodal : function() { // If we already have a media modal, open it. if ( ! _.isUndefined( this.media_modal ) ) { this.media_modal.open(); return; } // Create a new media modal. this.media_modal = wp.media( { frame : 'select', multiple : false, editing : true, title : this.model.get( 'l10n' ).choose, library : { type : 'image' }, button : { text: this.model.get( 'l10n' ).set } } ); // Runs when an image is selected in the media modal. this.media_modal.on( 'select', function() { // Gets the JSON data for the first selection. var media = this.media_modal.state().get( 'selection' ).first().toJSON(); // Size of image to display. var size = this.model.attributes.size; // Updates the model for the view. this.model.set( { src : media.sizes[ size ] ? media.sizes[ size ]['url'] : media.url, alt : media.alt, value : media.id } ); }, this ); // Opens the media modal. this.media_modal.open(); }, // Executed when the remove media button is clicked. removemedia : function() { // Updates the model for the view. this.model.set( { src : '', alt : '', value : '' } ); } } ); }() ); lite-vimeo { font-size: 10px; background-color: #000; position: relative; display: block; contain: content; background-position: center center; background-size: cover; background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgOCA0LjUiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBvbHlnb24gcG9pbnRzPSIwLDAgMSwwIDEsNC41IDAsNC41IiBmaWxsPSIjODVkY2U1Ii8+PHBvbHlnb24gcG9pbnRzPSIxLDAgMiwwIDIsNC41IDEsNC41IiBmaWxsPSIjZWJmMmY0Ii8+PHBvbHlnb24gcG9pbnRzPSIyLDAgMywwIDMsNC41IDIsNC41IiBmaWxsPSIjZmU1MjIxIi8+PHBvbHlnb24gcG9pbnRzPSIzLDAgNCwwIDQsNC41IDMsNC41IiBmaWxsPSIjZjdmYzhiIi8+PHBvbHlnb24gcG9pbnRzPSI0LDAgNSwwIDUsNC41IDQsNC41IiBmaWxsPSIjMTJhOWQxIi8+PHBvbHlnb24gcG9pbnRzPSI1LDAgNiwwIDYsNC41IDUsNC41IiBmaWxsPSIjNDEzNzMxIi8+PHBvbHlnb24gcG9pbnRzPSI2LDAgNywwIDcsNC41IDYsNC41IiBmaWxsPSIjYmQyZDA3Ii8+PHBvbHlnb24gcG9pbnRzPSI3LDAgOCwwIDgsNC41IDcsNC41IiBmaWxsPSIjY2ZlZDI1Ii8+PC9zdmc+"); cursor: pointer; } lite-vimeo.awb-lite-vimeo-no-background { background-image: none; } /* gradient, vimeo doesn't have this */ /*lite-vimeo::before { content: ''; display: block; position: absolute; top: 0; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAADGCAYAAAAT+OqFAAAAdklEQVQoz42QQQ7AIAgEF/T/D+kbq/RWAlnQyyazA4aoAB4FsBSA/bFjuF1EOL7VbrIrBuusmrt4ZZORfb6ehbWdnRHEIiITaEUKa5EJqUakRSaEYBJSCY2dEstQY7AuxahwXFrvZmWl2rh4JZ07z9dLtesfNj5q0FU3A5ObbwAAAABJRU5ErkJggg==); background-position: top; background-repeat: repeat-x; height: 60px; padding-bottom: 50px; width: 100%; transition: all 0.2s cubic-bezier(0, 0, 0.2, 1); }*/ /* responsive iframe with a 16:9 aspect ratio thanks https://css-tricks.com/responsive-iframes/ */ lite-vimeo::after { content: ""; display: block; padding-bottom: calc(100% / (16 / 9)); } lite-vimeo > iframe { width: 100%; height: 100%; position: absolute; top: 0; left: 0; } /* play button */ lite-vimeo > .ltv-playbtn { width: 6.5em; height: 4em; background: rgba(23,35,34,.75); z-index: 1; opacity: 0.8; border-radius: .5em; /* TODO: Consider replacing this with YT's actual svg. Eh. */ transition: all 0.2s cubic-bezier(0, 0, 0.2, 1); outline: 0; border: 0; cursor: pointer; } lite-vimeo:hover > .ltv-playbtn { background-color: rgb(0, 173, 239); opacity: 1; } /* play button triangle */ lite-vimeo > .ltv-playbtn::before { content: ''; border-style: solid; border-width: 10px 0 10px 20px; border-color: transparent transparent transparent #fff; } lite-vimeo > .ltv-playbtn, lite-vimeo > .ltv-playbtn::before { position: absolute; top: 50%; left: 50%; transform: translate3d(-50%, -50%, 0); } /* Post-click styles */ lite-vimeo.ltv-activated { cursor: unset; } lite-vimeo.ltv-activated::before, lite-vimeo.ltv-activated > .ltv-playbtn { opacity: 0; pointer-events: none; }
Warning: Cannot modify header information - headers already sent by (output started at /home/u1038669/public_html/wp-content/plugins/better-reviews/includes/template-functions.php:1) in /home/u1038669/public_html/wp-includes/pluggable.php on line 1435

Warning: Cannot modify header information - headers already sent by (output started at /home/u1038669/public_html/wp-content/plugins/better-reviews/includes/template-functions.php:1) in /home/u1038669/public_html/wp-includes/pluggable.php on line 1438