first commit
This commit is contained in:
+123
@@ -0,0 +1,123 @@
|
||||
|
||||
//extends api.CZRModule
|
||||
var BodyBGConstructor = BodyBGConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( BodyBGConstructor, {
|
||||
initialize: function( id, options ) {
|
||||
var module = this;
|
||||
//extend the module with new template Selectors
|
||||
// $.extend( module, {
|
||||
// itemInputList : 'czr-module-bodybg-item-content'
|
||||
// } );
|
||||
|
||||
//EXTEND THE DEFAULT CONSTRUCTORS FOR INPUT
|
||||
module.inputConstructor = api.CZRInput.extend( module.CZRBodyBgInputMths || {} );
|
||||
//EXTEND THE DEFAULT CONSTRUCTORS FOR MONOMODEL
|
||||
module.itemConstructor = api.CZRItem.extend( module.CZBodyBgItemMths || {} );
|
||||
|
||||
//run the parent initialize
|
||||
api.CZRModule.prototype.initialize.call( module, id, options );
|
||||
},//initialize
|
||||
|
||||
|
||||
|
||||
CZRBodyBgInputMths : {
|
||||
//////////////////////////////////////////////////
|
||||
///SETUP SELECTS
|
||||
//////////////////////////////////////////////////
|
||||
//setup select on view_rendered|item_content_event_map
|
||||
setupSelect : function() {
|
||||
var input = this,
|
||||
_id_param_map = {
|
||||
'background-repeat' : 'bg_repeat_options',
|
||||
'background-attachment' : 'bg_attachment_options',
|
||||
'background-position' : 'bg_position_options'
|
||||
},
|
||||
item = input.input_parent,
|
||||
serverParams = bodyBGModuleLocalized,
|
||||
options = {},
|
||||
module = input.module;
|
||||
|
||||
if ( ! _.has( _id_param_map, input.id ) )
|
||||
return;
|
||||
|
||||
if ( _.isUndefined( serverParams ) || _.isUndefined( serverParams[ _id_param_map[input.id] ] ) )
|
||||
return;
|
||||
options = serverParams[ _id_param_map[input.id] ];
|
||||
if ( _.isEmpty(options) )
|
||||
return;
|
||||
//generates the options
|
||||
_.each( options, function( title, key ) {
|
||||
var _attributes = {
|
||||
value : key,
|
||||
html: title
|
||||
};
|
||||
if ( key == input() || _.contains( input(), key ) )
|
||||
$.extend( _attributes, { selected : "selected" } );
|
||||
|
||||
$( 'select[data-czrtype]', input.container ).append( $('<option>', _attributes) );
|
||||
});
|
||||
//fire czrSelect2
|
||||
$( 'select[data-czrtype]', input.container ).czrSelect2();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
CZBodyBgItemMths : {
|
||||
//Fired if the item has been instantiated
|
||||
//The item.callbacks are declared.
|
||||
ready : function() {
|
||||
var item = this;
|
||||
|
||||
item.inputCollection.bind( function( _col_ ) {
|
||||
if ( ! _.isEmpty( _col_ ) && item.czr_Input && item.czr_Input.has( 'background-image' ) ) {
|
||||
item.czr_Input('background-image').isReady.done( function( input_instance ) {
|
||||
var set_visibilities = function( bg_val ) {
|
||||
var is_bg_img_set = ! _.isEmpty( bg_val ) ||_.isNumber( bg_val);
|
||||
_.each( ['background-repeat', 'background-attachment', 'background-position', 'background-size'], function( dep ) {
|
||||
item.czr_Input(dep).container.toggle( is_bg_img_set || false );
|
||||
});
|
||||
};
|
||||
set_visibilities( input_instance() );
|
||||
//update the item model on 'background-image' change
|
||||
item.bind('background-image:changed', function(){
|
||||
set_visibilities( item.czr_Input('background-image')() );
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
api.CZRItem.prototype.ready.call( item );
|
||||
},
|
||||
|
||||
}
|
||||
});//$.extend
|
||||
|
||||
|
||||
//provides a description of each module
|
||||
//=> will determine :
|
||||
//1) how to initialize the module model. If not crud, then the initial item(s) model shall be provided
|
||||
//2) which js template(s) to use : if crud, the module template shall include the add new and pre-item elements.
|
||||
// , if crud, the item shall be removable
|
||||
//3) how to render : if multi item, the item content is rendered when user click on edit button.
|
||||
// If not multi item, the single item content is rendered as soon as the item wrapper is rendered.
|
||||
//4) some DOM behaviour. For example, a multi item shall be sortable.
|
||||
api.czrModuleMap = api.czrModuleMap || {};
|
||||
$.extend( api.czrModuleMap, {
|
||||
czr_background : {
|
||||
mthds : BodyBGConstructor,
|
||||
crud : false,
|
||||
multi_item : false,
|
||||
name : 'Body Background',
|
||||
has_mod_opt : false,
|
||||
ready_on_section_expanded : true,
|
||||
defaultItemModel : {
|
||||
'background-color' : '#eaeaea',
|
||||
'background-image' : '',
|
||||
'background-repeat' : 'no-repeat',
|
||||
'background-attachment' : 'fixed',
|
||||
'background-position' : 'center center',
|
||||
'background-size' : 'cover'
|
||||
}
|
||||
}
|
||||
});
|
||||
})( wp.customize , jQuery, _ );
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
function hu_register_body_bg_module( $args ) {
|
||||
$defaults = array(
|
||||
'setting_id' => '',
|
||||
|
||||
'base_url_path' => '',//PC_AC_BASE_URL/inc/czr-modules/social-links/
|
||||
'version' => '',
|
||||
|
||||
'option_value' => array(), //<= will be used for the dynamic registration
|
||||
|
||||
'setting' => array(),
|
||||
'control' => array(),
|
||||
'section' => array(), //array( 'id' => '', 'label' => '' ),
|
||||
|
||||
'sanitize_callback' => '',
|
||||
'validate_callback' => ''
|
||||
);
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
if ( ! isset( $GLOBALS['czr_base_fmk_namespace'] ) ) {
|
||||
error_log( __FUNCTION__ . ' => global czr_base_fmk not set' );
|
||||
return;
|
||||
}
|
||||
|
||||
$czrnamespace = $GLOBALS['czr_base_fmk_namespace'];
|
||||
//czr_fn\czr_register_dynamic_module
|
||||
$CZR_Fmk_Base_fn = $czrnamespace . 'CZR_Fmk_Base';
|
||||
if ( ! function_exists( $CZR_Fmk_Base_fn) ) {
|
||||
error_log( __FUNCTION__ . ' => Namespace problem => ' . $CZR_Fmk_Base_fn );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$CZR_Fmk_Base_fn() -> czr_pre_register_dynamic_setting( array(
|
||||
'setting_id' => $args['setting_id'],
|
||||
'module_type' => 'czr_background',
|
||||
'option_value' => ! is_array( $args['option_value'] ) ? array() : $args['option_value'],
|
||||
|
||||
'setting' => $args['setting'],
|
||||
|
||||
'section' => $args['section'],
|
||||
|
||||
'control' => $args['control']
|
||||
));
|
||||
|
||||
// czr_fn\czr_register_dynamic_module()
|
||||
$CZR_Fmk_Base_fn() -> czr_pre_register_dynamic_module( array(
|
||||
'dynamic_registration' => true,
|
||||
'module_type' => 'czr_background',
|
||||
|
||||
// 'sanitize_callback' => 'hu_sanitize_callback__czr_social_module',
|
||||
// 'validate_callback' => 'hu_validate_callback__czr_social_module',
|
||||
|
||||
'customizer_assets' => array(
|
||||
'control_js' => array(
|
||||
// handle + params for wp_enqueue_script()
|
||||
// @see https://developer.wordpress.org/reference/functions/wp_enqueue_script/
|
||||
'czr-body-bg-module' => array(
|
||||
'src' => sprintf(
|
||||
'%1$s/assets/js/%2$s',
|
||||
$args['base_url_path'],
|
||||
'_3_2_body_background_module.js'
|
||||
),
|
||||
'deps' => array('customize-controls' , 'jquery', 'underscore'),
|
||||
'ver' => ( defined('WP_DEBUG') && true === WP_DEBUG ) ? time() : $args['version'],
|
||||
'in_footer' => true
|
||||
)
|
||||
),
|
||||
'localized_control_js' => array(
|
||||
'deps' => 'czr-customizer-fmk',
|
||||
'global_var_name' => 'bodyBGModuleLocalized',
|
||||
'params' => array(
|
||||
//background repeat select options
|
||||
'bg_repeat_options' => array(
|
||||
'no-repeat' => __( 'No Repeat', 'hueman' ),
|
||||
'repeat' => __( 'Repeat All', 'hueman' ),
|
||||
'repeat-x' => __( 'Repeat Horizontally', 'hueman' ),
|
||||
'repeat-y' => __( 'Repeat Vertically', 'hueman' ),
|
||||
'inherit' => __( 'Inherit', 'hueman' ),
|
||||
),
|
||||
|
||||
//background attachment select options
|
||||
'bg_attachment_options' => array(
|
||||
'fixed' => __( 'Fixed', 'hueman' ),
|
||||
'scroll' => __( 'Scroll', 'hueman' ),
|
||||
'inherit' => __( 'Inherit', 'hueman' ),
|
||||
),
|
||||
|
||||
//background position select options
|
||||
'bg_position_options' => array(
|
||||
'left top' => __( 'Left Top', 'hueman' ),
|
||||
'left center' => __( 'Left Center', 'hueman' ),
|
||||
'left bottom' => __( 'Left Bottom', 'hueman' ),
|
||||
'center top' => __( 'Center Top', 'hueman' ),
|
||||
'center center' => __( 'Center Center', 'hueman' ),
|
||||
'center bottom' => __( 'Center Bottom', 'hueman' ),
|
||||
'right top' => __( 'Right Top', 'hueman' ),
|
||||
'right center' => __( 'Right Center', 'hueman' ),
|
||||
'right bottom' => __( 'Right Bottom', 'hueman' ),
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
'tmpl' => array(
|
||||
'item-inputs' => array(
|
||||
'background-color' => array(
|
||||
'input_type' => 'wp_color_alpha',
|
||||
'title' => __('Color', 'hueman'),
|
||||
'default' => '#eaeaea',
|
||||
'width-100' => true
|
||||
),//"#000000",
|
||||
'background-image' => array(
|
||||
'input_type' => 'upload',
|
||||
'title' => __('Background Image', 'hueman'),
|
||||
),
|
||||
'background-repeat' => array(
|
||||
'input_type' => 'select',
|
||||
'title' => __('Repeat', 'hueman'),
|
||||
),
|
||||
'background-attachment' => array(
|
||||
'input_type' => 'select',
|
||||
'title' => __('Background attachment', 'hueman'),
|
||||
),
|
||||
'background-position' => array(
|
||||
'input_type' => 'select',
|
||||
'title' => __('Background position', 'hueman'),
|
||||
),
|
||||
'background-size' => array(
|
||||
'input_type' => 'text',
|
||||
'title' => __('Background size', 'hueman'),
|
||||
'notice_after' => sprintf( '%1$s %2$s',
|
||||
__('The background-size CSS property specifies the size of the background images. The size of the image can be fully constrained or only partially in order to preserve its intrinsic ratio.', 'hueman'),
|
||||
sprintf(' %1$s %2$s.',
|
||||
__('Learn more', 'hueman'),
|
||||
sprintf('<a href="%1$s" target="_blank">%2$s</a>', esc_url('developer.mozilla.org/en-US/docs/Web/CSS/background-size'), __('here', 'hueman') )
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)//tmpl
|
||||
));
|
||||
}//hu_register_body_bg_module()
|
||||
+499
@@ -0,0 +1,499 @@
|
||||
//extends api.CZRDynModule
|
||||
var CZRSocialModuleMths = CZRSocialModuleMths || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( CZRSocialModuleMths, {
|
||||
initialize: function( id, options ) {
|
||||
if ( _.isUndefined( window.socialModuleLocalized ) ) {
|
||||
api.errorLog( 'social module => Missing localized js params socialModuleLocalized');
|
||||
}
|
||||
|
||||
var module = this;
|
||||
//run the parent initialize
|
||||
api.CZRDynModule.prototype.initialize.call( module, id, options );
|
||||
|
||||
//extend the module with new template Selectors
|
||||
$.extend( module, {
|
||||
itemPreAddEl : '',/// 'czr-module-social-pre-add-view-content',
|
||||
itemInputList : '',// 'czr-module-social-item-content',
|
||||
modOptInputList : ''//czr-module-social-mod-opt'
|
||||
} );
|
||||
|
||||
this.social_icons = [
|
||||
'500px',
|
||||
'adn',
|
||||
'amazon',
|
||||
'android',
|
||||
'angellist',
|
||||
'apple',
|
||||
'behance',
|
||||
'behance-square',
|
||||
'bitbucket',
|
||||
//'bitbucket-square', //<- removed in fa5
|
||||
'black-tie',
|
||||
'btc',
|
||||
'buysellads',
|
||||
'chrome',
|
||||
'codepen',
|
||||
'codiepie',
|
||||
'connectdevelop',
|
||||
'contao',
|
||||
'dashcube',
|
||||
'delicious',
|
||||
'deviantart',
|
||||
'digg',
|
||||
'discord',
|
||||
'dribbble',
|
||||
'dropbox',
|
||||
'drupal',
|
||||
'edge',
|
||||
'empire',
|
||||
'envelope',
|
||||
'envelope-o', //<- go with far envelope
|
||||
'envelope-square',
|
||||
'expeditedssl',
|
||||
'facebook',
|
||||
'facebook-f (alias)',
|
||||
//'facebook-official', //<- removed in fa5
|
||||
'facebook-square',
|
||||
'firefox',
|
||||
'flickr',
|
||||
'flipboard',
|
||||
'fonticons',
|
||||
'fort-awesome',
|
||||
'forumbee',
|
||||
'foursquare',
|
||||
'get-pocket',
|
||||
'gg',
|
||||
'gg-circle',
|
||||
'git',
|
||||
'github',
|
||||
'github-alt',
|
||||
'github-square',
|
||||
'gitlab',
|
||||
'git-square',
|
||||
'google',
|
||||
'google-plus',
|
||||
//'google-plus-circle', //<- removed in fa5
|
||||
//'google-plus-official', //<- removed in fa5
|
||||
'google-plus-g', //<- added in fa5
|
||||
'google-plus-square',
|
||||
'google-wallet',
|
||||
'gratipay',
|
||||
'hacker-news',
|
||||
'houzz',
|
||||
'imdb',
|
||||
'instagram',
|
||||
'internet-explorer',
|
||||
'ioxhost',
|
||||
'joomla',
|
||||
'jsfiddle',
|
||||
'lastfm',
|
||||
'lastfm-square',
|
||||
'leanpub',
|
||||
'line',
|
||||
'linkedin',
|
||||
//'linkedin-square', //<- removed in fa5
|
||||
'linkedin-in', //<- added in fa5
|
||||
'linux',
|
||||
'mastodon',
|
||||
'maxcdn',
|
||||
//'meanpath', <- removed in fa5
|
||||
'meetup',
|
||||
'medium',
|
||||
'mixcloud',
|
||||
'map-marker',
|
||||
'mobile',
|
||||
'mobile-alt',//<- added in fa5
|
||||
'modx',
|
||||
'odnoklassniki',
|
||||
'odnoklassniki-square',
|
||||
'opencart',
|
||||
'openid',
|
||||
'opera',
|
||||
'optin-monster',
|
||||
'pagelines',
|
||||
'patreon',
|
||||
'paypal',
|
||||
'phone',
|
||||
'phone-square',
|
||||
'pied-piper',
|
||||
'pied-piper-alt',
|
||||
'pinterest',
|
||||
'pinterest-p',
|
||||
'pinterest-square',
|
||||
'product-hunt',
|
||||
'qq',
|
||||
'rebel',
|
||||
'reddit',
|
||||
'reddit-alien',
|
||||
'reddit-square',
|
||||
'renren',
|
||||
'rss',
|
||||
'rss-square',
|
||||
'safari',
|
||||
'scribd',
|
||||
'sellsy',
|
||||
'share-alt',
|
||||
'share-alt-square',
|
||||
'shirtsinbulk',
|
||||
'simplybuilt',
|
||||
'skyatlas',
|
||||
'skype',
|
||||
'slack',
|
||||
'slideshare',
|
||||
'sms',
|
||||
'snapchat',
|
||||
'soundcloud',
|
||||
'spotify',
|
||||
'stack-exchange',
|
||||
'stack-overflow',
|
||||
'steam',
|
||||
'steam-square',
|
||||
'stumbleupon',
|
||||
'stumbleupon-circle',
|
||||
'strava',
|
||||
'telegram',
|
||||
'tencent-weibo',
|
||||
'tiktok',
|
||||
'trello',
|
||||
'tripadvisor',
|
||||
'tumblr',
|
||||
'tumblr-square',
|
||||
'twitch',
|
||||
'twitter',
|
||||
'twitter-square',
|
||||
'usb',
|
||||
'viacoin',
|
||||
'viber',
|
||||
'vimeo',
|
||||
'vimeo-square',
|
||||
'vine',
|
||||
'vk',
|
||||
'weibo',
|
||||
'weixin',
|
||||
'whatsapp',
|
||||
'wikipedia-w',
|
||||
'windows',
|
||||
'wordpress',
|
||||
'xing',
|
||||
'xing-square',
|
||||
'yahoo',
|
||||
'y-combinator',
|
||||
'yelp',
|
||||
'youtube',
|
||||
//'youtube-play', //<- removed in fa5
|
||||
'youtube-square'
|
||||
];
|
||||
|
||||
//FA5 backward compatibility with FA4
|
||||
//see https://github.com/presscustomizr/customizr/issues/1364
|
||||
this.fa_solid_icons = [
|
||||
'fa-envelope',
|
||||
'fa-envelope-square',
|
||||
'fa-map-marker',
|
||||
'fa-mobile',
|
||||
'fa-mobile-alt',
|
||||
'fa-phone',
|
||||
'fa-phone-square',
|
||||
'fa-rss',
|
||||
'fa-rss-square',
|
||||
'fa-share-alt',
|
||||
'fa-share-alt-square',
|
||||
'fa-sms'
|
||||
];
|
||||
|
||||
this.fa_icons_replacement = {
|
||||
'fa-bitbucket-square' : 'fa-bitbucket',
|
||||
'fa-facebook-official' : 'fa-facebook-f',
|
||||
'fa-google-plus-circle' : 'fa-google-plus',
|
||||
'fa-google-plus-official' : 'fa-google-plus',
|
||||
'fa-linkedin-square' : 'fa-linkedin',
|
||||
'fa-youtube-play' : 'fa-youtube'
|
||||
};
|
||||
|
||||
this.defaultSocialColor = socialModuleLocalized.defaultSocialColor ? socialModuleLocalized.defaultSocialColor : 'rgb(90,90,90)';
|
||||
this.defaultSocialSize = socialModuleLocalized.defaultSocialSize ? socialModuleLocalized.defaultSocialSize : 14;
|
||||
|
||||
//EXTEND THE DEFAULT CONSTRUCTORS FOR INPUT
|
||||
module.inputConstructor = api.CZRInput.extend( module.CZRSocialsInputMths || {} );
|
||||
//EXTEND THE DEFAULT CONSTRUCTORS FOR MONOMODEL
|
||||
module.itemConstructor = api.CZRItem.extend( module.CZRSocialsItem || {} );
|
||||
|
||||
//declares a default ModOpt model
|
||||
this.defaultModOptModel = {
|
||||
is_mod_opt : true,
|
||||
module_id : module.id,
|
||||
'social-size' : module.defaultSocialSize
|
||||
};
|
||||
|
||||
//declares a default model
|
||||
this.defaultItemModel = {
|
||||
id : '',
|
||||
title : '' ,
|
||||
'social-icon' : '',
|
||||
'social-link' : '',
|
||||
'social-color' : module.defaultSocialColor,
|
||||
'social-target' : 1
|
||||
};
|
||||
|
||||
//overrides the default success message
|
||||
this.itemAddedMessage = socialModuleLocalized.i18n['New Social Link created ! Scroll down to edit it.'];
|
||||
|
||||
//fired ready :
|
||||
//1) on section expansion
|
||||
//2) or in the case of a module embedded in a regular control, if the module section is already opened => typically when skope is enabled
|
||||
if ( _.has( api, 'czr_activeSectionId' ) && module.control.section() == api.czr_activeSectionId() && 'resolved' != module.isReady.state() ) {
|
||||
module.ready();
|
||||
}
|
||||
|
||||
api.section( module.control.section() ).expanded.bind(function(to) {
|
||||
//set module ready on section expansion
|
||||
if ( 'resolved' != module.isReady.state() ) {
|
||||
module.ready();
|
||||
}
|
||||
});
|
||||
|
||||
module.isReady.then( function() {
|
||||
if ( _.isUndefined( module.preItem ) )
|
||||
return;
|
||||
//specific update for the item preModel on social-icon change
|
||||
module.preItem.bind( function( to, from ) {
|
||||
if ( ! _.has(to, 'social-icon') )
|
||||
return;
|
||||
if ( _.isEqual( to['social-icon'], from['social-icon'] ) )
|
||||
return;
|
||||
module.updateItemModel( module.preItem, true );
|
||||
});
|
||||
});
|
||||
},//initialize
|
||||
|
||||
|
||||
//ACTIONS ON ICON CHANGE
|
||||
//Fired on 'social-icon:changed'
|
||||
//Don't fire in pre item case
|
||||
//@item_instance an be the preItem or an already created item
|
||||
updateItemModel : function( item_instance, is_preItem ) {
|
||||
var item = item_instance,
|
||||
module = this;
|
||||
|
||||
is_preItem = is_preItem || false;
|
||||
|
||||
//check if we are in the pre Item case => if so, the social-icon might be empty
|
||||
if ( ! _.has( item(), 'social-icon') || _.isEmpty( item()['social-icon'] ) )
|
||||
return;
|
||||
|
||||
var _new_model, _new_title, _new_color;
|
||||
|
||||
_new_model = $.extend( true, {}, item() );//always safer to deep clone ( alternative to _.clone() ) => we don't know how nested this object might be in the future
|
||||
_new_title = this.getTitleFromIcon( _new_model['social-icon'] );
|
||||
_new_color = module.defaultSocialColor;
|
||||
if ( ! is_preItem && item.czr_Input.has( 'social-color' ) )
|
||||
_new_color = item.czr_Input('social-color')();
|
||||
|
||||
//add text follow us... to the title
|
||||
_new_title = [ socialModuleLocalized.i18n['Follow us on'], _new_title].join(' ');
|
||||
|
||||
if ( is_preItem ) {
|
||||
_new_model = $.extend( _new_model, { title : _new_title, 'social-color' : _new_color } );
|
||||
item.set( _new_model );
|
||||
} else {
|
||||
item.czr_Input('title').set( _new_title );
|
||||
//item.czr_Input('social-link').set( '' );
|
||||
if ( item.czr_Input('social-color') ) { //optional
|
||||
item.czr_Input('social-color').set( _new_color );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/* Helpers */
|
||||
getTitleFromIcon : function( icon ) {
|
||||
return api.CZR_Helpers.capitalize( icon.replace('fa-', '').replace('envelope', 'email') );
|
||||
},
|
||||
|
||||
getIconFromTitle : function( title ) {
|
||||
return 'fa-' . title.toLowerCase().replace('envelope', 'email');
|
||||
},
|
||||
|
||||
//from : https://stackoverflow.com/a/34560648
|
||||
_strReplace : function( $f, $r, $s ) {
|
||||
return $s.replace(new RegExp("(" + (typeof($f) == "string" ? $f.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&") : $f.map(function(i){return i.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&")}).join("|")) + ")", "g"), typeof($r) == "string" ? $r : typeof($f) == "string" ? $r[0] : function(i){ return $r[$f.indexOf(i)]});
|
||||
},
|
||||
|
||||
buildFaIcon : function( value ) {
|
||||
//FA5 backward compatibility with FA4
|
||||
//see https://github.com/presscustomizr/customizr/issues/1364
|
||||
//by default they're brands
|
||||
var _fa_group = 'fab', //<- brand group by default
|
||||
_icon_class = value.toLowerCase(),
|
||||
solidIcons = this.fa_solid_icons,
|
||||
iconsReplacement = this.fa_icons_replacement;
|
||||
|
||||
_icon_class = this._strReplace( _.keys( iconsReplacement ), _.values( iconsReplacement ),_icon_class);
|
||||
|
||||
//former -o icons => now part of the far (Regular) group
|
||||
if ( _icon_class.match(/-o$/) ) {
|
||||
_fa_group = 'far';
|
||||
_icon_class = _icon_class.replace(/-o$/,'');
|
||||
}
|
||||
//solid icons
|
||||
else if ( _.contains( solidIcons, _icon_class ) ) {
|
||||
_fa_group = 'fas';
|
||||
}
|
||||
|
||||
return _fa_group + ' ' +_icon_class;
|
||||
|
||||
},
|
||||
|
||||
|
||||
|
||||
CZRSocialsInputMths : {
|
||||
setupSelect : function() {
|
||||
var input = this,
|
||||
item = input.input_parent,
|
||||
module = input.module,
|
||||
socialList = module.social_icons,
|
||||
solidIcons = module.fa_solid_icons,
|
||||
iconsReplacement = module.fa_icons_eplacement,
|
||||
_model = item(),
|
||||
//check if we are in the pre Item case => if so, the id is empty
|
||||
is_preItem = _.isEmpty( _model.id );
|
||||
|
||||
//=> add the select text in the pre Item case
|
||||
if ( is_preItem ) {
|
||||
socialList = _.union( [ socialModuleLocalized.i18n['Select a social icon'] || 'Select a social icon' ], socialList );
|
||||
}
|
||||
//generates the options
|
||||
_.each( socialList , function( icon_name, k ) {
|
||||
icon_name = _.isEmpty( icon_name ) ? '' : icon_name;
|
||||
// in the pre Item case the first select element is the notice "Select a social icon"
|
||||
// doesn't need the fa-* class
|
||||
var _value = ( is_preItem && 0 === k ) ? '' : 'fa-' + icon_name.toLowerCase(),
|
||||
_attributes = {
|
||||
value : _value,
|
||||
html: module.getTitleFromIcon( icon_name )
|
||||
};
|
||||
if ( _value == _model['social-icon'] )
|
||||
$.extend( _attributes, { selected : "selected" } );
|
||||
|
||||
$( 'select[data-czrtype="social-icon"]', input.container ).append( $('<option>', _attributes) );
|
||||
});
|
||||
|
||||
function addIcon( state ) {
|
||||
if (! state.id) { return state.text; }
|
||||
|
||||
//two spans here because we cannot wrap the social text into the social icon span as the solid FA5 font-weight is bold
|
||||
var $state = $(
|
||||
'<span class="' + module.buildFaIcon( state.element.value.toLowerCase() ) + '"></span><span class="social-name"> ' + state.text + '</span>'
|
||||
);
|
||||
return $state;
|
||||
}
|
||||
|
||||
//fire select2
|
||||
$( 'select[data-czrtype="social-icon"]', input.container ).czrSelect2( {
|
||||
templateResult: addIcon,
|
||||
templateSelection: addIcon
|
||||
});
|
||||
},
|
||||
|
||||
setupColorPicker : function( obj ) {
|
||||
var input = this,
|
||||
item = input.input_parent,
|
||||
module = input.module,
|
||||
$el = $( 'input[data-czrtype="social-color"]', input.container );
|
||||
|
||||
$el.iris( {
|
||||
palettes: true,
|
||||
hide:false,
|
||||
defaultColor : module.defaultSocialColor || 'rgba(255,255,255,0.7)',
|
||||
change : function( e, o ) {
|
||||
//if the input val is not updated here, it's not detected right away.
|
||||
//weird
|
||||
//is there a "change complete" kind of event for iris ?
|
||||
//hack to reset the color to default...@todo => use another color picker.
|
||||
if ( _.has( o, 'color') && 16777215 == o.color._color )
|
||||
$(this).val( module.defaultSocialColor || 'rgba(255,255,255,0.7)' );
|
||||
else
|
||||
$(this).val( o.color.toString() );
|
||||
|
||||
$(this).trigger('colorpickerchange').trigger('change');
|
||||
}
|
||||
});
|
||||
|
||||
//when the picker opens, it might be below the visible viewport.
|
||||
//No built-in event available to react on this in the wpColorPicker unfortunately
|
||||
$el.closest('div').on('click keydown', function() {
|
||||
module._adjustScrollExpandedBlock( input.container );
|
||||
});
|
||||
}
|
||||
|
||||
},//CZRSocialsInputMths
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
CZRSocialsItem : {
|
||||
//Fired if the item has been instantiated
|
||||
//The item.callbacks are declared.
|
||||
ready : function() {
|
||||
var item = this;
|
||||
api.CZRItem.prototype.ready.call( item );
|
||||
|
||||
//update the item model on social-icon change
|
||||
item.bind('social-icon:changed', function(){
|
||||
item.module.updateItemModel( item );
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
_buildTitle : function( title, icon, color ) {
|
||||
var item = this,
|
||||
module = item.module;
|
||||
|
||||
title = title || ( 'string' === typeof(icon) ? api.CZR_Helpers.capitalize( icon.replace( 'fa-', '') ) : '' );
|
||||
title = api.CZR_Helpers.truncate(title, 20);
|
||||
icon = icon || 'fa-' + module.social_icons[0];
|
||||
color = color || module.defaultSocialColor;
|
||||
|
||||
return '<div><span class="' + module.buildFaIcon( icon ) + '" style="color:' + color + '"></span> ' + title + '</div>';
|
||||
},
|
||||
|
||||
//overrides the default parent method by a custom one
|
||||
//at this stage, the model passed in the obj is up to date
|
||||
writeItemViewTitle : function( model ) {
|
||||
var item = this,
|
||||
module = item.module,
|
||||
_model = model || item(),
|
||||
_title = module.getTitleFromIcon( _model['social-icon'] );
|
||||
|
||||
$( '.' + module.control.css_attr.item_title , item.container ).html(
|
||||
item._buildTitle( _title, _model['social-icon'], _model['social-color'] )
|
||||
);
|
||||
}
|
||||
},//CZRSocialsItem
|
||||
});//$.extend
|
||||
})( wp.customize , jQuery, _ );
|
||||
|
||||
(function ( api, $ ) {
|
||||
//provides a description of each module
|
||||
//=> will determine :
|
||||
//1) how to initialize the module model. If not crud, then the initial item(s) model shall be provided
|
||||
//2) which js template(s) to use : if crud, the module template shall include the add new and pre-item elements.
|
||||
// , if crud, the item shall be removable
|
||||
//3) how to render : if multi item, the item content is rendered when user click on edit button.
|
||||
// If not multi item, the single item content is rendered as soon as the item wrapper is rendered.
|
||||
//4) some DOM behaviour. For example, a multi item shall be sortable.
|
||||
api.czrModuleMap = api.czrModuleMap || {};
|
||||
$.extend( api.czrModuleMap, {
|
||||
czr_social_module : {
|
||||
mthds : CZRSocialModuleMths,
|
||||
crud : true,
|
||||
name : 'Social Icons',
|
||||
has_mod_opt : true
|
||||
},
|
||||
});
|
||||
})( wp.customize, jQuery );
|
||||
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
function hu_register_social_links_module( $args ) {
|
||||
$defaults = array(
|
||||
'setting_id' => '',
|
||||
|
||||
'base_url_path' => '',//PC_AC_BASE_URL/inc/czr-modules/social-links/
|
||||
'version' => '',
|
||||
|
||||
'option_value' => array(), //<= will be used for the dynamic registration
|
||||
|
||||
'setting' => array(),
|
||||
'control' => array(),
|
||||
'section' => array(), //array( 'id' => '', 'label' => '' ),
|
||||
|
||||
'sanitize_callback' => '',
|
||||
'validate_callback' => ''
|
||||
);
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
if ( ! isset( $GLOBALS['czr_base_fmk_namespace'] ) ) {
|
||||
error_log( __FUNCTION__ . ' => global czr_base_fmk not set' );
|
||||
return;
|
||||
}
|
||||
|
||||
$czrnamespace = $GLOBALS['czr_base_fmk_namespace'];
|
||||
//czr_fn\czr_register_dynamic_module
|
||||
$CZR_Fmk_Base_fn = $czrnamespace . 'CZR_Fmk_Base';
|
||||
if ( ! function_exists( $CZR_Fmk_Base_fn) ) {
|
||||
error_log( __FUNCTION__ . ' => Namespace problem => ' . $CZR_Fmk_Base_fn );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$CZR_Fmk_Base_fn() -> czr_pre_register_dynamic_setting( array(
|
||||
'setting_id' => $args['setting_id'],
|
||||
'module_type' => 'czr_social_module',
|
||||
'option_value' => ! is_array( $args['option_value'] ) ? array() : $args['option_value'],
|
||||
|
||||
'setting' => $args['setting'],
|
||||
|
||||
'section' => $args['section'],
|
||||
|
||||
'control' => $args['control']
|
||||
));
|
||||
|
||||
// czr_fn\czr_register_dynamic_module()
|
||||
$CZR_Fmk_Base_fn() -> czr_pre_register_dynamic_module( array(
|
||||
'dynamic_registration' => true,
|
||||
'module_type' => 'czr_social_module',
|
||||
|
||||
'sanitize_callback' => 'hu_sanitize_callback__czr_social_module',
|
||||
//'validate_callback' => 'hu_validate_callback__czr_social_module',
|
||||
|
||||
'customizer_assets' => array(
|
||||
'control_js' => array(
|
||||
// handle + params for wp_enqueue_script()
|
||||
// @see https://developer.wordpress.org/reference/functions/wp_enqueue_script/
|
||||
'czr-social-links-module' => array(
|
||||
'src' => sprintf(
|
||||
'%1$s/assets/js/%2$s',
|
||||
$args['base_url_path'],
|
||||
'_2_7_socials_module.js'
|
||||
),
|
||||
'deps' => array('customize-controls' , 'jquery', 'underscore'),
|
||||
'ver' => ( defined('WP_DEBUG') && true === WP_DEBUG ) ? time() : $args['version'],
|
||||
'in_footer' => true
|
||||
)
|
||||
),
|
||||
'localized_control_js' => array(
|
||||
'deps' => 'czr-customizer-fmk',
|
||||
'global_var_name' => 'socialModuleLocalized',
|
||||
'params' => array(
|
||||
//Social Module
|
||||
'defaultSocialColor' => 'rgb(90,90,90)',
|
||||
'defaultSocialSize' => 14,
|
||||
'i18n' => array(
|
||||
'Rss' => __('Rss', 'hueman'),
|
||||
'Select a social icon' => __('Select a social icon', 'hueman'),
|
||||
'Follow us on' => __('Follow us on', 'hueman'),
|
||||
'Done !' => __('Done !', 'hueman'),
|
||||
'New Social Link created ! Scroll down to edit it.' => __('New Social Link created ! Scroll down to edit it.', 'hueman'),
|
||||
)
|
||||
//option value for dynamic registration
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
'tmpl' => array(
|
||||
'pre-item' => array(
|
||||
'social-icon' => array(
|
||||
'input_type' => 'select',
|
||||
'title' => __('Select an icon', 'hueman')
|
||||
),
|
||||
'social-link' => array(
|
||||
'input_type' => 'text',
|
||||
'title' => __('Social link url', 'hueman'),
|
||||
'notice_after' => __('Enter the full url of your social profile (must be valid url).', 'hueman'),
|
||||
'placeholder' => __('http://...,mailto:...,...', 'hueman')
|
||||
)
|
||||
),
|
||||
'mod-opt' => array(
|
||||
'social-size' => array(
|
||||
'input_type' => 'number',
|
||||
'title' => __('Size in px', 'hueman'),
|
||||
'step' => 1,
|
||||
'min' => 5,
|
||||
'transport' => 'postMessage'
|
||||
)
|
||||
),
|
||||
'item-inputs' => array(
|
||||
'social-icon' => array(
|
||||
'input_type' => 'select',
|
||||
'title' => __('Social icon', 'hueman')
|
||||
),
|
||||
'social-link' => array(
|
||||
'input_type' => 'text',
|
||||
'title' => __('Social link', 'hueman'),
|
||||
'notice_after' => __('Enter the full url of your social profile (must be valid url).', 'hueman'),
|
||||
'placeholder' => __('http://...,mailto:...,...', 'hueman')
|
||||
),
|
||||
'title' => array(
|
||||
'input_type' => 'text',
|
||||
'title' => __('Title', 'hueman'),
|
||||
'notice_after' => __('This is the text displayed on mouse over.', 'hueman'),
|
||||
),
|
||||
'social-color' => array(
|
||||
'input_type' => 'color',
|
||||
'title' => sprintf( '%1$s <i>%2$s %3$s</i>', __('Icon color', 'hueman'), __('default:', 'hueman'), 'rgba(255,255,255,0.7)' ),
|
||||
'notice_after' => __('Set a unique color for your icon.', 'hueman'),
|
||||
'transport' => 'postMessage'
|
||||
),
|
||||
'social-target' => array(
|
||||
'input_type' => 'nimblecheck',
|
||||
'title' => __('Link target', 'hueman'),
|
||||
'notice_after' => __('Check this option to open the link in a another tab of the browser.', 'hueman'),
|
||||
'title_width' => 'width-80',
|
||||
'input_width' => 'width-20',
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
}//ac_register_social_links_module()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// SANITIZATION
|
||||
/***
|
||||
* Social Module sanitization/validation
|
||||
**/
|
||||
function hu_sanitize_callback__czr_social_module( $socials ) {
|
||||
// error_log( 'IN SANITIZATION CALLBACK' );
|
||||
// error_log( print_r( $socials, true ));
|
||||
if ( empty( $socials ) )
|
||||
return array();
|
||||
|
||||
//sanitize urls and titles for the db
|
||||
foreach ( $socials as $index => &$social ) {
|
||||
if ( ! is_array( $social ) || ! array_key_exists( 'title', $social) )
|
||||
continue;
|
||||
|
||||
$social['title'] = esc_attr( $social['title'] );
|
||||
}
|
||||
return $socials;
|
||||
}
|
||||
|
||||
function hu_validate_callback__czr_social_module( $validity, $socials ) {
|
||||
// error_log( 'IN VALIDATION CALLBACK' );
|
||||
// error_log( print_r( $socials, true ));
|
||||
$ids_malformed_url = array();
|
||||
$malformed_message = __( 'An error occurred: malformed social links', 'hueman');
|
||||
|
||||
if ( empty( $socials ) )
|
||||
return array();
|
||||
|
||||
|
||||
//(
|
||||
// [0] => Array
|
||||
// (
|
||||
// [is_mod_opt] => 1
|
||||
// [module_id] => tc_social_links_czr_module
|
||||
// [social-size] => 15
|
||||
// )
|
||||
|
||||
// [1] => Array
|
||||
// (
|
||||
// [id] => czr_social_module_0
|
||||
// [title] => Follow us on Renren
|
||||
// [social-icon] => fa-renren
|
||||
// [social-link] => http://customizr-dev.dev/feed/rss/
|
||||
// [social-color] => #6d4c8e
|
||||
// [social-target] => 1
|
||||
// )
|
||||
// )
|
||||
//validate urls
|
||||
foreach ( $socials as $index => $item_or_modopt ) {
|
||||
if ( ! is_array( $item_or_modopt ) )
|
||||
return new WP_Error( 'required', $malformed_message );
|
||||
|
||||
//should be an item or a mod opt
|
||||
if ( ! array_key_exists( 'is_mod_opt', $item_or_modopt ) && ! array_key_exists( 'id', $item_or_modopt ) )
|
||||
return new WP_Error( 'required', $malformed_message );
|
||||
|
||||
//if modopt case, skip
|
||||
if ( array_key_exists( 'is_mod_opt', $item_or_modopt ) )
|
||||
continue;
|
||||
|
||||
if ( $item_or_modopt['social-link'] != esc_url_raw( $item_or_modopt['social-link'] ) )
|
||||
array_push( $ids_malformed_url, $item_or_modopt[ 'id' ] );
|
||||
}
|
||||
|
||||
if ( empty( $ids_malformed_url) )
|
||||
return null;
|
||||
|
||||
return new WP_Error( 'required', __( 'Please fill the social link inputs with a valid URLs', 'hueman' ), $ids_malformed_url );
|
||||
}
|
||||
|
||||
+973
@@ -0,0 +1,973 @@
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
initialize: function( id, constructorOptions ) {
|
||||
var module = this;
|
||||
|
||||
api.CZRDynModule.prototype.initialize.call( this, id, constructorOptions );
|
||||
|
||||
//extend the module with new template Selectors
|
||||
$.extend( module, {
|
||||
itemPreAddEl : 'czr-module-widgets-pre-add-view-content',
|
||||
itemInputList : 'czr-module-widgets-item-input-list',
|
||||
ruItemPart : 'czr-module-widgets-ru-item-part'
|
||||
} );
|
||||
|
||||
//EXTEND THE DEFAULT CONSTRUCTORS FOR INPUT
|
||||
module.inputConstructor = api.CZRInput.extend( module.CZRWZonesInputMths || {} );
|
||||
//EXTEND THE DEFAULT CONSTRUCTORS FOR MONOMODEL
|
||||
module.itemConstructor = api.CZRItem.extend( module.CZRWZonesItemConstructor || {} );
|
||||
|
||||
module.serverParams = widgetModuleLocalized || {};
|
||||
|
||||
//add a shortcut to the server side json properties
|
||||
module.contexts = _.has( module.serverParams , 'sidebar_contexts') ? module.serverParams.sidebar_contexts : {};
|
||||
|
||||
//context match map
|
||||
module.context_match_map = {
|
||||
is_404 : '404',
|
||||
is_category : 'archive-category',
|
||||
is_home : 'home',
|
||||
is_page : 'page',
|
||||
is_search : 'search',
|
||||
is_single : 'single'
|
||||
};
|
||||
|
||||
|
||||
module.locations = _.has( module.serverParams , 'sidebar_locations') ? module.serverParams.sidebar_locations : {};
|
||||
|
||||
//declares a default model
|
||||
module.defaultItemModel = {
|
||||
id : '',
|
||||
title : widgetModuleLocalized.i18n.widgetZone,
|
||||
contexts : _.without( _.keys(module.contexts), '_all_' ),//the server list of contexts is an object, we only need the keys, whitout _all_
|
||||
locations : [ module.serverParams.defaultWidgetLocation ],
|
||||
description : ''
|
||||
};
|
||||
|
||||
//overrides the default success message
|
||||
this.itemAddedMessage = widgetModuleLocalized.i18n.widgetZoneAdded;
|
||||
|
||||
//Observe and react to sidebar insights from the preview frame
|
||||
// SIDEBAR INSIGHTS => stores and observes the sidebars and widgets settings sent by the preview */
|
||||
if ( ! _.has( api, 'sidebar_insights' ) ) {
|
||||
api.sidebar_insights = new api.Values();
|
||||
api.sidebar_insights.create('candidates');//will store the sidebar candidates on preview refresh
|
||||
api.sidebar_insights.create('actives');//will record the refreshed active list of active sidebars sent from the preview
|
||||
api.sidebar_insights.create('inactives');
|
||||
api.sidebar_insights.create('registered');
|
||||
api.sidebar_insights.create('available_locations');
|
||||
}
|
||||
|
||||
|
||||
this.listenToSidebarInsights();
|
||||
|
||||
//React on 'houston-widget-settings'
|
||||
//actives : data.renderedSidebars,
|
||||
// inactives : _inactives,
|
||||
// registered : _registered,
|
||||
// candidates : _candidates,
|
||||
// available_locations : data.availableWidgetLocations//built server side
|
||||
api.czr_widgetZoneSettings = api.czr_widgetZoneSettings || new api.Value();
|
||||
api.czr_widgetZoneSettings.bind( function( updated_data_sent_from_preview , from ) {
|
||||
//console.log('REACT ON czr_widgetZoneSettings', updated_data_sent_from_preview , from );
|
||||
module.isReady.then( function() {
|
||||
_.each( updated_data_sent_from_preview, function( _data, _key ) {
|
||||
api.sidebar_insights( _key ).set( _data );
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
//AVAILABLE LOCATIONS FOR THE PRE MODEL
|
||||
//1) add an observable value to module.preItem to handle the alert visibility
|
||||
module.preItem_location_alert_view_state = new api.Value( 'closed');
|
||||
//2) add state listeners
|
||||
module.preItem_location_alert_view_state.callbacks.add( function( to, from ) {
|
||||
module._toggleLocationAlertExpansion( module.container, to );
|
||||
});
|
||||
|
||||
|
||||
//REACT ON ADD / REMOVE ITEMS
|
||||
module.bind( 'item-added', function( model ) {
|
||||
module.addWidgetSidebar( model );
|
||||
});
|
||||
|
||||
module.bind( 'pre_item_api_remove' , function(model) {
|
||||
module.removeWidgetSidebar( model );
|
||||
});
|
||||
|
||||
|
||||
//records the top margin value of the widgets panel on each expansion
|
||||
var fixTopMargin = new api.Values();
|
||||
fixTopMargin.create('fixed_for_current_session');
|
||||
fixTopMargin.create('value');
|
||||
|
||||
api.section(module.serverParams.dynWidgetSection).fixTopMargin = fixTopMargin;
|
||||
api.section(module.serverParams.dynWidgetSection).fixTopMargin('fixed_for_current_session').set(false);
|
||||
|
||||
|
||||
//setup reactions on widget section expansion
|
||||
//change the expanded behaviour for the widget zone section
|
||||
//api.section(module.serverParams.dynWidgetSection).expanded.callbacks.add( function() { return module.widgetSectionReact.apply(module, arguments ); } );
|
||||
|
||||
//bind actions on widget panel expansion and widget zone section expansion
|
||||
//Fire the module
|
||||
api.panel('widgets').expanded.callbacks.add( function(to, from) {
|
||||
module.widgetPanelReact();//setup some visual adjustments, must be ran each time panel is closed or expanded
|
||||
|
||||
//Fire the module if not done already
|
||||
if ( 'resolved' == module.isReady.state() )
|
||||
return;
|
||||
module.ready();
|
||||
});
|
||||
},//initialize
|
||||
|
||||
|
||||
|
||||
|
||||
//When the control is embedded on the page, this method is fired in api.CZRBaseModuleControl:ready()
|
||||
//=> right after the module is instantiated.
|
||||
//VERIFIED
|
||||
ready : function() {
|
||||
var module = this;
|
||||
api.CZRDynModule.prototype.ready.call( module );
|
||||
|
||||
//add state listener on pre Item view
|
||||
module.preItemExpanded.callbacks.add( function( to, from ) {
|
||||
if ( ! to )
|
||||
return;
|
||||
//refresh the location list
|
||||
module.preItem.czr_Input( 'locations' )._setupLocationSelect( true );//true for refresh
|
||||
//refresh the location alert message
|
||||
module.preItem.czr_Input( 'locations' ).mayBeDisplayModelAlert();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
//overrides parent method
|
||||
//adds the default widget zones in the items
|
||||
//VERIFIED
|
||||
initializeModuleModel : function( constructorOptions ) {
|
||||
var module = this, dfd = $.Deferred();
|
||||
constructorOptions.items = _.union( _.has( module.serverParams, 'default_zones' ) ? module.serverParams.default_zones : [], constructorOptions.items );
|
||||
return dfd.resolve( constructorOptions ).promise();
|
||||
},
|
||||
|
||||
|
||||
});//$.extend()
|
||||
|
||||
})( wp.customize , jQuery, _ );//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
|
||||
CZRWZonesInputMths : {
|
||||
ready : function() {
|
||||
var input = this;
|
||||
|
||||
input.bind('locations:changed', function(){
|
||||
input.mayBeDisplayModelAlert();
|
||||
});
|
||||
|
||||
api.CZRInput.prototype.ready.call( input);
|
||||
},
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
///SETUP SELECTS
|
||||
//////////////////////////////////////////////////
|
||||
//setup select on view_rendered|item_content_event_map
|
||||
setupSelect : function() {
|
||||
var input = this;
|
||||
if ( 'locations' == this.id )
|
||||
this._setupLocationSelect();
|
||||
if ( 'contexts' == this.id )
|
||||
this._setupContextSelect();
|
||||
|
||||
},
|
||||
|
||||
//helper
|
||||
_setupContextSelect : function() {
|
||||
var input = this,
|
||||
input_contexts = input(),
|
||||
item = input.input_parent,
|
||||
module = input.module;
|
||||
|
||||
//generates the contexts options
|
||||
_.each( module.contexts, function( title, key ) {
|
||||
var _attributes = {
|
||||
value : key,
|
||||
html: title
|
||||
};
|
||||
if ( key == input_contexts || _.contains( input_contexts, key ) )
|
||||
$.extend( _attributes, { selected : "selected" } );
|
||||
|
||||
$( 'select[data-czrtype="contexts"]', input.container ).append( $('<option>', _attributes) );
|
||||
});
|
||||
//fire czrSelect2
|
||||
$( 'select[data-czrtype="contexts"]', input.container ).czrSelect2();
|
||||
},
|
||||
|
||||
|
||||
//helper
|
||||
//the refresh param is a bool
|
||||
_setupLocationSelect : function(refresh ) {
|
||||
var input = this,
|
||||
input_locations = input(),
|
||||
item = input.input_parent,
|
||||
module = input.module,
|
||||
available_locs = api.sidebar_insights('available_locations')();
|
||||
|
||||
//console.log('_setupLocationSelect', input(), module.locations );
|
||||
//generates the locations options
|
||||
//append them if not set yet
|
||||
if ( ! $( 'select[data-czrtype="locations"]', input.container ).children().length ) {
|
||||
_.each( module.locations, function( title, key ) {
|
||||
var _attributes = {
|
||||
value : key,
|
||||
html: title
|
||||
};
|
||||
|
||||
if ( key == input_locations || _.contains( input_locations, key ) )
|
||||
$.extend( _attributes, { selected : "selected" } );
|
||||
|
||||
$( 'select[data-czrtype="locations"]', input.container ).append( $('<option>', _attributes) );
|
||||
});
|
||||
}//if
|
||||
|
||||
function setAvailability( state ) {
|
||||
if (! state.id) { return state.text; }
|
||||
if ( _.contains(available_locs, state.element.value) ) { return state.text; }
|
||||
var $state = $(
|
||||
'<span class="czr-unavailable-location fas fa-ban" title="' + widgetModuleLocalized.i18n.unavailableLocation + '"> ' + state.text + '</span>'
|
||||
);
|
||||
return $state;
|
||||
}
|
||||
|
||||
if ( refresh ) {
|
||||
$( 'select[data-czrtype="locations"]', input.container ).czrSelect2( 'destroy' );
|
||||
}
|
||||
|
||||
//fire czrSelect2
|
||||
$( 'select[data-czrtype="locations"]', input.container ).czrSelect2( {
|
||||
templateResult: setAvailability,
|
||||
templateSelection: setAvailability
|
||||
});
|
||||
},
|
||||
|
||||
//fired on view event map : 'locations:changed'
|
||||
//@param obj { dom_el: $() , model : {} )
|
||||
mayBeDisplayModelAlert : function() {
|
||||
var input = this,
|
||||
item = input.input_parent,
|
||||
module = input.module;
|
||||
|
||||
//check if we are in the pre Item case => if so, the locations might be empty
|
||||
if ( ! _.has( item(), 'locations') || _.isEmpty( item().locations ) )
|
||||
return;
|
||||
|
||||
var _selected_locations = $('select[data-czrtype="locations"]', input.container ).val(),
|
||||
available_locs = api.sidebar_insights('available_locations')(),
|
||||
_unavailable = _.filter( _selected_locations, function( loc ) {
|
||||
return ! _.contains(available_locs, loc);
|
||||
});
|
||||
|
||||
//check if we are in the pre Item case => if so, the id is empty
|
||||
if ( ! _.has( item(), 'id' ) || _.isEmpty( item().id ) ) {
|
||||
module.preItem_location_alert_view_state.set( ! _.isEmpty( _unavailable ) ? 'expanded' : 'closed' );
|
||||
} else {
|
||||
item.czr_itemLocationAlert.set( ! _.isEmpty( _unavailable ) ? 'expanded' : 'closed' );
|
||||
}
|
||||
}
|
||||
},//CZRWZonesInputMths
|
||||
|
||||
});//$.extend()
|
||||
|
||||
})( wp.customize , jQuery, _ );//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
CZRWZonesItemConstructor : {
|
||||
initialize : function( id, options ) {
|
||||
var item = this,
|
||||
module = item.module;
|
||||
|
||||
//Add some observable values for this item
|
||||
item.czr_itemLocationAlert = new api.Value();
|
||||
|
||||
api.CZRItem.prototype.initialize.call( item, null, options );
|
||||
|
||||
// filter the params of the ajax query used to get the item wrapper template
|
||||
// because we need a ru ( not a read update delete ) template for builtins widget zones
|
||||
// requestParams = {
|
||||
// tmpl : 'rud-item-part',
|
||||
// module_type: 'all_modules',
|
||||
// nonce: api.settings.nonce.save//<= do we need to set a specific nonce to fetch the tmpls ?
|
||||
// };
|
||||
// this has been introduced in March 2018, after the introduction of the tmpl ajax fetching
|
||||
// it does the same job that the overriden getTemplateEl() was doing.
|
||||
// This filter is declared in item::renderItemWrapper()
|
||||
item.bind( 'item-wrapper-tmpl-params-before-fetching', function( requestParams ) {
|
||||
//force view-content type to ru-item-part if the model is a built-in (primary, secondary, footer-1, ...)
|
||||
//=> user can't delete a built-in model.
|
||||
requestParams.tmpl = ( _.has( item(), 'is_builtin' ) && item().is_builtin ) ? 'ruItemPart' : requestParams.tmpl;
|
||||
return requestParams;
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
//extend parent setupview
|
||||
itemWrapperViewSetup : function() {
|
||||
var item = this,
|
||||
module = item.module;
|
||||
|
||||
api.CZRItem.prototype.itemWrapperViewSetup.call(item);
|
||||
|
||||
/// ALERT FOR NOT AVAILABLE LOCATION
|
||||
item.czr_itemLocationAlert.set('closed');
|
||||
|
||||
//add a state listener on expansion change
|
||||
item.czr_itemLocationAlert.callbacks.add( function( to, from ) {
|
||||
module._toggleLocationAlertExpansion( item.container , to );
|
||||
});
|
||||
|
||||
//update item title
|
||||
item.writeSubtitleInfos(item());
|
||||
|
||||
//this is fired just after the itemWrapperViewSetupApiListeners
|
||||
//=> add a callback to refresh the availability status of the locations in the select location picker
|
||||
//add a state listener on expansion change
|
||||
item.viewState.callbacks.add( function( to, from ) {
|
||||
if ( -1 == to.indexOf('expanded') )//can take the expanded_noscroll value !
|
||||
return;
|
||||
//don't try to invoke the input instances before the content is actually rendered
|
||||
//=> there might be cases when the content rendering is debounced...
|
||||
item.bind('contentRendered', function() {
|
||||
//refresh the location list
|
||||
item.czr_Input('locations')._setupLocationSelect( true );//true for refresh
|
||||
//refresh the location alert message
|
||||
item.czr_Input('locations').mayBeDisplayModelAlert();
|
||||
});
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
//extend parent listener
|
||||
itemReact : function(to, from) {
|
||||
var item = this;
|
||||
api.CZRItem.prototype.itemReact.call(item, to, from);
|
||||
|
||||
item.writeSubtitleInfos(to);
|
||||
item.updateSectionTitle(to).setModelUpdateTimer();
|
||||
},
|
||||
|
||||
|
||||
|
||||
//Fired in setupItemListeners. Reacts to model change.
|
||||
//Write html informations under the title : location(s) and context(s)
|
||||
writeSubtitleInfos : function(model) {
|
||||
var item = this,
|
||||
module = item.module,
|
||||
_model = _.clone( model || item() ),
|
||||
_locations = [],
|
||||
_contexts = [],
|
||||
_html = '';
|
||||
|
||||
if ( ! item.container.length )
|
||||
return this;
|
||||
|
||||
//generate the locations and the contexts text from the json data if exists
|
||||
_model.locations =_.isString(_model.locations) ? [_model.locations] : _model.locations;
|
||||
_.each( _model.locations, function( loc ) {
|
||||
if ( _.has( module.locations , loc ) )
|
||||
_locations.push(module.locations[loc]);
|
||||
else
|
||||
_locations.push(loc);
|
||||
}
|
||||
);
|
||||
|
||||
//build the context list
|
||||
_model.contexts =_.isString(_model.contexts) ? [_model.contexts] : _model.contexts;
|
||||
|
||||
//all contexts cases ?
|
||||
if ( item._hasModelAllContexts( model ) ) {
|
||||
_contexts.push(module.contexts._all_);
|
||||
} else {
|
||||
_.each( _model.contexts, function( con ) {
|
||||
if ( _.has( module.contexts , con ) )
|
||||
_contexts.push(module.contexts[con]);
|
||||
else
|
||||
_contexts.push(con);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
//Translated strings
|
||||
var _locationText = widgetModuleLocalized.i18n.locations,
|
||||
_contextText = widgetModuleLocalized.i18n.contexts,
|
||||
_notsetText = widgetModuleLocalized.i18n.notset;
|
||||
|
||||
_locations = _.isEmpty( _locations ) ? '<span style="font-weight: bold;">' + _notsetText + '</span>' : _locations.join(', ');
|
||||
_contexts = _.isEmpty( _contexts ) ? '<span style="font-weight: bold;">' + _notsetText + '</span>' : _contexts.join(', ');
|
||||
|
||||
//write the description if builtin
|
||||
//else, write the dynamic location
|
||||
// if ( _.has(_model, 'description') && _.has(_model, 'is_builtin') )
|
||||
// _html = _model.description + ' <strong>|</strong> <u>Contexts</u> : ' + _contexts;
|
||||
// else
|
||||
|
||||
_html = '<u>' + _locationText + '</u> : ' + _locations + ' <strong>|</strong> <u>' + _contextText + '</u> : ' + _contexts;
|
||||
|
||||
if ( ! $('.czr-zone-infos', item.container ).length ) {
|
||||
var $_zone_infos = $('<div/>', {
|
||||
class : [ 'czr-zone-infos' , module.control.css_attr.item_sort_handle ].join(' '),
|
||||
html : _html
|
||||
});
|
||||
$( '.' + module.control.css_attr.item_btns, item.container ).after($_zone_infos);
|
||||
} else {
|
||||
$('.czr-zone-infos', item.container ).html(_html);
|
||||
}
|
||||
|
||||
return this;
|
||||
},//writeSubtitleInfos
|
||||
|
||||
|
||||
|
||||
////Fired in setupItemListeners
|
||||
updateSectionTitle : function(model) {
|
||||
var _sidebar_id = 'sidebar-widgets-' + model.id,
|
||||
_new_title = model.title;
|
||||
//does this section exists ?
|
||||
if ( ! api.section.has(_sidebar_id) )
|
||||
return this;
|
||||
|
||||
//update the section title
|
||||
$('.accordion-section-title', api.section(_sidebar_id).container ).text(_new_title);
|
||||
|
||||
//update the top title ( visible when inside the expanded section )
|
||||
$('.customize-section-title h3', api.section(_sidebar_id).container ).html(
|
||||
'<span class="customize-action">' + api.section(_sidebar_id).params.customizeAction + '</span>' + _new_title
|
||||
);
|
||||
// $('.customize-section-title h3', api.section(_sidebar_id).container )
|
||||
// .append('<span>', {
|
||||
// class: 'customize-section-back',
|
||||
// html: api.section(_sidebar_id).params.customizeAction
|
||||
// } )
|
||||
// .append(_new_title);
|
||||
|
||||
//remove and re-instanciate
|
||||
//=> works for the section but the controls are not activated anymore.
|
||||
//Should be easy to fix but useless to go further here. Jquery does the job.
|
||||
// var _params = _.clone( api.section(_sidebar_id).params );
|
||||
// _params.title = _new_title;
|
||||
// api.section(_sidebar_id).container.remove();
|
||||
// api.section.remove(_sidebar_id);
|
||||
// api.section.add( _sidebar_id, new api.sectionConstructor[_params.type]( _params.id ,{ params : _params } ) );
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
//fired on model_update
|
||||
//Don't hammer the preview with too many refreshs
|
||||
//2 seconds delay
|
||||
setModelUpdateTimer : function() {
|
||||
var item = this,
|
||||
module = item.module;
|
||||
|
||||
clearTimeout( $.data(this, 'modelUpdateTimer') );
|
||||
$.data(
|
||||
this,
|
||||
'modelUpdateTimer',
|
||||
_.delay( function() {
|
||||
//refresh preview
|
||||
api.previewer.refresh();
|
||||
} , 1000)
|
||||
);//$.data
|
||||
},
|
||||
|
||||
|
||||
//@return bool
|
||||
//takes the model unique id
|
||||
_hasModelAllContexts : function( model ) {
|
||||
var item = this,
|
||||
module = item.module,
|
||||
moduleContexts = _.keys(module.contexts);
|
||||
|
||||
model = model || this();
|
||||
|
||||
if ( ! _.has(model, 'contexts') )
|
||||
return;
|
||||
|
||||
if ( _.contains( model.contexts, '_all_') )
|
||||
return true;
|
||||
|
||||
//case when model does not have _all_ but all the others
|
||||
return _.isEmpty( _.difference( _.without(moduleContexts, '_all_') , model.contexts ) );
|
||||
},
|
||||
|
||||
//@param contexts = array of contexts
|
||||
//api.czr_wpQueryInfos is refreshed on each preview refresh
|
||||
_getMatchingContexts : function( defaults ) {
|
||||
var module = this,
|
||||
_current = api.czr_wpQueryInfos().conditional_tags || {},
|
||||
_matched = _.filter( module.context_match_map, function( hu, wp ) { return true === _current[wp]; } );
|
||||
|
||||
return _.isEmpty( _matched ) ? defaults : _matched;
|
||||
}
|
||||
},//CZRWZonesItemConstructor
|
||||
|
||||
});//$.extend()
|
||||
|
||||
})( wp.customize , jQuery, _ );//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
/////////////////////////////////////////
|
||||
/// ADD / REMOVE WIDGET ZONES
|
||||
////////////////////////////////////////
|
||||
//fired on model_added_by_user
|
||||
//
|
||||
//can also be called statically when a dynamic sidebar is added in the preview
|
||||
//in this case the parameter are the sidebar data with id and name
|
||||
addWidgetSidebar : function( model, sidebar_data ) {
|
||||
if ( ! _.isObject(model) && _.isEmpty(sidebar_data) ) {
|
||||
throw new Error('No valid input were provided to add a new Widget Zone.');
|
||||
}
|
||||
|
||||
|
||||
//ADD the new sidebar to the existing collection
|
||||
//Clone the serverControlParams.defaultWidgetSidebar sidebar
|
||||
var module = this,
|
||||
_model = ! _.isEmpty(model) ? _.clone(model) : sidebar_data,
|
||||
_new_sidebar = _.isEmpty(model) ? sidebar_data : $.extend(
|
||||
_.clone( _.findWhere( api.Widgets.data.registeredSidebars, { id: module.serverParams.defaultWidgetSidebar } ) ),
|
||||
{
|
||||
name : _model.title,
|
||||
id : _model.id
|
||||
}
|
||||
);
|
||||
|
||||
//Add it to the backbone collection
|
||||
api.Widgets.registeredSidebars.add( _new_sidebar );
|
||||
|
||||
//test if added:
|
||||
//api.Widgets.registeredSidebars('czr_sidebars_8');
|
||||
|
||||
|
||||
//ADD the sidebar section
|
||||
var _params = $.extend(
|
||||
_.clone( api.section( "sidebar-widgets-" + module.serverParams.defaultWidgetSidebar ).params ),
|
||||
{
|
||||
id : "sidebar-widgets-" + _model.id,
|
||||
instanceNumber: _.max(api.settings.sections, function(sec){ return sec.instanceNumber; }).instanceNumber + 1,
|
||||
sidebarId: _new_sidebar.id,
|
||||
title: _new_sidebar.name,
|
||||
description : 'undefined' != typeof(sidebar_data) ? sidebar_data.description : api.section( "sidebar-widgets-" + module.serverParams.defaultWidgetSidebar ).params.description,
|
||||
//always set the new priority to the maximum + 1 ( module.serverParams.dynWidgetSection is excluded from this calculation because it must always be at the bottom )
|
||||
priority: _.max( _.omit( api.settings.sections, module.serverParams.dynWidgetSection), function(sec){ return sec.instanceNumber; }).priority + 1,
|
||||
}
|
||||
);
|
||||
|
||||
api.section.add( _params.id, new api.sectionConstructor[ _params.type ]( _params.id ,{ params : _params } ) );
|
||||
|
||||
//add it to the static collection of settings
|
||||
api.settings.sections[ _params.id ] = _params.id;
|
||||
|
||||
//ADD A SETTING
|
||||
//Clone the module.serverParams.defaultWidgetSidebar sidebar widget area setting
|
||||
var _new_set_id = 'sidebars_widgets['+_model.id+']',
|
||||
_new_set = $.extend(
|
||||
_.clone( api.settings.settings['sidebars_widgets[' + module.serverParams.defaultWidgetSidebar + ']'] ),
|
||||
{
|
||||
value:[]
|
||||
}
|
||||
);
|
||||
|
||||
//add it to the static collection of settings
|
||||
api.settings.settings[ _new_set_id ] = _new_set;
|
||||
|
||||
//instanciate it
|
||||
api.create( _new_set_id, _new_set_id, _new_set.value, {
|
||||
transport: _new_set.transport,
|
||||
previewer: api.previewer,
|
||||
dirty: false
|
||||
} );
|
||||
|
||||
|
||||
|
||||
//ADD A CONTROL
|
||||
var _cloned_control = $.extend(
|
||||
_.clone( api.settings.controls['sidebars_widgets[' + module.serverParams.defaultWidgetSidebar + ']'] ),
|
||||
{
|
||||
settings : { default : _new_set_id }
|
||||
}),
|
||||
_new_control = {};
|
||||
|
||||
|
||||
//replace serverControlParams.defaultWidgetSidebar by the new sidebar id
|
||||
_.each( _cloned_control, function( param, key ) {
|
||||
if ( 'string' == typeof(param) ) {
|
||||
param = param.replace( module.serverParams.defaultWidgetSidebar , _model.id );
|
||||
}
|
||||
_new_control[key] = param;
|
||||
});
|
||||
|
||||
//set the instance number (no sure if needed)
|
||||
_new_control.instanceNumber = _.max(api.settings.controls, function(con){ return con.instanceNumber; }).instanceNumber + 1;
|
||||
|
||||
//add it to the static collection of controls
|
||||
api.settings.controls[_new_set_id] = _new_control;
|
||||
|
||||
//instanciate it
|
||||
api.control.add( _new_set_id, new api.controlConstructor[ _new_control.type ]( _new_set_id, {
|
||||
params: _new_control,
|
||||
previewer: api.previewer
|
||||
} ) );
|
||||
|
||||
|
||||
//say it to the control container
|
||||
//only if we are in an instanciated object => because this method can be accessed statically
|
||||
if ( _.has(this, 'container') )
|
||||
this.container.trigger( 'widget_zone_created', { model : _model, section_id : "sidebar-widgets-" + _model.id , setting_id : _new_set_id });
|
||||
},//addWidgetSidebar
|
||||
|
||||
|
||||
//fired on "after_modelRemoved"
|
||||
removeWidgetSidebar : function( model ) {
|
||||
var module = this;
|
||||
if ( ! _.isObject(model) || _.isEmpty(model) ) {
|
||||
throw new Error('No valid data were provided to remove a Widget Zone.');
|
||||
}
|
||||
|
||||
//Remove this sidebar from the backbone collection
|
||||
api.Widgets.registeredSidebars.remove( model.id );
|
||||
|
||||
//remove the section from the api values and the DOM if exists
|
||||
if ( api.section.has("sidebar-widgets-" + model.id) ) {
|
||||
//Remove the section container from the DOM
|
||||
api.section("sidebar-widgets-" + model.id).container.remove();
|
||||
//Remove the sidebar section from the api
|
||||
api.section.remove( "sidebar-widgets-" + model.id );
|
||||
//Remove this section from the static collection
|
||||
delete api.settings.sections[ "sidebar-widgets-" + model.id ];
|
||||
}
|
||||
|
||||
//remove the setting from the api if exists
|
||||
if ( api.has('sidebars_widgets['+model.id+']') ) {
|
||||
//Remove this setting from the api
|
||||
api.remove( 'sidebars_widgets['+model.id+']' );
|
||||
//Remove this setting from the static collection
|
||||
delete api.settings.settings['sidebars_widgets['+model.id+']'];
|
||||
}
|
||||
|
||||
//remove the widget control of this sidebar from the api and the DOM if exists
|
||||
if ( api.control.has('sidebars_widgets['+model.id+']') ) {
|
||||
//Remove the control container from the DOM
|
||||
api.control( 'sidebars_widgets['+model.id+']' ).container.remove();
|
||||
//Remove this control from the api
|
||||
api.control.remove( 'sidebars_widgets['+model.id+']' );
|
||||
//Remove it to the static collection of controls
|
||||
delete api.settings.controls['sidebars_widgets['+model.id+']'];
|
||||
}
|
||||
|
||||
//refresh
|
||||
var _refresh = function() {
|
||||
api.previewer.refresh();
|
||||
};
|
||||
_refresh = _.debounce( _refresh, 500 );
|
||||
$.when( _refresh() ).done( function() {
|
||||
//say it
|
||||
module.trigger( 'widget_zone_removed',
|
||||
{
|
||||
model : model,
|
||||
section_id : "sidebar-widgets-" + model.id ,
|
||||
setting_id : 'sidebars_widgets['+model.id+']'
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
});//$.extend()
|
||||
|
||||
})( wp.customize , jQuery, _ );
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
|
||||
/////////////////////////////////////////
|
||||
/// SET EXPANSION CALLBACKS FOR WIDGET PANEL AND WIDGET ZONE CREATION SECTION
|
||||
////////////////////////////////////////
|
||||
//cb of : api.panel('widgets').expanded.callbacks.add
|
||||
widgetPanelReact : function() {
|
||||
var module = this;
|
||||
//will be used for adjustments
|
||||
var _top_margin = api.panel('widgets').container.find( '.control-panel-content' ).css('margin-top');
|
||||
|
||||
api.section(module.serverParams.dynWidgetSection).fixTopMargin('value').set( _top_margin );
|
||||
|
||||
var _section_content = api.section(module.serverParams.dynWidgetSection).container.find( '.accordion-section-content' ),
|
||||
_panel_content = api.panel('widgets').container.find( '.control-panel-content' ),
|
||||
_set_margins = function() {
|
||||
_section_content.css( 'margin-top', '' );
|
||||
_panel_content.css('margin-top', api.section(module.serverParams.dynWidgetSection).fixTopMargin('value')() );
|
||||
};
|
||||
|
||||
// Fix the top margin after reflow.
|
||||
api.bind( 'pane-contents-reflowed', _.debounce( function() {
|
||||
_set_margins();
|
||||
}, 150 ) );
|
||||
|
||||
//Close all views on widget panel expansion/clos
|
||||
module.closeAllItems().closeRemoveDialogs();
|
||||
//Close preItem dialog box if exists
|
||||
if ( _.has( module, 'preItemExpanded' ) )
|
||||
module.preItemExpanded.set(false);
|
||||
},//widgetPanelReact()
|
||||
|
||||
|
||||
//cb of api.section(module.serverParams.dynWidgetSection).expanded.callbacks
|
||||
widgetSectionReact : function( to, from ) {
|
||||
var module = this,
|
||||
section = api.section(module.serverParams.dynWidgetSection),
|
||||
container = section.container.closest( '.wp-full-overlay-sidebar-content' ),
|
||||
content = section.container.find( '.accordion-section-content' ),
|
||||
overlay = section.container.closest( '.wp-full-overlay' ),
|
||||
backBtn = section.container.find( '.customize-section-back' ),
|
||||
sectionTitle = section.container.find( '.accordion-section-title' ).first(),
|
||||
headerActionsHeight = $( '#customize-header-actions' ).height(),
|
||||
resizeContentHeight, expand, position, scroll;
|
||||
|
||||
if ( to ) {
|
||||
overlay.removeClass( 'section-open' );
|
||||
content.css( 'height', 'auto' );
|
||||
//section.container.removeClass( 'open' );
|
||||
sectionTitle.attr( 'tabindex', '0' );
|
||||
content.css( 'margin-top', '' );
|
||||
container.scrollTop( 0 );
|
||||
}
|
||||
|
||||
module.closeAllItems().closeRemoveDialogs();
|
||||
|
||||
content.slideToggle();
|
||||
}
|
||||
});//$.extend()
|
||||
})( wp.customize , jQuery, _ );
|
||||
|
||||
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
|
||||
/////////////////////////////////////////
|
||||
/// LISTEN TO SIDEBAR INSIGHTS FROM THE PREVIEW FRAME
|
||||
/// REACT TO THEM
|
||||
////////////////////////////////////////
|
||||
listenToSidebarInsights : function() {
|
||||
var module = this;
|
||||
|
||||
//VISIBILITY BASED ON THE SIDEBAR INSIGHTS
|
||||
api.sidebar_insights('registered').callbacks.add( function( _registered_zones ) {
|
||||
var _current_collection = _.clone( module.itemCollection() );
|
||||
_.each( _current_collection, function( _model ) {
|
||||
if ( ! module.getViewEl(_model.id).length )
|
||||
return;
|
||||
|
||||
module.getViewEl(_model.id).css('display' , _.contains( _registered_zones, _model.id ) ? 'block' : 'none' );
|
||||
});
|
||||
});
|
||||
|
||||
//OPACITY SIDEBAR INSIGHTS BASED
|
||||
api.sidebar_insights('inactives').callbacks.add( function( _inactives_zones ) {
|
||||
var _current_collection = _.clone( module.itemCollection() );
|
||||
_.each( _current_collection, function( _model ) {
|
||||
if ( ! module.getViewEl(_model.id).length )
|
||||
return;
|
||||
|
||||
if ( _.contains( _inactives_zones, _model.id ) ) {
|
||||
module.getViewEl( _model.id ).addClass('inactive');
|
||||
if ( ! module.getViewEl( _model.id ).find('.czr-inactive-alert').length ) {
|
||||
module.getViewEl( _model.id ).find('.czr-item-title').append(
|
||||
$('<span/>', {class : "czr-inactive-alert", html : " [ " + widgetModuleLocalized.i18n.inactiveWidgetZone + " ]" })
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
module.getViewEl( _model.id ).removeClass('inactive');
|
||||
if ( module.getViewEl( _model.id ).find('.czr-inactive-alert').length )
|
||||
module.getViewEl( _model.id ).find('.czr-inactive-alert').remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//WIDGET SIDEBAR CREATION BASED ON SIDEBAR INSIGHTS
|
||||
//react to a new register candidate(s) on preview refresh
|
||||
api.sidebar_insights('candidates').callbacks.add( function(_candidates) {
|
||||
if ( ! _.isArray(_candidates) )
|
||||
return;
|
||||
_.each( _candidates, function( _sidebar ) {
|
||||
if ( ! _.isObject(_sidebar) )
|
||||
return;
|
||||
//add this widget sidebar and the related setting and control.
|
||||
//Only if not added already
|
||||
if ( api.section.has("sidebar-widgets-" +_sidebar.id ) )
|
||||
return;
|
||||
|
||||
//access the registration method statically
|
||||
module.addWidgetSidebar( {}, _sidebar );
|
||||
//activate it if so
|
||||
if ( _.has( api.sidebar_insights('actives')(), _sidebar.id ) && api.section.has("sidebar-widgets-" +_sidebar.id ) )
|
||||
api.section( "sidebar-widgets-" +_sidebar.id ).activate();
|
||||
});
|
||||
});
|
||||
}//listenToSidebarInsights()
|
||||
});//$.extend()
|
||||
})( wp.customize , jQuery, _ );
|
||||
|
||||
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
/////////////////////////////////////////
|
||||
/// OVERRIDEN METHODS
|
||||
////////////////////////////////////////
|
||||
//fired in toggleItemExpansion()
|
||||
//has to be overridden for the widget zones control because this control is embedded directly in a panel and not in a section
|
||||
//therefore the module to animate the scrollTop is not the section container but $('.wp-full-overlay-sidebar-content')
|
||||
_adjustScrollExpandedBlock : function( $_block_el, adjust ) {
|
||||
if ( ! $_block_el.length )
|
||||
return;
|
||||
var module = this,
|
||||
_currentScrollTopVal = $('.wp-full-overlay-sidebar-content').scrollTop(),
|
||||
_scrollDownVal,
|
||||
_adjust = adjust || 90;
|
||||
setTimeout( function() {
|
||||
if ( ( $_block_el.offset().top + $_block_el.height() + _adjust ) > $(window.top).height() ) {
|
||||
_scrollDownVal = $_block_el.offset().top + $_block_el.height() + _adjust - $(window.top).height();
|
||||
$('.wp-full-overlay-sidebar-content').animate({
|
||||
scrollTop: _currentScrollTopVal + _scrollDownVal
|
||||
}, 600);
|
||||
}
|
||||
}, 50);
|
||||
},
|
||||
|
||||
|
||||
|
||||
//overrides the parent class default model getter
|
||||
//=> add a dynamic title
|
||||
getDefaultItemModel : function( id ) {
|
||||
var module = this,
|
||||
_current_collection = module.itemCollection(),
|
||||
_default = _.clone( module.defaultItemModel ),
|
||||
_default_contexts = _default.contexts;
|
||||
return $.extend( _default, {
|
||||
title : 'Widget Zone ' + ( _.size(_current_collection)*1 + 1 )
|
||||
//contexts : module._getMatchingContexts( _default_contexts )
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
_toggleLocationAlertExpansion : function( $view, to ) {
|
||||
var $_alert_el = $view.find('.czr-location-alert');
|
||||
if ( ! $_alert_el.length ) {
|
||||
var _html = [
|
||||
'<span>' + widgetModuleLocalized.i18n.locationWarning + '</span>',
|
||||
api.CZR_Helpers.getDocSearchLink( widgetModuleLocalized.i18n.locationWarning ),
|
||||
].join('');
|
||||
|
||||
$_alert_el = $('<div/>', {
|
||||
class:'czr-location-alert',
|
||||
html:_html,
|
||||
style:"display:none"
|
||||
});
|
||||
|
||||
$('select[data-czrtype="locations"]', $view ).closest('div').after($_alert_el);
|
||||
}
|
||||
$_alert_el.toggle( 'expanded' == to);
|
||||
}
|
||||
});//$.extend()
|
||||
})( wp.customize , jQuery, _ );
|
||||
|
||||
|
||||
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
/*****************************************************************************
|
||||
* CAPTURE PREVIEW INFORMATIONS ON REFRESH + REACT TO THEM
|
||||
*****************************************************************************/
|
||||
(function (api, $, _) {
|
||||
//Data are sent by the preview frame when the panel has sent the 'sync' or even better 'active' event
|
||||
api.bind( 'ready', function() {
|
||||
//observe widget settings changes
|
||||
api.previewer.bind('houston-widget-settings', function(data) {
|
||||
//console.log('control panel => ALORS ON HOUSTON- SETTINGS ? => ', data );
|
||||
//get the difference
|
||||
var _candidates = _.filter( data.registeredSidebars, function( sb ) {
|
||||
return ! _.findWhere( _wpCustomizeWidgetsSettings.registeredSidebars, { id: sb.id } );
|
||||
});
|
||||
|
||||
var _inactives = _.filter( data.registeredSidebars, function( sb ) {
|
||||
return ! _.has( data.renderedSidebars, sb.id );
|
||||
});
|
||||
|
||||
_inactives = _.map( _inactives, function(obj) {
|
||||
return obj.id;
|
||||
});
|
||||
|
||||
var _registered = _.map( data.registeredSidebars, function(obj) {
|
||||
return obj.id;
|
||||
});
|
||||
|
||||
//stores and update the widget zone settings
|
||||
api.czr_widgetZoneSettings = api.czr_widgetZoneSettings || new api.Value();//will store all widget zones data sent by preview as an observable object
|
||||
api.czr_widgetZoneSettings.set( {
|
||||
actives : data.renderedSidebars,
|
||||
inactives : _inactives,
|
||||
registered : _registered,
|
||||
candidates : _candidates,
|
||||
available_locations : data.availableWidgetLocations//built server side
|
||||
} );
|
||||
|
||||
});
|
||||
});//api.bind('ready')
|
||||
})( wp.customize , jQuery, _ );//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
//provides a description of each module
|
||||
//=> will determine :
|
||||
//1) how to initialize the module model. If not crud, then the initial item(s) model shall be provided
|
||||
//2) which js template(s) to use : if crud, the module template shall include the add new and pre-item elements.
|
||||
// , if crud, the item shall be removable
|
||||
//3) how to render : if multi item, the item content is rendered when user click on edit button.
|
||||
// If not multi item, the single item content is rendered as soon as the item wrapper is rendered.
|
||||
//4) some DOM behaviour. For example, a multi item shall be sortable.
|
||||
api.czrModuleMap = api.czrModuleMap || {};
|
||||
$.extend( api.czrModuleMap, {
|
||||
czr_widget_areas_module : {
|
||||
mthds : WidgetAreaConstructor,
|
||||
crud : true,
|
||||
multi_item : false,
|
||||
name : 'Widget Areas',
|
||||
has_mod_opt : false,
|
||||
ready_on_section_expanded : true,
|
||||
//defaultItemModel : {}
|
||||
}
|
||||
});
|
||||
})( wp.customize , jQuery, _ );
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
initialize: function( id, constructorOptions ) {
|
||||
var module = this;
|
||||
|
||||
api.CZRDynModule.prototype.initialize.call( this, id, constructorOptions );
|
||||
|
||||
//extend the module with new template Selectors
|
||||
$.extend( module, {
|
||||
itemPreAddEl : 'czr-module-widgets-pre-add-view-content',
|
||||
itemInputList : 'czr-module-widgets-item-input-list',
|
||||
ruItemPart : 'czr-module-widgets-ru-item-part'
|
||||
} );
|
||||
|
||||
//EXTEND THE DEFAULT CONSTRUCTORS FOR INPUT
|
||||
module.inputConstructor = api.CZRInput.extend( module.CZRWZonesInputMths || {} );
|
||||
//EXTEND THE DEFAULT CONSTRUCTORS FOR MONOMODEL
|
||||
module.itemConstructor = api.CZRItem.extend( module.CZRWZonesItemConstructor || {} );
|
||||
|
||||
module.serverParams = widgetModuleLocalized || {};
|
||||
|
||||
//add a shortcut to the server side json properties
|
||||
module.contexts = _.has( module.serverParams , 'sidebar_contexts') ? module.serverParams.sidebar_contexts : {};
|
||||
|
||||
//context match map
|
||||
module.context_match_map = {
|
||||
is_404 : '404',
|
||||
is_category : 'archive-category',
|
||||
is_home : 'home',
|
||||
is_page : 'page',
|
||||
is_search : 'search',
|
||||
is_single : 'single'
|
||||
};
|
||||
|
||||
|
||||
module.locations = _.has( module.serverParams , 'sidebar_locations') ? module.serverParams.sidebar_locations : {};
|
||||
|
||||
//declares a default model
|
||||
module.defaultItemModel = {
|
||||
id : '',
|
||||
title : widgetModuleLocalized.i18n.widgetZone,
|
||||
contexts : _.without( _.keys(module.contexts), '_all_' ),//the server list of contexts is an object, we only need the keys, whitout _all_
|
||||
locations : [ module.serverParams.defaultWidgetLocation ],
|
||||
description : ''
|
||||
};
|
||||
|
||||
//overrides the default success message
|
||||
this.itemAddedMessage = widgetModuleLocalized.i18n.widgetZoneAdded;
|
||||
|
||||
//Observe and react to sidebar insights from the preview frame
|
||||
// SIDEBAR INSIGHTS => stores and observes the sidebars and widgets settings sent by the preview */
|
||||
if ( ! _.has( api, 'sidebar_insights' ) ) {
|
||||
api.sidebar_insights = new api.Values();
|
||||
api.sidebar_insights.create('candidates');//will store the sidebar candidates on preview refresh
|
||||
api.sidebar_insights.create('actives');//will record the refreshed active list of active sidebars sent from the preview
|
||||
api.sidebar_insights.create('inactives');
|
||||
api.sidebar_insights.create('registered');
|
||||
api.sidebar_insights.create('available_locations');
|
||||
}
|
||||
|
||||
|
||||
this.listenToSidebarInsights();
|
||||
|
||||
//React on 'houston-widget-settings'
|
||||
//actives : data.renderedSidebars,
|
||||
// inactives : _inactives,
|
||||
// registered : _registered,
|
||||
// candidates : _candidates,
|
||||
// available_locations : data.availableWidgetLocations//built server side
|
||||
api.czr_widgetZoneSettings = api.czr_widgetZoneSettings || new api.Value();
|
||||
api.czr_widgetZoneSettings.bind( function( updated_data_sent_from_preview , from ) {
|
||||
//console.log('REACT ON czr_widgetZoneSettings', updated_data_sent_from_preview , from );
|
||||
module.isReady.then( function() {
|
||||
_.each( updated_data_sent_from_preview, function( _data, _key ) {
|
||||
api.sidebar_insights( _key ).set( _data );
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
//AVAILABLE LOCATIONS FOR THE PRE MODEL
|
||||
//1) add an observable value to module.preItem to handle the alert visibility
|
||||
module.preItem_location_alert_view_state = new api.Value( 'closed');
|
||||
//2) add state listeners
|
||||
module.preItem_location_alert_view_state.callbacks.add( function( to, from ) {
|
||||
module._toggleLocationAlertExpansion( module.container, to );
|
||||
});
|
||||
|
||||
|
||||
//REACT ON ADD / REMOVE ITEMS
|
||||
module.bind( 'item-added', function( model ) {
|
||||
module.addWidgetSidebar( model );
|
||||
});
|
||||
|
||||
module.bind( 'pre_item_api_remove' , function(model) {
|
||||
module.removeWidgetSidebar( model );
|
||||
});
|
||||
|
||||
|
||||
//records the top margin value of the widgets panel on each expansion
|
||||
var fixTopMargin = new api.Values();
|
||||
fixTopMargin.create('fixed_for_current_session');
|
||||
fixTopMargin.create('value');
|
||||
|
||||
api.section(module.serverParams.dynWidgetSection).fixTopMargin = fixTopMargin;
|
||||
api.section(module.serverParams.dynWidgetSection).fixTopMargin('fixed_for_current_session').set(false);
|
||||
|
||||
|
||||
//setup reactions on widget section expansion
|
||||
//change the expanded behaviour for the widget zone section
|
||||
//api.section(module.serverParams.dynWidgetSection).expanded.callbacks.add( function() { return module.widgetSectionReact.apply(module, arguments ); } );
|
||||
|
||||
//bind actions on widget panel expansion and widget zone section expansion
|
||||
//Fire the module
|
||||
api.panel('widgets').expanded.callbacks.add( function(to, from) {
|
||||
module.widgetPanelReact();//setup some visual adjustments, must be ran each time panel is closed or expanded
|
||||
|
||||
//Fire the module if not done already
|
||||
if ( 'resolved' == module.isReady.state() )
|
||||
return;
|
||||
module.ready();
|
||||
});
|
||||
},//initialize
|
||||
|
||||
|
||||
|
||||
|
||||
//When the control is embedded on the page, this method is fired in api.CZRBaseModuleControl:ready()
|
||||
//=> right after the module is instantiated.
|
||||
//VERIFIED
|
||||
ready : function() {
|
||||
var module = this;
|
||||
api.CZRDynModule.prototype.ready.call( module );
|
||||
|
||||
//add state listener on pre Item view
|
||||
module.preItemExpanded.callbacks.add( function( to, from ) {
|
||||
if ( ! to )
|
||||
return;
|
||||
//refresh the location list
|
||||
module.preItem.czr_Input( 'locations' )._setupLocationSelect( true );//true for refresh
|
||||
//refresh the location alert message
|
||||
module.preItem.czr_Input( 'locations' ).mayBeDisplayModelAlert();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
//overrides parent method
|
||||
//adds the default widget zones in the items
|
||||
//VERIFIED
|
||||
initializeModuleModel : function( constructorOptions ) {
|
||||
var module = this, dfd = $.Deferred();
|
||||
constructorOptions.items = _.union( _.has( module.serverParams, 'default_zones' ) ? module.serverParams.default_zones : [], constructorOptions.items );
|
||||
return dfd.resolve( constructorOptions ).promise();
|
||||
},
|
||||
|
||||
|
||||
});//$.extend()
|
||||
|
||||
})( wp.customize , jQuery, _ );
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
|
||||
CZRWZonesInputMths : {
|
||||
ready : function() {
|
||||
var input = this;
|
||||
|
||||
input.bind('locations:changed', function(){
|
||||
input.mayBeDisplayModelAlert();
|
||||
});
|
||||
|
||||
api.CZRInput.prototype.ready.call( input);
|
||||
},
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
///SETUP SELECTS
|
||||
//////////////////////////////////////////////////
|
||||
//setup select on view_rendered|item_content_event_map
|
||||
setupSelect : function() {
|
||||
var input = this;
|
||||
if ( 'locations' == this.id )
|
||||
this._setupLocationSelect();
|
||||
if ( 'contexts' == this.id )
|
||||
this._setupContextSelect();
|
||||
|
||||
},
|
||||
|
||||
//helper
|
||||
_setupContextSelect : function() {
|
||||
var input = this,
|
||||
input_contexts = input(),
|
||||
item = input.input_parent,
|
||||
module = input.module;
|
||||
|
||||
//generates the contexts options
|
||||
_.each( module.contexts, function( title, key ) {
|
||||
var _attributes = {
|
||||
value : key,
|
||||
html: title
|
||||
};
|
||||
if ( key == input_contexts || _.contains( input_contexts, key ) )
|
||||
$.extend( _attributes, { selected : "selected" } );
|
||||
|
||||
$( 'select[data-czrtype="contexts"]', input.container ).append( $('<option>', _attributes) );
|
||||
});
|
||||
//fire czrSelect2
|
||||
$( 'select[data-czrtype="contexts"]', input.container ).czrSelect2();
|
||||
},
|
||||
|
||||
|
||||
//helper
|
||||
//the refresh param is a bool
|
||||
_setupLocationSelect : function(refresh ) {
|
||||
var input = this,
|
||||
input_locations = input(),
|
||||
item = input.input_parent,
|
||||
module = input.module,
|
||||
available_locs = api.sidebar_insights('available_locations')();
|
||||
|
||||
//console.log('_setupLocationSelect', input(), module.locations );
|
||||
//generates the locations options
|
||||
//append them if not set yet
|
||||
if ( ! $( 'select[data-czrtype="locations"]', input.container ).children().length ) {
|
||||
_.each( module.locations, function( title, key ) {
|
||||
var _attributes = {
|
||||
value : key,
|
||||
html: title
|
||||
};
|
||||
|
||||
if ( key == input_locations || _.contains( input_locations, key ) )
|
||||
$.extend( _attributes, { selected : "selected" } );
|
||||
|
||||
$( 'select[data-czrtype="locations"]', input.container ).append( $('<option>', _attributes) );
|
||||
});
|
||||
}//if
|
||||
|
||||
function setAvailability( state ) {
|
||||
if (! state.id) { return state.text; }
|
||||
if ( _.contains(available_locs, state.element.value) ) { return state.text; }
|
||||
var $state = $(
|
||||
'<span class="czr-unavailable-location fas fa-ban" title="' + widgetModuleLocalized.i18n.unavailableLocation + '"> ' + state.text + '</span>'
|
||||
);
|
||||
return $state;
|
||||
}
|
||||
|
||||
if ( refresh ) {
|
||||
$( 'select[data-czrtype="locations"]', input.container ).czrSelect2( 'destroy' );
|
||||
}
|
||||
|
||||
//fire czrSelect2
|
||||
$( 'select[data-czrtype="locations"]', input.container ).czrSelect2( {
|
||||
templateResult: setAvailability,
|
||||
templateSelection: setAvailability
|
||||
});
|
||||
},
|
||||
|
||||
//fired on view event map : 'locations:changed'
|
||||
//@param obj { dom_el: $() , model : {} )
|
||||
mayBeDisplayModelAlert : function() {
|
||||
var input = this,
|
||||
item = input.input_parent,
|
||||
module = input.module;
|
||||
|
||||
//check if we are in the pre Item case => if so, the locations might be empty
|
||||
if ( ! _.has( item(), 'locations') || _.isEmpty( item().locations ) )
|
||||
return;
|
||||
|
||||
var _selected_locations = $('select[data-czrtype="locations"]', input.container ).val(),
|
||||
available_locs = api.sidebar_insights('available_locations')(),
|
||||
_unavailable = _.filter( _selected_locations, function( loc ) {
|
||||
return ! _.contains(available_locs, loc);
|
||||
});
|
||||
|
||||
//check if we are in the pre Item case => if so, the id is empty
|
||||
if ( ! _.has( item(), 'id' ) || _.isEmpty( item().id ) ) {
|
||||
module.preItem_location_alert_view_state.set( ! _.isEmpty( _unavailable ) ? 'expanded' : 'closed' );
|
||||
} else {
|
||||
item.czr_itemLocationAlert.set( ! _.isEmpty( _unavailable ) ? 'expanded' : 'closed' );
|
||||
}
|
||||
}
|
||||
},//CZRWZonesInputMths
|
||||
|
||||
});//$.extend()
|
||||
|
||||
})( wp.customize , jQuery, _ );
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
CZRWZonesItemConstructor : {
|
||||
initialize : function( id, options ) {
|
||||
var item = this,
|
||||
module = item.module;
|
||||
|
||||
//Add some observable values for this item
|
||||
item.czr_itemLocationAlert = new api.Value();
|
||||
|
||||
api.CZRItem.prototype.initialize.call( item, null, options );
|
||||
|
||||
// filter the params of the ajax query used to get the item wrapper template
|
||||
// because we need a ru ( not a read update delete ) template for builtins widget zones
|
||||
// requestParams = {
|
||||
// tmpl : 'rud-item-part',
|
||||
// module_type: 'all_modules',
|
||||
// nonce: api.settings.nonce.save//<= do we need to set a specific nonce to fetch the tmpls ?
|
||||
// };
|
||||
// this has been introduced in March 2018, after the introduction of the tmpl ajax fetching
|
||||
// it does the same job that the overriden getTemplateEl() was doing.
|
||||
// This filter is declared in item::renderItemWrapper()
|
||||
item.bind( 'item-wrapper-tmpl-params-before-fetching', function( requestParams ) {
|
||||
//force view-content type to ru-item-part if the model is a built-in (primary, secondary, footer-1, ...)
|
||||
//=> user can't delete a built-in model.
|
||||
requestParams.tmpl = ( _.has( item(), 'is_builtin' ) && item().is_builtin ) ? 'ruItemPart' : requestParams.tmpl;
|
||||
return requestParams;
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
//extend parent setupview
|
||||
itemWrapperViewSetup : function() {
|
||||
var item = this,
|
||||
module = item.module;
|
||||
|
||||
api.CZRItem.prototype.itemWrapperViewSetup.call(item);
|
||||
|
||||
/// ALERT FOR NOT AVAILABLE LOCATION
|
||||
item.czr_itemLocationAlert.set('closed');
|
||||
|
||||
//add a state listener on expansion change
|
||||
item.czr_itemLocationAlert.callbacks.add( function( to, from ) {
|
||||
module._toggleLocationAlertExpansion( item.container , to );
|
||||
});
|
||||
|
||||
//update item title
|
||||
item.writeSubtitleInfos(item());
|
||||
|
||||
//this is fired just after the itemWrapperViewSetupApiListeners
|
||||
//=> add a callback to refresh the availability status of the locations in the select location picker
|
||||
//add a state listener on expansion change
|
||||
item.viewState.callbacks.add( function( to, from ) {
|
||||
if ( -1 == to.indexOf('expanded') )//can take the expanded_noscroll value !
|
||||
return;
|
||||
//don't try to invoke the input instances before the content is actually rendered
|
||||
//=> there might be cases when the content rendering is debounced...
|
||||
item.bind('contentRendered', function() {
|
||||
//refresh the location list
|
||||
item.czr_Input('locations')._setupLocationSelect( true );//true for refresh
|
||||
//refresh the location alert message
|
||||
item.czr_Input('locations').mayBeDisplayModelAlert();
|
||||
});
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
//extend parent listener
|
||||
itemReact : function(to, from) {
|
||||
var item = this;
|
||||
api.CZRItem.prototype.itemReact.call(item, to, from);
|
||||
|
||||
item.writeSubtitleInfos(to);
|
||||
item.updateSectionTitle(to).setModelUpdateTimer();
|
||||
},
|
||||
|
||||
|
||||
|
||||
//Fired in setupItemListeners. Reacts to model change.
|
||||
//Write html informations under the title : location(s) and context(s)
|
||||
writeSubtitleInfos : function(model) {
|
||||
var item = this,
|
||||
module = item.module,
|
||||
_model = _.clone( model || item() ),
|
||||
_locations = [],
|
||||
_contexts = [],
|
||||
_html = '';
|
||||
|
||||
if ( ! item.container.length )
|
||||
return this;
|
||||
|
||||
//generate the locations and the contexts text from the json data if exists
|
||||
_model.locations =_.isString(_model.locations) ? [_model.locations] : _model.locations;
|
||||
_.each( _model.locations, function( loc ) {
|
||||
if ( _.has( module.locations , loc ) )
|
||||
_locations.push(module.locations[loc]);
|
||||
else
|
||||
_locations.push(loc);
|
||||
}
|
||||
);
|
||||
|
||||
//build the context list
|
||||
_model.contexts =_.isString(_model.contexts) ? [_model.contexts] : _model.contexts;
|
||||
|
||||
//all contexts cases ?
|
||||
if ( item._hasModelAllContexts( model ) ) {
|
||||
_contexts.push(module.contexts._all_);
|
||||
} else {
|
||||
_.each( _model.contexts, function( con ) {
|
||||
if ( _.has( module.contexts , con ) )
|
||||
_contexts.push(module.contexts[con]);
|
||||
else
|
||||
_contexts.push(con);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
//Translated strings
|
||||
var _locationText = widgetModuleLocalized.i18n.locations,
|
||||
_contextText = widgetModuleLocalized.i18n.contexts,
|
||||
_notsetText = widgetModuleLocalized.i18n.notset;
|
||||
|
||||
_locations = _.isEmpty( _locations ) ? '<span style="font-weight: bold;">' + _notsetText + '</span>' : _locations.join(', ');
|
||||
_contexts = _.isEmpty( _contexts ) ? '<span style="font-weight: bold;">' + _notsetText + '</span>' : _contexts.join(', ');
|
||||
|
||||
//write the description if builtin
|
||||
//else, write the dynamic location
|
||||
// if ( _.has(_model, 'description') && _.has(_model, 'is_builtin') )
|
||||
// _html = _model.description + ' <strong>|</strong> <u>Contexts</u> : ' + _contexts;
|
||||
// else
|
||||
|
||||
_html = '<u>' + _locationText + '</u> : ' + _locations + ' <strong>|</strong> <u>' + _contextText + '</u> : ' + _contexts;
|
||||
|
||||
if ( ! $('.czr-zone-infos', item.container ).length ) {
|
||||
var $_zone_infos = $('<div/>', {
|
||||
class : [ 'czr-zone-infos' , module.control.css_attr.item_sort_handle ].join(' '),
|
||||
html : _html
|
||||
});
|
||||
$( '.' + module.control.css_attr.item_btns, item.container ).after($_zone_infos);
|
||||
} else {
|
||||
$('.czr-zone-infos', item.container ).html(_html);
|
||||
}
|
||||
|
||||
return this;
|
||||
},//writeSubtitleInfos
|
||||
|
||||
|
||||
|
||||
////Fired in setupItemListeners
|
||||
updateSectionTitle : function(model) {
|
||||
var _sidebar_id = 'sidebar-widgets-' + model.id,
|
||||
_new_title = model.title;
|
||||
//does this section exists ?
|
||||
if ( ! api.section.has(_sidebar_id) )
|
||||
return this;
|
||||
|
||||
//update the section title
|
||||
$('.accordion-section-title', api.section(_sidebar_id).container ).text(_new_title);
|
||||
|
||||
//update the top title ( visible when inside the expanded section )
|
||||
$('.customize-section-title h3', api.section(_sidebar_id).container ).html(
|
||||
'<span class="customize-action">' + api.section(_sidebar_id).params.customizeAction + '</span>' + _new_title
|
||||
);
|
||||
// $('.customize-section-title h3', api.section(_sidebar_id).container )
|
||||
// .append('<span>', {
|
||||
// class: 'customize-section-back',
|
||||
// html: api.section(_sidebar_id).params.customizeAction
|
||||
// } )
|
||||
// .append(_new_title);
|
||||
|
||||
//remove and re-instanciate
|
||||
//=> works for the section but the controls are not activated anymore.
|
||||
//Should be easy to fix but useless to go further here. Jquery does the job.
|
||||
// var _params = _.clone( api.section(_sidebar_id).params );
|
||||
// _params.title = _new_title;
|
||||
// api.section(_sidebar_id).container.remove();
|
||||
// api.section.remove(_sidebar_id);
|
||||
// api.section.add( _sidebar_id, new api.sectionConstructor[_params.type]( _params.id ,{ params : _params } ) );
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
//fired on model_update
|
||||
//Don't hammer the preview with too many refreshs
|
||||
//2 seconds delay
|
||||
setModelUpdateTimer : function() {
|
||||
var item = this,
|
||||
module = item.module;
|
||||
|
||||
clearTimeout( $.data(this, 'modelUpdateTimer') );
|
||||
$.data(
|
||||
this,
|
||||
'modelUpdateTimer',
|
||||
_.delay( function() {
|
||||
//refresh preview
|
||||
api.previewer.refresh();
|
||||
} , 1000)
|
||||
);//$.data
|
||||
},
|
||||
|
||||
|
||||
//@return bool
|
||||
//takes the model unique id
|
||||
_hasModelAllContexts : function( model ) {
|
||||
var item = this,
|
||||
module = item.module,
|
||||
moduleContexts = _.keys(module.contexts);
|
||||
|
||||
model = model || this();
|
||||
|
||||
if ( ! _.has(model, 'contexts') )
|
||||
return;
|
||||
|
||||
if ( _.contains( model.contexts, '_all_') )
|
||||
return true;
|
||||
|
||||
//case when model does not have _all_ but all the others
|
||||
return _.isEmpty( _.difference( _.without(moduleContexts, '_all_') , model.contexts ) );
|
||||
},
|
||||
|
||||
//@param contexts = array of contexts
|
||||
//api.czr_wpQueryInfos is refreshed on each preview refresh
|
||||
_getMatchingContexts : function( defaults ) {
|
||||
var module = this,
|
||||
_current = api.czr_wpQueryInfos().conditional_tags || {},
|
||||
_matched = _.filter( module.context_match_map, function( hu, wp ) { return true === _current[wp]; } );
|
||||
|
||||
return _.isEmpty( _matched ) ? defaults : _matched;
|
||||
}
|
||||
},//CZRWZonesItemConstructor
|
||||
|
||||
});//$.extend()
|
||||
|
||||
})( wp.customize , jQuery, _ );
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
/////////////////////////////////////////
|
||||
/// ADD / REMOVE WIDGET ZONES
|
||||
////////////////////////////////////////
|
||||
//fired on model_added_by_user
|
||||
//
|
||||
//can also be called statically when a dynamic sidebar is added in the preview
|
||||
//in this case the parameter are the sidebar data with id and name
|
||||
addWidgetSidebar : function( model, sidebar_data ) {
|
||||
if ( ! _.isObject(model) && _.isEmpty(sidebar_data) ) {
|
||||
throw new Error('No valid input were provided to add a new Widget Zone.');
|
||||
}
|
||||
|
||||
|
||||
//ADD the new sidebar to the existing collection
|
||||
//Clone the serverControlParams.defaultWidgetSidebar sidebar
|
||||
var module = this,
|
||||
_model = ! _.isEmpty(model) ? _.clone(model) : sidebar_data,
|
||||
_new_sidebar = _.isEmpty(model) ? sidebar_data : $.extend(
|
||||
_.clone( _.findWhere( api.Widgets.data.registeredSidebars, { id: module.serverParams.defaultWidgetSidebar } ) ),
|
||||
{
|
||||
name : _model.title,
|
||||
id : _model.id
|
||||
}
|
||||
);
|
||||
|
||||
//Add it to the backbone collection
|
||||
api.Widgets.registeredSidebars.add( _new_sidebar );
|
||||
|
||||
//test if added:
|
||||
//api.Widgets.registeredSidebars('czr_sidebars_8');
|
||||
|
||||
|
||||
//ADD the sidebar section
|
||||
var _params = $.extend(
|
||||
_.clone( api.section( "sidebar-widgets-" + module.serverParams.defaultWidgetSidebar ).params ),
|
||||
{
|
||||
id : "sidebar-widgets-" + _model.id,
|
||||
instanceNumber: _.max(api.settings.sections, function(sec){ return sec.instanceNumber; }).instanceNumber + 1,
|
||||
sidebarId: _new_sidebar.id,
|
||||
title: _new_sidebar.name,
|
||||
description : 'undefined' != typeof(sidebar_data) ? sidebar_data.description : api.section( "sidebar-widgets-" + module.serverParams.defaultWidgetSidebar ).params.description,
|
||||
//always set the new priority to the maximum + 1 ( module.serverParams.dynWidgetSection is excluded from this calculation because it must always be at the bottom )
|
||||
priority: _.max( _.omit( api.settings.sections, module.serverParams.dynWidgetSection), function(sec){ return sec.instanceNumber; }).priority + 1,
|
||||
}
|
||||
);
|
||||
|
||||
api.section.add( _params.id, new api.sectionConstructor[ _params.type ]( _params.id ,{ params : _params } ) );
|
||||
|
||||
//add it to the static collection of settings
|
||||
api.settings.sections[ _params.id ] = _params.id;
|
||||
|
||||
//ADD A SETTING
|
||||
//Clone the module.serverParams.defaultWidgetSidebar sidebar widget area setting
|
||||
var _new_set_id = 'sidebars_widgets['+_model.id+']',
|
||||
_new_set = $.extend(
|
||||
_.clone( api.settings.settings['sidebars_widgets[' + module.serverParams.defaultWidgetSidebar + ']'] ),
|
||||
{
|
||||
value:[]
|
||||
}
|
||||
);
|
||||
|
||||
//add it to the static collection of settings
|
||||
api.settings.settings[ _new_set_id ] = _new_set;
|
||||
|
||||
//instanciate it
|
||||
api.create( _new_set_id, _new_set_id, _new_set.value, {
|
||||
transport: _new_set.transport,
|
||||
previewer: api.previewer,
|
||||
dirty: false
|
||||
} );
|
||||
|
||||
|
||||
|
||||
//ADD A CONTROL
|
||||
var _cloned_control = $.extend(
|
||||
_.clone( api.settings.controls['sidebars_widgets[' + module.serverParams.defaultWidgetSidebar + ']'] ),
|
||||
{
|
||||
settings : { default : _new_set_id }
|
||||
}),
|
||||
_new_control = {};
|
||||
|
||||
|
||||
//replace serverControlParams.defaultWidgetSidebar by the new sidebar id
|
||||
_.each( _cloned_control, function( param, key ) {
|
||||
if ( 'string' == typeof(param) ) {
|
||||
param = param.replace( module.serverParams.defaultWidgetSidebar , _model.id );
|
||||
}
|
||||
_new_control[key] = param;
|
||||
});
|
||||
|
||||
//set the instance number (no sure if needed)
|
||||
_new_control.instanceNumber = _.max(api.settings.controls, function(con){ return con.instanceNumber; }).instanceNumber + 1;
|
||||
|
||||
//add it to the static collection of controls
|
||||
api.settings.controls[_new_set_id] = _new_control;
|
||||
|
||||
//instanciate it
|
||||
api.control.add( _new_set_id, new api.controlConstructor[ _new_control.type ]( _new_set_id, {
|
||||
params: _new_control,
|
||||
previewer: api.previewer
|
||||
} ) );
|
||||
|
||||
|
||||
//say it to the control container
|
||||
//only if we are in an instanciated object => because this method can be accessed statically
|
||||
if ( _.has(this, 'container') )
|
||||
this.container.trigger( 'widget_zone_created', { model : _model, section_id : "sidebar-widgets-" + _model.id , setting_id : _new_set_id });
|
||||
},//addWidgetSidebar
|
||||
|
||||
|
||||
//fired on "after_modelRemoved"
|
||||
removeWidgetSidebar : function( model ) {
|
||||
var module = this;
|
||||
if ( ! _.isObject(model) || _.isEmpty(model) ) {
|
||||
throw new Error('No valid data were provided to remove a Widget Zone.');
|
||||
}
|
||||
|
||||
//Remove this sidebar from the backbone collection
|
||||
api.Widgets.registeredSidebars.remove( model.id );
|
||||
|
||||
//remove the section from the api values and the DOM if exists
|
||||
if ( api.section.has("sidebar-widgets-" + model.id) ) {
|
||||
//Remove the section container from the DOM
|
||||
api.section("sidebar-widgets-" + model.id).container.remove();
|
||||
//Remove the sidebar section from the api
|
||||
api.section.remove( "sidebar-widgets-" + model.id );
|
||||
//Remove this section from the static collection
|
||||
delete api.settings.sections[ "sidebar-widgets-" + model.id ];
|
||||
}
|
||||
|
||||
//remove the setting from the api if exists
|
||||
if ( api.has('sidebars_widgets['+model.id+']') ) {
|
||||
//Remove this setting from the api
|
||||
api.remove( 'sidebars_widgets['+model.id+']' );
|
||||
//Remove this setting from the static collection
|
||||
delete api.settings.settings['sidebars_widgets['+model.id+']'];
|
||||
}
|
||||
|
||||
//remove the widget control of this sidebar from the api and the DOM if exists
|
||||
if ( api.control.has('sidebars_widgets['+model.id+']') ) {
|
||||
//Remove the control container from the DOM
|
||||
api.control( 'sidebars_widgets['+model.id+']' ).container.remove();
|
||||
//Remove this control from the api
|
||||
api.control.remove( 'sidebars_widgets['+model.id+']' );
|
||||
//Remove it to the static collection of controls
|
||||
delete api.settings.controls['sidebars_widgets['+model.id+']'];
|
||||
}
|
||||
|
||||
//refresh
|
||||
var _refresh = function() {
|
||||
api.previewer.refresh();
|
||||
};
|
||||
_refresh = _.debounce( _refresh, 500 );
|
||||
$.when( _refresh() ).done( function() {
|
||||
//say it
|
||||
module.trigger( 'widget_zone_removed',
|
||||
{
|
||||
model : model,
|
||||
section_id : "sidebar-widgets-" + model.id ,
|
||||
setting_id : 'sidebars_widgets['+model.id+']'
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
});//$.extend()
|
||||
|
||||
})( wp.customize , jQuery, _ );
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
|
||||
/////////////////////////////////////////
|
||||
/// SET EXPANSION CALLBACKS FOR WIDGET PANEL AND WIDGET ZONE CREATION SECTION
|
||||
////////////////////////////////////////
|
||||
//cb of : api.panel('widgets').expanded.callbacks.add
|
||||
widgetPanelReact : function() {
|
||||
var module = this;
|
||||
//will be used for adjustments
|
||||
var _top_margin = api.panel('widgets').container.find( '.control-panel-content' ).css('margin-top');
|
||||
|
||||
api.section(module.serverParams.dynWidgetSection).fixTopMargin('value').set( _top_margin );
|
||||
|
||||
var _section_content = api.section(module.serverParams.dynWidgetSection).container.find( '.accordion-section-content' ),
|
||||
_panel_content = api.panel('widgets').container.find( '.control-panel-content' ),
|
||||
_set_margins = function() {
|
||||
_section_content.css( 'margin-top', '' );
|
||||
_panel_content.css('margin-top', api.section(module.serverParams.dynWidgetSection).fixTopMargin('value')() );
|
||||
};
|
||||
|
||||
// Fix the top margin after reflow.
|
||||
api.bind( 'pane-contents-reflowed', _.debounce( function() {
|
||||
_set_margins();
|
||||
}, 150 ) );
|
||||
|
||||
//Close all views on widget panel expansion/clos
|
||||
module.closeAllItems().closeRemoveDialogs();
|
||||
//Close preItem dialog box if exists
|
||||
if ( _.has( module, 'preItemExpanded' ) )
|
||||
module.preItemExpanded.set(false);
|
||||
},//widgetPanelReact()
|
||||
|
||||
|
||||
//cb of api.section(module.serverParams.dynWidgetSection).expanded.callbacks
|
||||
widgetSectionReact : function( to, from ) {
|
||||
var module = this,
|
||||
section = api.section(module.serverParams.dynWidgetSection),
|
||||
container = section.container.closest( '.wp-full-overlay-sidebar-content' ),
|
||||
content = section.container.find( '.accordion-section-content' ),
|
||||
overlay = section.container.closest( '.wp-full-overlay' ),
|
||||
backBtn = section.container.find( '.customize-section-back' ),
|
||||
sectionTitle = section.container.find( '.accordion-section-title' ).first(),
|
||||
headerActionsHeight = $( '#customize-header-actions' ).height(),
|
||||
resizeContentHeight, expand, position, scroll;
|
||||
|
||||
if ( to ) {
|
||||
overlay.removeClass( 'section-open' );
|
||||
content.css( 'height', 'auto' );
|
||||
//section.container.removeClass( 'open' );
|
||||
sectionTitle.attr( 'tabindex', '0' );
|
||||
content.css( 'margin-top', '' );
|
||||
container.scrollTop( 0 );
|
||||
}
|
||||
|
||||
module.closeAllItems().closeRemoveDialogs();
|
||||
|
||||
content.slideToggle();
|
||||
}
|
||||
});//$.extend()
|
||||
})( wp.customize , jQuery, _ );
|
||||
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
|
||||
/////////////////////////////////////////
|
||||
/// LISTEN TO SIDEBAR INSIGHTS FROM THE PREVIEW FRAME
|
||||
/// REACT TO THEM
|
||||
////////////////////////////////////////
|
||||
listenToSidebarInsights : function() {
|
||||
var module = this;
|
||||
|
||||
//VISIBILITY BASED ON THE SIDEBAR INSIGHTS
|
||||
api.sidebar_insights('registered').callbacks.add( function( _registered_zones ) {
|
||||
var _current_collection = _.clone( module.itemCollection() );
|
||||
_.each( _current_collection, function( _model ) {
|
||||
if ( ! module.getViewEl(_model.id).length )
|
||||
return;
|
||||
|
||||
module.getViewEl(_model.id).css('display' , _.contains( _registered_zones, _model.id ) ? 'block' : 'none' );
|
||||
});
|
||||
});
|
||||
|
||||
//OPACITY SIDEBAR INSIGHTS BASED
|
||||
api.sidebar_insights('inactives').callbacks.add( function( _inactives_zones ) {
|
||||
var _current_collection = _.clone( module.itemCollection() );
|
||||
_.each( _current_collection, function( _model ) {
|
||||
if ( ! module.getViewEl(_model.id).length )
|
||||
return;
|
||||
|
||||
if ( _.contains( _inactives_zones, _model.id ) ) {
|
||||
module.getViewEl( _model.id ).addClass('inactive');
|
||||
if ( ! module.getViewEl( _model.id ).find('.czr-inactive-alert').length ) {
|
||||
module.getViewEl( _model.id ).find('.czr-item-title').append(
|
||||
$('<span/>', {class : "czr-inactive-alert", html : " [ " + widgetModuleLocalized.i18n.inactiveWidgetZone + " ]" })
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
module.getViewEl( _model.id ).removeClass('inactive');
|
||||
if ( module.getViewEl( _model.id ).find('.czr-inactive-alert').length )
|
||||
module.getViewEl( _model.id ).find('.czr-inactive-alert').remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//WIDGET SIDEBAR CREATION BASED ON SIDEBAR INSIGHTS
|
||||
//react to a new register candidate(s) on preview refresh
|
||||
api.sidebar_insights('candidates').callbacks.add( function(_candidates) {
|
||||
if ( ! _.isArray(_candidates) )
|
||||
return;
|
||||
_.each( _candidates, function( _sidebar ) {
|
||||
if ( ! _.isObject(_sidebar) )
|
||||
return;
|
||||
//add this widget sidebar and the related setting and control.
|
||||
//Only if not added already
|
||||
if ( api.section.has("sidebar-widgets-" +_sidebar.id ) )
|
||||
return;
|
||||
|
||||
//access the registration method statically
|
||||
module.addWidgetSidebar( {}, _sidebar );
|
||||
//activate it if so
|
||||
if ( _.has( api.sidebar_insights('actives')(), _sidebar.id ) && api.section.has("sidebar-widgets-" +_sidebar.id ) )
|
||||
api.section( "sidebar-widgets-" +_sidebar.id ).activate();
|
||||
});
|
||||
});
|
||||
}//listenToSidebarInsights()
|
||||
});//$.extend()
|
||||
})( wp.customize , jQuery, _ );
|
||||
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
$.extend( WidgetAreaConstructor, {
|
||||
/////////////////////////////////////////
|
||||
/// OVERRIDEN METHODS
|
||||
////////////////////////////////////////
|
||||
//fired in toggleItemExpansion()
|
||||
//has to be overridden for the widget zones control because this control is embedded directly in a panel and not in a section
|
||||
//therefore the module to animate the scrollTop is not the section container but $('.wp-full-overlay-sidebar-content')
|
||||
_adjustScrollExpandedBlock : function( $_block_el, adjust ) {
|
||||
if ( ! $_block_el.length )
|
||||
return;
|
||||
var module = this,
|
||||
_currentScrollTopVal = $('.wp-full-overlay-sidebar-content').scrollTop(),
|
||||
_scrollDownVal,
|
||||
_adjust = adjust || 90;
|
||||
setTimeout( function() {
|
||||
if ( ( $_block_el.offset().top + $_block_el.height() + _adjust ) > $(window.top).height() ) {
|
||||
_scrollDownVal = $_block_el.offset().top + $_block_el.height() + _adjust - $(window.top).height();
|
||||
$('.wp-full-overlay-sidebar-content').animate({
|
||||
scrollTop: _currentScrollTopVal + _scrollDownVal
|
||||
}, 600);
|
||||
}
|
||||
}, 50);
|
||||
},
|
||||
|
||||
|
||||
|
||||
//overrides the parent class default model getter
|
||||
//=> add a dynamic title
|
||||
getDefaultItemModel : function( id ) {
|
||||
var module = this,
|
||||
_current_collection = module.itemCollection(),
|
||||
_default = _.clone( module.defaultItemModel ),
|
||||
_default_contexts = _default.contexts;
|
||||
return $.extend( _default, {
|
||||
title : 'Widget Zone ' + ( _.size(_current_collection)*1 + 1 )
|
||||
//contexts : module._getMatchingContexts( _default_contexts )
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
_toggleLocationAlertExpansion : function( $view, to ) {
|
||||
var $_alert_el = $view.find('.czr-location-alert');
|
||||
if ( ! $_alert_el.length ) {
|
||||
var _html = [
|
||||
'<span>' + widgetModuleLocalized.i18n.locationWarning + '</span>',
|
||||
api.CZR_Helpers.getDocSearchLink( widgetModuleLocalized.i18n.locationWarning ),
|
||||
].join('');
|
||||
|
||||
$_alert_el = $('<div/>', {
|
||||
class:'czr-location-alert',
|
||||
html:_html,
|
||||
style:"display:none"
|
||||
});
|
||||
|
||||
$('select[data-czrtype="locations"]', $view ).closest('div').after($_alert_el);
|
||||
}
|
||||
$_alert_el.toggle( 'expanded' == to);
|
||||
}
|
||||
});//$.extend()
|
||||
})( wp.customize , jQuery, _ );
|
||||
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
/*****************************************************************************
|
||||
* CAPTURE PREVIEW INFORMATIONS ON REFRESH + REACT TO THEM
|
||||
*****************************************************************************/
|
||||
(function (api, $, _) {
|
||||
//Data are sent by the preview frame when the panel has sent the 'sync' or even better 'active' event
|
||||
api.bind( 'ready', function() {
|
||||
//observe widget settings changes
|
||||
api.previewer.bind('houston-widget-settings', function(data) {
|
||||
//console.log('control panel => ALORS ON HOUSTON- SETTINGS ? => ', data );
|
||||
//get the difference
|
||||
var _candidates = _.filter( data.registeredSidebars, function( sb ) {
|
||||
return ! _.findWhere( _wpCustomizeWidgetsSettings.registeredSidebars, { id: sb.id } );
|
||||
});
|
||||
|
||||
var _inactives = _.filter( data.registeredSidebars, function( sb ) {
|
||||
return ! _.has( data.renderedSidebars, sb.id );
|
||||
});
|
||||
|
||||
_inactives = _.map( _inactives, function(obj) {
|
||||
return obj.id;
|
||||
});
|
||||
|
||||
var _registered = _.map( data.registeredSidebars, function(obj) {
|
||||
return obj.id;
|
||||
});
|
||||
|
||||
//stores and update the widget zone settings
|
||||
api.czr_widgetZoneSettings = api.czr_widgetZoneSettings || new api.Value();//will store all widget zones data sent by preview as an observable object
|
||||
api.czr_widgetZoneSettings.set( {
|
||||
actives : data.renderedSidebars,
|
||||
inactives : _inactives,
|
||||
registered : _registered,
|
||||
candidates : _candidates,
|
||||
available_locations : data.availableWidgetLocations//built server side
|
||||
} );
|
||||
|
||||
});
|
||||
});//api.bind('ready')
|
||||
})( wp.customize , jQuery, _ );
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
//extends api.CZRDynModule
|
||||
//globals widgetModuleLocalized, themeServerControlParams
|
||||
var WidgetAreaConstructor = WidgetAreaConstructor || {};
|
||||
( function ( api, $, _ ) {
|
||||
//provides a description of each module
|
||||
//=> will determine :
|
||||
//1) how to initialize the module model. If not crud, then the initial item(s) model shall be provided
|
||||
//2) which js template(s) to use : if crud, the module template shall include the add new and pre-item elements.
|
||||
// , if crud, the item shall be removable
|
||||
//3) how to render : if multi item, the item content is rendered when user click on edit button.
|
||||
// If not multi item, the single item content is rendered as soon as the item wrapper is rendered.
|
||||
//4) some DOM behaviour. For example, a multi item shall be sortable.
|
||||
api.czrModuleMap = api.czrModuleMap || {};
|
||||
$.extend( api.czrModuleMap, {
|
||||
czr_widget_areas_module : {
|
||||
mthds : WidgetAreaConstructor,
|
||||
crud : true,
|
||||
multi_item : false,
|
||||
name : 'Widget Areas',
|
||||
has_mod_opt : false,
|
||||
ready_on_section_expanded : true,
|
||||
//defaultItemModel : {}
|
||||
}
|
||||
});
|
||||
})( wp.customize , jQuery, _ );
|
||||
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
function hu_register_widget_zones_module( $args ) {
|
||||
$defaults = array(
|
||||
'setting_id' => '',
|
||||
|
||||
'base_url_path' => '',//PC_AC_BASE_URL/inc/czr-modules/social-links/
|
||||
'version' => '',
|
||||
|
||||
'option_value' => array(), //<= will be used for the dynamic registration
|
||||
|
||||
'setting' => array(),
|
||||
'control' => array(),
|
||||
'section' => array(), //array( 'id' => '', 'label' => '' ),
|
||||
|
||||
'sanitize_callback' => '',
|
||||
'validate_callback' => ''
|
||||
);
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
if ( ! isset( $GLOBALS['czr_base_fmk_namespace'] ) ) {
|
||||
error_log( __FUNCTION__ . ' => global czr_base_fmk not set' );
|
||||
return;
|
||||
}
|
||||
|
||||
$czrnamespace = $GLOBALS['czr_base_fmk_namespace'];
|
||||
//czr_fn\czr_register_dynamic_module
|
||||
$CZR_Fmk_Base_fn = $czrnamespace . 'CZR_Fmk_Base';
|
||||
if ( ! function_exists( $CZR_Fmk_Base_fn) ) {
|
||||
error_log( __FUNCTION__ . ' => Namespace problem => ' . $CZR_Fmk_Base_fn );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$CZR_Fmk_Base_fn() -> czr_pre_register_dynamic_setting( array(
|
||||
'setting_id' => $args['setting_id'],
|
||||
'module_type' => 'czr_widget_areas_module',
|
||||
'option_value' => ! is_array( $args['option_value'] ) ? array() : $args['option_value'],
|
||||
|
||||
'setting' => $args['setting'],
|
||||
|
||||
'section' => $args['section'],
|
||||
|
||||
'control' => $args['control']
|
||||
));
|
||||
|
||||
// czr_fn\czr_register_dynamic_module()
|
||||
$CZR_Fmk_Base_fn() -> czr_pre_register_dynamic_module( array(
|
||||
'dynamic_registration' => true,
|
||||
'module_type' => 'czr_widget_areas_module',
|
||||
|
||||
// 'sanitize_callback' => 'hu_sanitize_callback__czr_social_module',
|
||||
// 'validate_callback' => 'hu_validate_callback__czr_social_module',
|
||||
|
||||
'customizer_assets' => array(
|
||||
'control_js' => array(
|
||||
// handle + params for wp_enqueue_script()
|
||||
// @see https://developer.wordpress.org/reference/functions/wp_enqueue_script/
|
||||
'czr-widget-areas-module' => array(
|
||||
'src' => sprintf(
|
||||
'%1$s/assets/js/%2$s',
|
||||
$args['base_url_path'],
|
||||
'_2_6_widget_areas_module.js'
|
||||
),
|
||||
'deps' => array('customize-controls' , 'jquery', 'underscore'),
|
||||
'ver' => ( defined('WP_DEBUG') && true === WP_DEBUG ) ? time() : $args['version'],
|
||||
'in_footer' => true
|
||||
)
|
||||
),
|
||||
'localized_control_js' => array(
|
||||
'deps' => 'czr-customizer-fmk',
|
||||
'global_var_name' => 'widgetModuleLocalized',
|
||||
'params' => array(
|
||||
//Widget Area Module
|
||||
'dynWidgetSection' => HU_DYN_WIDGETS_SECTION,
|
||||
'defaultWidgetSidebar' => 'primary',//the one that will be cloned. Specific to each themes
|
||||
'defaultWidgetLocation' => 's1',//Specific to each themes
|
||||
'sidebar_contexts' => hu_get_contexts_list(),
|
||||
'sidebar_locations' => hu_get_widget_el_locations(),
|
||||
|
||||
'i18n' => array(
|
||||
'widgetZone' => __('Widget Zone', 'hueman'),
|
||||
'widgetZoneAdded' => __('New Widget Zone created ! Scroll down to edit it.', 'hueman'),
|
||||
'inactiveWidgetZone' => __('Inactive in current context/location', 'hueman'),
|
||||
'unavailableLocation' => __('Unavailable location. Some settings must be changed.', 'hueman'),
|
||||
'locationWarning' => __('A selected location is not available with the current settings.', 'hueman'),
|
||||
'locations' => __('Location(s)', 'hueman'),
|
||||
'contexts' => __('Context(s)', 'hueman'),
|
||||
'notset' => __('Not set', 'hueman'),
|
||||
)
|
||||
//'default_zones' => hu_get_widget_el_default_zones()
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
'tmpl' => array()//tmpl
|
||||
));
|
||||
}//hu_register_widget_zones_module()
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* Various Helpers
|
||||
/* ------------------------------------------------------------------------- */
|
||||
function hu_get_widget_el_locations() {
|
||||
$_default_locations = hu_get_builtin_widget_zones_location();
|
||||
//generates the locations for json
|
||||
$locations = array();
|
||||
foreach ($_default_locations as $_id => $data ) {
|
||||
$_k = key($data);
|
||||
$locations[$_k] = $data[$_k];
|
||||
}
|
||||
return $locations;
|
||||
}
|
||||
|
||||
function hu_get_widget_el_default_zones() {
|
||||
//generates the default widget zone for json
|
||||
$default_zones = array();
|
||||
foreach ( hu_get_default_widget_zones() as $_zone_id => $_data ) {
|
||||
//get the default location
|
||||
$_loc = isset($_default_locations[$_zone_id]) ? key($_default_locations[$_zone_id]) : '';
|
||||
|
||||
$default_zones[] = array(
|
||||
'id' => $_data['id'],
|
||||
'title' => $_data['name'],
|
||||
'contexts' => array('_all_'),
|
||||
'locations' => array($_loc),
|
||||
'is_builtin' => true,
|
||||
'description' => $_data['description']
|
||||
);
|
||||
}
|
||||
return $default_zones;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* PREVIEW SCRIPT
|
||||
*****************************************************************************/
|
||||
//exports some wp_query informations. Updated on each preview refresh.
|
||||
add_action( 'customize_preview_init' , 'hu_schedule_preview_script_printing', 20 );
|
||||
function hu_schedule_preview_script_printing() {
|
||||
add_action( 'wp_footer', 'hu_print_widget_module_script', 1000 );
|
||||
}
|
||||
|
||||
function hu_print_widget_module_script() {
|
||||
?>
|
||||
<script id="hu-widget-zones-module">
|
||||
//global _wpWidgetCustomizerPreviewSettings
|
||||
( function( api, $, _ ) {
|
||||
api.bind( 'preview-ready', function() {
|
||||
api.preview.bind( 'active', function() {
|
||||
api.preview.send( 'houston-widget-settings',
|
||||
_.extend( _wpWidgetCustomizerPreviewSettings,
|
||||
{
|
||||
availableWidgetLocations : _.values( api.settings.availableWidgetLocations )
|
||||
}
|
||||
)
|
||||
);//send()
|
||||
});
|
||||
});
|
||||
})( wp.customize, jQuery, _ );
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* PRINT TEMPLATES
|
||||
*****************************************************************************/
|
||||
//print the pre add view content
|
||||
add_action( 'customize_controls_print_footer_scripts', 'hu_print_widget_areas_templates' , 1 );
|
||||
|
||||
|
||||
|
||||
function hu_print_widget_areas_templates() {
|
||||
if ( ! isset( $GLOBALS['czr_base_fmk_namespace'] ) ) {
|
||||
error_log( __FUNCTION__ . ' => global czr_base_fmk not set' );
|
||||
return;
|
||||
}
|
||||
|
||||
$czrnamespace = $GLOBALS['czr_base_fmk_namespace'];
|
||||
//czr_fn\czr_register_dynamic_module
|
||||
$CZR_Fmk_Base_fn = $czrnamespace . 'CZR_Fmk_Base';
|
||||
if ( ! function_exists( $CZR_Fmk_Base_fn) ) {
|
||||
error_log( __FUNCTION__ . ' => Namespace problem => ' . $CZR_Fmk_Base_fn );
|
||||
return;
|
||||
}
|
||||
$css_attr = $CZR_Fmk_Base_fn()->czr_css_attr;
|
||||
?>
|
||||
<script type="text/html" id="tmpl-czr-module-widgets-pre-add-view-content">
|
||||
<div class="<?php echo $css_attr['sub_set_wrapper']; ?>" data-input-type="text">
|
||||
<div class="customize-control-title"><?php _e('Name', 'hueman'); ?></div>
|
||||
<div class="czr-input">
|
||||
<input data-czrtype="title" type="text" value="" placeholder="<?php _e('Give it a name', 'hueman'); ?>"></input>
|
||||
</div>
|
||||
<span class="czr-notice"><?php _e('Personalizing the name of the widget zone will help you identify it.', 'hueman'); ?></span>
|
||||
</div>
|
||||
<div class="<?php echo $css_attr['sub_set_wrapper']; ?> width-100" data-input-type="select">
|
||||
<div class="customize-control-title"><?php _e('Location(s)', 'hueman'); ?></div>
|
||||
<span class="czr-notice"><?php _e('Select the pre-defined location(s) in which you will embed this widget zone.', 'hueman'); ?></span>
|
||||
<div class="czr-input">
|
||||
<select data-czrtype="locations" class="js-example-basic-multiple" multiple="multiple"></select>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<?php
|
||||
//print template for built-in models like primary, secondary, footer-1, etc...
|
||||
//REDUCED VIEW TEMPLATE
|
||||
//no remove button
|
||||
//no remove alert wrapper
|
||||
?>
|
||||
<script type="text/html" id="tmpl-czr-module-widgets-ru-item-part">
|
||||
<div class="<?php echo $css_attr['item_header']; ?> czr-builtin-model">
|
||||
<div class="<?php echo $css_attr['item_title']; ?> <?php echo $css_attr['item_sort_handle']; ?>"><h4>{{ data.title }}</h4></div>
|
||||
<div class="<?php echo $css_attr['item_btns']; ?>"><a title="<?php _e('Edit', 'hueman'); ?>" href="javascript:void(0);" class="fas fa-pencil-alt <?php echo $css_attr['edit_view_btn']; ?>"></a></div>
|
||||
</div>
|
||||
</script>
|
||||
<?php
|
||||
//the following template is a "sub view"
|
||||
//it's rendered :
|
||||
//1) on customizer start, depending on what is fetched from the db
|
||||
//2) dynamically when designing from the customizer
|
||||
//data looks like : { id : 'sidebar-one', title : 'A Title One' }
|
||||
?>
|
||||
|
||||
<script type="text/html" id="tmpl-czr-module-widgets-item-input-list">
|
||||
<div class="<?php echo $css_attr['sub_set_wrapper']; ?>" data-input-type="text">
|
||||
<div class="customize-control-title"><?php _e('id', 'hueman'); ?></div>
|
||||
<input data-czrtype="id" type="hidden"></input>
|
||||
<span><?php _e('unique id', 'hueman')?> : {{ data.id }}</span>
|
||||
</div>
|
||||
<div class="<?php echo $css_attr['sub_set_wrapper']; ?>" data-input-type="text">
|
||||
<div class="customize-control-title"><?php _e('Name', 'hueman'); ?></div>
|
||||
<div class="czr-input">
|
||||
<input data-czrtype="title" type="text" value="{{ data.title }}" placeholder="<?php _e('Enter a name', 'hueman'); ?>"></input>
|
||||
</div>
|
||||
<span class="czr-notice"><?php _e('Personalizing the name of the widget zone will help you identify it.', 'hueman'); ?></span>
|
||||
</div>
|
||||
<div class="<?php echo $css_attr['sub_set_wrapper']; ?> width-100" data-input-type="select">
|
||||
<div class="customize-control-title"><?php _e('Location(s)', 'hueman'); ?></div>
|
||||
<span class="czr-notice"><?php _e('Select the pre-defined location(s) in which you will embed this widget zone.', 'hueman'); ?></span>
|
||||
<div class="czr-input">
|
||||
<select data-czrtype="locations" class="js-example-basic-multiple" multiple="multiple"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="<?php echo $css_attr['sub_set_wrapper']; ?> width-100" data-input-type="select">
|
||||
<div class="customize-control-title"><?php _e('Context(s)', 'hueman'); ?></div>
|
||||
<span class="czr-notice"><?php _e('Pick the context(s) where this widget area will be displayed.', 'hueman'); ?></span>
|
||||
<div class="czr-input">
|
||||
<select data-czrtype="contexts" class="js-example-basic-multiple" multiple="multiple"></select>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
||||
<?php
|
||||
}
|
||||
Reference in New Issue
Block a user