first commit

This commit is contained in:
CHIEFSOFT\ameye
2023-12-28 16:20:07 -05:00
commit b114fdf4fa
5377 changed files with 1850677 additions and 0 deletions
@@ -0,0 +1,575 @@
<?php
namespace Nimble;
// Exit if accessed directly
if ( !defined( 'ABSPATH' ) ) exit;
/* ------------------------------------------------------------------------- *
* REGISTER PAGE
/* ------------------------------------------------------------------------- */
// function nb_register_settings() {
// add_option( 'myplugin_option_name', 'This is my option value.');
// register_setting( 'myplugin_options_group', 'myplugin_option_name', '\Nimble\myplugin_callback' );
// }
// add_action( 'admin_init', '\Nimble\nb_register_settings' );
function nb_register_options_page() {
if ( !sek_current_user_can_access_nb_ui() )
return;
add_options_page(
apply_filters( 'nb_admin_settings_title', __('Nimble Builder', 'text-domain') ),
apply_filters( 'nb_admin_settings_title', __('Nimble Builder', 'text-domain') ),
'manage_options',
NIMBLE_OPTIONS_PAGE,
'\Nimble\nb_options_page'
);
}
add_action( 'admin_menu', '\Nimble\nb_register_options_page');
// callback of add_options_page()
// fired @'admin_menu'
function nb_options_page() {
$option_tabs = Nimble_Manager()->admin_option_tabs;
$active_tab_id = nb_get_active_option_tab();
$default_title = esc_html( get_admin_page_title() );
$page_title = isset( $option_tabs[$active_tab_id] ) ? $option_tabs[$active_tab_id]['page_title'] : $default_title;
$page_title = empty($page_title) ? $default_title : $page_title;
?>
<div id="nimble-options" class="wrap">
<h1 class="nb-option-page-title">
<?php
printf('<span class="sek-nimble-title-icon"><img src="%1$s" alt="Build with Nimble Builder"></span>',
esc_url( NIMBLE_BASE_URL.'/assets/img/nimble/nimble_icon.svg?ver='.NIMBLE_VERSION )
);
echo apply_filters( 'nimble_parse_admin_text', esc_html( $page_title ) ) . wp_kses_post( apply_filters( 'nimble_option_title_icon_after', '' ) );
?>
</h1>
<div class="nav-tab-wrapper">
<?php
$allowed_tags = array(
'div' => array('class'=>true),
'span' => array('class'=>true),
'img' => array('class'=>true, 'src'=>true, 'alt'=>true),
);
foreach ($option_tabs as $tab_id => $tab_data ) {
printf('<a class="nav-tab %1$s" href="%2$s">%3$s</a>',
$tab_id === nb_get_active_option_tab() ? 'nav-tab-active' : '',
esc_url( admin_url( NIMBLE_OPTIONS_PAGE_URL ) . '&tab=' . $tab_id ),
wp_kses($tab_data['title'], $allowed_tags)
);
}
?>
</div>
<div class="tab-content-wrapper">
<?php
$_cb = $option_tabs[$active_tab_id]['content'];
if( is_string( $_cb ) && !empty( $_cb ) ) {
if ( function_exists( $_cb ) ) {
call_user_func( $_cb );
} else {
echo esc_attr($_cb);
}
} else if ( is_array($_cb) && 2 == count($_cb) ) {
if ( is_object($_cb[0]) ) {
$to_return = call_user_func( array( $_cb[0] , $_cb[1] ) );
}
//instantiated with an instance property holding the object ?
else if ( class_exists($_cb[0]) ) {
/* PHP 5.3- compliant*/
$class_vars = get_class_vars( $_cb[0] );
if ( isset( $class_vars[ 'instance' ] ) && method_exists( $class_vars[ 'instance' ], $_cb[1]) ) {
$to_return = call_user_func( array( $class_vars[ 'instance' ] , $_cb[1] ) );
}
else {
$_class_obj = new $_cb[0]();
if ( method_exists($_class_obj, $_cb[1]) )
$to_return = call_user_func( array( $_class_obj, $_cb[1] ) );
}
}
}
?>
<div>
</div><!-- .wrap -->
<?php
}
/* ------------------------------------------------------------------------- *
* ADD SETTINGS LINKS
/* ------------------------------------------------------------------------- */
function nb_settings_link($links) {
$doc_link = sprintf('<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>', 'https://docs.presscustomizr.com/article/337-getting-started-with-the-nimble-builder-plugin', __('Docs', 'text-doma') );
array_unshift($links, $doc_link );
$settings_link = sprintf('<a href="%1$s">%2$s</a>',
add_query_arg( array( 'tab' => 'options' ), admin_url( NIMBLE_OPTIONS_PAGE_URL ) ),
__('Settings', 'text-doma')
);
array_unshift($links, $settings_link );
return $links;
}
add_filter("plugin_action_links_".plugin_basename(NIMBLE_PLUGIN_FILE), '\Nimble\nb_settings_link' );
/* ------------------------------------------------------------------------- *
* SAVE OPTION HOOK + CUSTOMIZABLE REDIRECTION
/* ------------------------------------------------------------------------- */
// fired @'admin_post'
function nb_save_options() {
do_action('nb_admin_post');
//wp_safe_redirect( urldecode( admin_url( NIMBLE_OPTIONS_PAGE_URL ) ) );
nb_admin_redirect();
}
add_action( 'admin_post', '\Nimble\nb_save_options' );
// fired @'admin_post'
function nb_admin_redirect() {
$url = sanitize_text_field(
wp_unslash( $_POST['_wp_http_referer'] ) // Input var okay.
);
// Default option url : urldecode( admin_url( NIMBLE_OPTIONS_PAGE_URL ) )
$url = urldecode( $url );
$url = empty($url) ? urldecode( admin_url( NIMBLE_OPTIONS_PAGE_URL ) ) : $url;
// Finally, redirect back to the admin page.
// Note : filter 'nimble_admin_redirect_url' is used in NB pro to add query params used to display warning/error messages
wp_safe_redirect( apply_filters('nimble_admin_redirect_url', $url ) );
exit;
}
// @return bool
function nb_has_valid_nonce( $option_group = 'nb-options-save', $nonce = 'nb-options-nonce' ) {
// If the field isn't even in the $_POST, then it's invalid.
if ( !isset( $_POST[$nonce] ) ) { // Input var okay.
return false;
}
return wp_verify_nonce( wp_unslash( $_POST[$nonce] ), $option_group );
}
/* ------------------------------------------------------------------------- *
* REGISTER TABS
/* ------------------------------------------------------------------------- */
Nimble_Manager()->admin_option_tabs = array();
// @return void
function nb_register_option_tab( $tab ) {
$tab = wp_parse_args( $tab, array(
'id' => '',
'title' => '',
'page_title' => '',
'content' => '',
));
Nimble_Manager()->admin_option_tabs[$tab['id']] = $tab;
}
function nb_get_active_option_tab() {
// check that we have a tab param and that this tab is registered
$tab_id = isset( $_GET['tab'] ) ? sanitize_text_field($_GET['tab']) : 'welcome';
if ( !array_key_exists( $tab_id, Nimble_Manager()->admin_option_tabs ) ) {
sek_error_log( __FUNCTION__ . ' error => invalid tab');
$tab_id = 'welcome';
}
return $tab_id;
}
/* ------------------------------------------------------------------------- *
* WELCOME PAGE
/* ------------------------------------------------------------------------- */
nb_register_option_tab([
'id' => 'welcome',
'title' => __('Welcome', 'text-doma'),
'page_title' => __('Nimble Builder', 'nimble' ),
'content' => '\Nimble\print_welcome_page',
]);
function print_welcome_page() {
?>
<div class="nimble-welcome-content">
<?php echo wp_kses_post(sek_get_welcome_block()); ?>
</div>
<div class="clear"></div>
<hr/>
<div>
<h2><?php _e('Watch the video below for a brief overview of Nimble Builder features', 'text-doma'); ?></h2>
<iframe src="https://player.vimeo.com/video/328473405?loop=1&title=0&byline=0&portrait=0" width="640" height="424" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>
</div>
<?php
}
/* ------------------------------------------------------------------------- *
* DATA CLEANING for #826
/* ------------------------------------------------------------------------- */
// Fired when click on button in admin options
// introduced for https://github.com/presscustomizr/nimble-builder/issues/826
function sek_clean_all_nimble_data() {
if ( !isset( $_GET['clean_nb'] ) )
return;
// Do we have a nonce passed ?
if ( !isset( $_GET['ecnon'] ) )
return;
// validate the nonce and verify the user as permission to save.
if ( !wp_verify_nonce( wp_unslash( $_GET['ecnon'] ), 'nb-base-options' ) || !current_user_can( 'manage_options' ) )
return;
// Nimble CPT for skoped sections, for user templates, for user sections
$nb_cpt_list = [ 'NIMBLE_CPT', 'NIMBLE_TEMPLATE_CPT', 'NIMBLE_SECTION_CPT' ];
foreach( $nb_cpt_list as $nb_cpt ) {
if ( !defined( $nb_cpt ) )
continue;
$nb_cpt = constant($nb_cpt);
$query = new \WP_Query(
array(
'post_type' => $nb_cpt,
'post_status' => get_post_stati(),
'posts_per_page' => -1,
'no_found_rows' => true,
'cache_results' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'lazy_load_term_meta' => false,
)
);
if ( !is_array( $query->posts ) || empty( $query->posts ) ) {
continue;
}
foreach ( $query->posts as $post_object ) {
//permanently delete post ( unlike wp_trash_post() )
wp_delete_post($post_object->ID);
}
}
// Nimble options
$nb_opts = [
'NIMBLE_OPT_SEKTION_POST_INDEX',
'NIMBLE_OPT_NAME_FOR_GLOBAL_OPTIONS',
'NIMBLE_OPT_FOR_MODULE_CSS_READING_STATUS',
'NIMBLE_OPT_NAME_FOR_MOST_USED_FONTS',
'NIMBLE_OPT_FOR_GLOBAL_CSS',
'NIMBLE_OPT_NAME_FOR_SECTION_JSON',
'NIMBLE_OPT_NAME_FOR_BACKWARD_FIXES',
// admin options
'NIMBLE_OPT_NAME_FOR_SHORTCODE_PARSING',
'NIMBLE_OPT_NAME_FOR_DEBUG_MODE'
];
foreach( $nb_opts as $opt_name ) {
if ( !defined( $opt_name ) )
continue;
$opt_name = constant($opt_name);
delete_option( $opt_name );
}
// clean other options like : nimble_start_date, nimble_started_with_version, nimble_version,
foreach( [
'nimble_start_date',
'nimble_started_with_version',
'nimble_version_upgraded_from',
'nimble_version',
'nimble_last_update_notice',
'__nimble_options__'//<= deprecated option name
] as $opt_name ) {
delete_option( $opt_name );
}
// clean options like nimble___skp__post_page_1010 ( old way to map skope_id and skoped post )
sek_clean_options_starting_like( 'nimble___');
sek_clean_options_starting_like( 'nimblebuilder_pro_');
// Nimble transients
$nb_transients = [
'NIMBLE_FEEDBACK_NOTICE_ID',
'NIMBLE_FAWESOME_TRANSIENT_ID',
'NIMBLE_GFONTS_TRANSIENT_ID',
'NIMBLE_FEEDBACK_STATUS_TRANSIENT_ID',
'NIMBLE_API_CHECK_TRANSIENT_ID'
];
foreach( $nb_transients as $trans_id ) {
if ( !defined( $trans_id ) )
continue;
$trans_id = constant($trans_id);
delete_transient( $trans_id );
}
// => remove all other transients
sek_clean_transients_like( 'nimble_' );//'nimble_api_posts', 'nimble_api_tmpl_' . $tmpl_name
sek_clean_transients_like( 'nimble_preset_sections_' );//old transient for storing preset sections. Now fetched remotely. See #802
sek_clean_transients_like( 'section_params_transient' );//old transient that may still be there
sek_clean_transients_like( 'section_params_transient' );//old transient that may still be there
// Nimble CSS stylesheets
$css_dir_list = [ 'NIMBLE_DEPREC_ONE_CSS_FOLDER_NAME', 'NIMBLE_DEPREC_TWO_CSS_FOLDER_NAME', 'NIMBLE_CSS_FOLDER_NAME' ];
global $wp_filesystem;
require_once ( ABSPATH . '/wp-admin/includes/file.php' );
WP_Filesystem();
$upload_dir = wp_get_upload_dir();
foreach( $css_dir_list as $css_dir ) {
if ( !defined( $css_dir ) )
continue;
$css_dir = constant( $css_dir );
if ( is_multisite() ) {
$site = get_site();
$network_id = $site->site_id;
$site_id = $site->blog_id;
$css_dir = trailingslashit( $css_dir ) . trailingslashit( $network_id ) . $site_id;
}
$folder_path = wp_normalize_path( trailingslashit( $upload_dir['basedir'] ) . $css_dir );
if ( $wp_filesystem->exists( $folder_path ) ) {
$wp_filesystem->rmdir( $folder_path, true );
}
}
return 'success';
}
/* ------------------------------------------------------------------------- *
* OPTIONS PAGE
/* ------------------------------------------------------------------------- */
nb_register_option_tab([
'id' => 'options',
'title' => __('Options', 'text-doma'),
'page_title' => __('Nimble Builder Options', 'nimble' ),
'content' => '\Nimble\print_options_page',
]);
function print_options_page() {
?>
<form method="post" action="<?php echo esc_html( admin_url( 'admin-post.php' ) ); ?>">
<table class="form-table" role="presentation">
<tbody>
<tr>
<th scope="row"><?php _e('Shortcodes', 'text_doma'); ?></th>
<td>
<fieldset><legend class="screen-reader-text"><span><?php _e('Shortcodes', 'text_doma'); ?></span></legend>
<?php
$shortcode_opt_val = get_option( NIMBLE_OPT_NAME_FOR_SHORTCODE_PARSING );
?>
<label for="nb_shortcodes_parsed_in_czr"><input name="nb_shortcodes_parsed_in_czr" type="checkbox" id="nb_shortcodes_parsed_in_czr" value="on" <?php checked( $shortcode_opt_val, 'on' ); ?>>
<?php _e('Parse shortcodes when building your pages in the customizer', 'text_doma'); ?></label>
<p class="description"><?php _e('Shortcodes are disabled by default when customizing to prevent any conflicts with Nimble Builder interface.', 'text_doma'); ?></p>
</fieldset>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Widgets Module', 'text_doma'); ?></th>
<td>
<fieldset><legend class="screen-reader-text"><span><?php _e('Widgets module', 'text_doma'); ?></span></legend>
<?php
$widget_disabled_opt_val = get_option( NIMBLE_OPT_NAME_FOR_DISABLING_WIDGET_MODULE );
?>
<label for="nb_widgets_disabled_in_czr"><input name="nb_widgets_disabled_in_czr" type="checkbox" id="nb_widgets_disabled_in_czr" value="on" <?php checked( $widget_disabled_opt_val, 'on' ); ?>>
<?php _e('Disable the Widgets Module', 'text_doma'); ?></label>
</fieldset>
</td>
</tr>
<tr>
<th scope="row"><?php _e('Debug Mode', 'text_doma'); ?></th>
<td>
<fieldset><legend class="screen-reader-text"><span><?php _e('Debug Mode', 'text_doma'); ?></span></legend>
<?php
$nb_debug_mode_opt_val = get_option( NIMBLE_OPT_NAME_FOR_DEBUG_MODE );
?>
<label for="nb_debug_mode_active"><input name="nb_debug_mode_active" type="checkbox" id="nb_debug_mode_active" value="on" <?php checked( $nb_debug_mode_opt_val, 'on' ); ?>>
<?php _e('Activate the debug mode when customizing', 'text_doma'); ?></label>
<p class="description"><?php _e('In debug mode, during customization Nimble Builder deactivates all modules content and prints only the structure of your sections. This lets you troubleshoot, remove or edit your modules safely.', 'text_doma'); ?></p>
</fieldset>
</td>
</tr>
</tbody>
</table>
<?php
do_action('nb_admin_options_tab_after_content');
wp_nonce_field( 'nb-base-options', 'nb-base-options-nonce' );
submit_button();
?>
</form>
<hr/>
<table class="form-table" role="presentation">
<tbody>
<tr>
<th scope="row"><?php _e('Remove all Nimble Builder data', 'text_doma'); ?></th>
<td>
<fieldset><legend class="screen-reader-text"><span><?php _e('Remove all Nimble Builder data', 'text_doma'); ?></span></legend>
<?php
$refresh_url = add_query_arg( array( 'tab' => 'options', 'clean_nb' => 'true' ), admin_url( NIMBLE_OPTIONS_PAGE_URL ));
ob_start();
?>
var nb_toggle_clean_button = function() {
jQuery( function($) {
$('.nb-clean-traces-confirm').stop().slideToggle('fast');
});
};
var _nonce_value, _url
var nb_refresh_opt_page = function() {
jQuery( function($) {
_nonce_value = $('#nb-base-options-nonce').val();
_url = '<?php echo esc_url($refresh_url); ?>';
// add nonce as param so NB can verify it when the page reloads
if ( _nonce_value ) {
_url = _url + '&ecnon=' + _nonce_value;// looks like site.com/wp-admin/options-general.php?page=nb-options&tab=options&clean_nb=true&ecnon=7cc5758b65
}
window.location.href = _url;
});
};
<?php
$script = ob_get_clean();
wp_register_script( 'nb_options_js', '');
wp_enqueue_script( 'nb_options_js' );
wp_add_inline_script( 'nb_options_js', $script );
?>
<?php $clean_nb = isset( $_GET['clean_nb'] ) ? sanitize_text_field($_GET['clean_nb']) : false; ?>
<?php if ( $clean_nb ) : ?>
<?php $status = sek_clean_all_nimble_data(); ?>
<?php if ( 'success' === $status ) : ?>
<div id="message" class="updated notice">
<p class="nb-clean-traces-success"><strong><?php _e('All Nimble Builder data have been successfully removed from your WordPress website.', 'text_doma'); ?></strong></p>
</div>
<?php else : ?>
<div id="message" class="error notice">
<p><strong><?php _e('Security problem when trying to remove Nimble Builder data.', 'text_doma'); ?></strong></p>
</div>
<?php endif; ?>
<?php else : ?>
<p class="description"><?php _e('This will permanently remove all data created by Nimble Builder and stored in your database or as stylesheets : page customizations, custom sections, custom templates, options, CSS stylesheets.', 'text_doma'); ?></p><br/>
<button class="button" onclick="window.nb_toggle_clean_button()"><?php _e('Remove now', 'text_doma'); ?></button>
<div class="nb-clean-traces-confirm" style="display:none">
<p class="description"><?php _e('Once you delete Nimble Builder data, there is no going back. Please be certain. ', 'text_doma'); ?></p><br/>
<button class="button nb-permanent-removal-btn" onclick="window.nb_refresh_opt_page()"><?php _e('Yes I want to clean all data', 'text_doma'); ?></button>
</div>
<?php endif; ?>
</fieldset>
</td>
</tr>
</tbody>
</table>
<?php
}
add_action( 'nb_admin_post', '\Nimble\nb_save_base_options' );
// hook : nb_admin_post
function nb_save_base_options() {
// First, validate the nonce and verify the user as permission to save.
if ( !nb_has_valid_nonce( 'nb-base-options', 'nb-base-options-nonce' ) || !current_user_can( 'manage_options' ) )
return;
// Shortcode parsing when customizing
nb_maybe_update_checkbox_option( NIMBLE_OPT_NAME_FOR_SHORTCODE_PARSING, 'off' );
// Widgets disabled when customizing
nb_maybe_update_checkbox_option( NIMBLE_OPT_NAME_FOR_DISABLING_WIDGET_MODULE, 'off' );
// Debug mode
nb_maybe_update_checkbox_option( NIMBLE_OPT_NAME_FOR_DEBUG_MODE, 'off' );
}
// helper to update a checkbox option
// the option is updated only if different than the default val or if the option exists already
function nb_maybe_update_checkbox_option( $opt_name, $unchecked_value ) {
$opt_value = get_option( $opt_name );
$posted_value = array_key_exists( $opt_name, $_POST ) ? sanitize_text_field($_POST[$opt_name]) : $unchecked_value;
if ( $unchecked_value !== $posted_value ) {
update_option( $opt_name, esc_attr( $posted_value ), 'no' );
} else {
// if the option was never set before, then leave it not set
// otherwise update it to 'off'
if ( false !== $opt_value ) {
update_option( $opt_name, $unchecked_value, 'no' );
}
}
}
do_action('nb_base_admin_options_registered');
/* ------------------------------------------------------------------------- *
* RESTRICT USERS
/* ------------------------------------------------------------------------- */
//register option tab and print the form
if ( sek_is_pro() || sek_is_upsell_enabled() ) {
$restrict_users_title = __('Manage authorized users', 'text-doma');
if ( !sek_is_pro() ) {
$restrict_users_title = sprintf( '<span class="sek-pro-icon"><img src="%1$s" alt="Pro feature"></span><span class="sek-title-after-icon">%2$s</span>',
NIMBLE_BASE_URL.'/assets/czr/sek/img/pro_orange.svg?ver='.NIMBLE_VERSION,
__('Manage authorized users', 'nimble' )
);
}
nb_register_option_tab([
'id' => 'restrict_users',
'title' => $restrict_users_title,
'page_title' => __('Manage authorized users', 'nimble' ),
'content' => '\Nimble\print_restrict_users_options_content',
]);
function print_restrict_users_options_content() {
if ( !sek_is_pro() ) {
?>
<h4><?php _e('Nimble Builder can be used by default by all users with an administrator role. With Nimble Builder Pro you can decide which administrators are allowed to use the plugin.', 'text_domain'); ?></h4>
<h4><?php _e('Unauthorized users will not see any reference to Nimble Builder when editing a page, in the customizer and in the WordPress admin screens.', 'text_domain') ?></h4>
<a class="sek-pro-link" href="https://presscustomizr.com/nimble-builder-pro/" rel="noopener noreferrer" title="Go Pro" target="_blank"><?php _e('Go Pro', 'text_domain'); ?> <span class="dashicons dashicons-external"></span></a>
<?php
}
do_action( 'nb_restrict_user_content' );
}
}
/* ------------------------------------------------------------------------- *
* SYSTEM INFO
/* ------------------------------------------------------------------------- */
nb_register_option_tab([
'id' => 'system-info',
'title' => __('System info', 'text-doma'),
'page_title' => __('System info', 'nimble' ),
'content' => '\Nimble\print_system_info',
]);
function print_system_info() {
require_once( NIMBLE_BASE_PATH . '/inc/admin/system-info.php' );
?>
<h3><?php _e( 'System Informations', 'text_domain_to_be_chg' ); ?></h3>
<h4><?php _e( 'Please include your system informations when posting support requests.' , 'text_domain_to_be_chg' ) ?></h4>
<textarea readonly="readonly" onclick="this.focus();this.select()" id="system-info-textarea" name="tc-sysinfo" title="<?php _e( 'To copy the system info, click below then press Ctrl + C (PC) or Cmd + C (Mac).', 'text_domain_to_be_chg' ); ?>" style="width: 800px;min-height: 800px;font-family: Menlo,Monaco,monospace;background: 0 0;white-space: pre;overflow: auto;display:block;"><?php echo wp_kses_post(sek_config_infos()); ?></textarea>
<?php
}
/* ------------------------------------------------------------------------- *
* DOCUMENTATION
/* ------------------------------------------------------------------------- */
nb_register_option_tab([
'id' => 'doc',
'title' => __('Documentation', 'text-doma'),
'page_title' => __('Nimble Builder knowledge base', 'nimble' ),
'content' => '\Nimble\print_doc_page',
]);
function print_doc_page() {
?>
<div class="nimble-doc">
<ul>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/337-getting-started-with-the-nimble-builder-plugin"><span>Getting started with Nimble Page Builder for WordPress</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/386-how-to-access-the-live-customization-interface-of-the-nimble-builder"><span>How to access the live customization interface of Nimble Builder ?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/371-how-to-start-building-from-a-blank-page-with-the-wordpress-nimble-builder"><span>How to start building from a blank ( full width ) page with WordPress Nimble Builder?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href=" https://docs.presscustomizr.com/article/427-how-to-insert-and-edit-a-module-with-nimble-builder"><span>How to insert and edit a module with Nimble Builder ?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/358-building-your-header-and-footer-with-the-nimble-builder"><span>How to build your WordPress header and footer with Nimble Builder ?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/350-how-to-use-shortcodes-from-other-plugins-with-the-nimble-builder-plugin"><span>How to embed WordPress shortcodes in your pages with Nimble Builder ?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/366-how-to-add-an-anchor-to-a-section-and-integrate-it-into-the-menu-with-the-nimble-page-builder"><span>How to add an anchor to a section and integrate it into the menu with Nimble Page Builder ?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/380-how-to-set-a-parallax-background-for-a-section-in-wordpress-with-the-nimble-builder"><span>How to set a parallax background for a section in WordPress with Nimble Builder ?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/343-designing-for-mobile-devices-with-wordpress-nimble-builder"><span>Designing for mobile devices with the WordPress Nimble Builder</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/414-nimble-builder-and-website-performances"><span>Nimble Builder and website performance 🚀</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/393-how-to-add-post-grids-to-any-wordpress-page-with-nimble-builder"><span>How to add post grids to any WordPress page with Nimble Builder ?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/372-design-your-404-page-with-the-nimble-builder"><span>How to design your 404 error page with Nimble Builder</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/391-how-to-export-and-import-templates-with-nimble-builder"><span>How to reuse sections and templates with the export / import feature of Nimble Builder ?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/401-how-to-create-a-video-background-with-nimble-builder-wordpress-plugin"><span>How to create a video background with Nimble Builder WordPress plugin ?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/408-how-to-insert-a-responsive-carousel-in-your-wordpress-pages-with-nimble-builder"><span>How to insert a responsive carousel in your WordPress pages with Nimble Builder ?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/389-how-to-visualize-the-structure-of-the-content-created-with-nimble-builder"><span>How to visualize the structure of the content created with Nimble Builder ?</span></a></li>
<li><a target="_blank" rel="noopener noreferrer" href="https://docs.presscustomizr.com/article/383-how-to-customize-the-height-of-your-sections-and-columns-with-the-nimble-builder"><span>How to customize the height of your sections and columns with Nimble Builder ?</span></a></li>
</ul>
<a href="https://docs.presscustomizr.com/collection/334-nimble-page-builder" target="_blank" class="button button-primary button-hero" rel="noopener noreferrer"><span class="dashicons dashicons-search"></span>&nbsp;<?php _e('Explore Nimble Builder knowledge base', 'text-doma'); ?></a>
</div>
<?php
}
?>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,228 @@
<?php
namespace Nimble;
// Exit if accessed directly
if ( !defined( 'ABSPATH' ) ) exit;
/**
* Get system info
* Inspired by the system infos page for Easy Digital Download plugin
* @return string $return A string containing the info to output
*/
function sek_config_infos() {
global $wpdb;
if ( !class_exists( 'Browser' ) ) {
require_once( NIMBLE_BASE_PATH . '/inc/libs/browser.php' );
}
$browser = new \Browser();
// Get theme info
$theme_data = wp_get_theme();
$theme = $theme_data->Name . ' ' . $theme_data->Version;
$parent_theme = $theme_data->Template;
if ( !empty( $parent_theme ) ) {
$parent_theme_data = wp_get_theme( $parent_theme );
$parent_theme = $parent_theme_data->Name . ' ' . $parent_theme_data->Version;
}
$return = '### Begin System Info (Generated ' . date( 'Y-m-d H:i:s' ) . ') ###' . "";
// Site infos
$return .= "\n" .'------------ SITE INFO' . "\n";
$return .= 'Site URL: ' . site_url() . "\n";
$return .= 'Home URL: ' . home_url() . "\n";
$return .= 'Multisite: ' . ( is_multisite() ? 'Yes' : 'No' ) . "\n";
// Browser infos
$return .= "\n\n" . '------------ USER BROWSER' . "\n";
$return .= $browser;
$locale = get_locale();
// WordPress config
$return .= "\n\n" . '------------ WORDPRESS CONFIG' . "\n";
$return .= 'WP Version: ' . get_bloginfo( 'version' ) . "\n";
$return .= 'Language: ' . ( !empty( $locale ) ? $locale : 'en_US' ) . "\n";
$return .= 'Permalink Structure: ' . ( get_option( 'permalink_structure' ) ? get_option( 'permalink_structure' ) : 'Default' ) . "\n";
$return .= 'Active Theme: ' . $theme . "\n";
if ( $parent_theme !== $theme ) {
$return .= 'Parent Theme: ' . $parent_theme . "\n";
}
$return .= 'Show On Front: ' . get_option( 'show_on_front' ) . "\n";
// Only show page specs if frontpage is set to 'page'
if( get_option( 'show_on_front' ) == 'page' ) {
$front_page_id = get_option( 'page_on_front' );
$blog_page_id = get_option( 'page_for_posts' );
$return .= 'Page On Front: ' . ( $front_page_id != 0 ? get_the_title( $front_page_id ) . ' (#' . $front_page_id . ')' : 'Unset' ) . "\n";
$return .= 'Page For Posts: ' . ( $blog_page_id != 0 ? get_the_title( $blog_page_id ) . ' (#' . $blog_page_id . ')' : 'Unset' ) . "\n";
}
$return .= 'ABSPATH: ' . ABSPATH . "\n";
$return .= 'WP_DEBUG: ' . ( defined( 'WP_DEBUG' ) ? WP_DEBUG ? 'Enabled' : 'Disabled' : 'Not set' ) . "\n";
$return .= 'WP Memory Limit: ' . ( sek_let_to_num( WP_MEMORY_LIMIT )/( 1024 ) ) ."MB" . "\n";
//$return .= 'Registered Post Stati: ' . implode( ', ', get_post_stati() ) . "\n";
// Nimble configuration
$return .= "\n\n" . '------------ NIMBLE CONFIGURATION' . "\n";
$return .= 'Version: ' . NIMBLE_VERSION . "\n";
$return .= 'Upgraded From: ' . get_option( 'nimble_version_upgraded_from', 'None' ) . "\n";
$return .= 'Started With: ' . get_option( 'nimble_started_with_version', 'None' ) . "\n";
// sept 2020 : filter added to allow printing NB Pro versions info
$return = apply_filters('nb_admin_syst_info_after_nb_config', $return);
// Get plugins that have an update
$updates = get_plugin_updates();
// Must-use plugins
// NOTE: MU plugins can't show updates!
$muplugins = get_mu_plugins();
if( count( $muplugins ) > 0 ) {
$return .= "\n\n" . '------------ MU PLUGINS' . "\n";
foreach( $muplugins as $plugin => $plugin_data ) {
$return .= $plugin_data['Name'] . ': ' . $plugin_data['Version'] . "\n";
}
}
// WordPress active plugins
$return .= "\n\n" . '------------ WP ACTIVE PLUGINS' . "\n";
$plugins = get_plugins();
$active_plugins = get_option( 'active_plugins', array() );
foreach( $plugins as $plugin_path => $plugin ) {
if( !in_array( $plugin_path, $active_plugins ) )
continue;
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[$plugin_path]->update->new_version . ')' : '';
$return .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
}
// WordPress inactive plugins
$return .= "\n\n" . '------------ WP INACTIVE PLUGINS' . "\n";
foreach( $plugins as $plugin_path => $plugin ) {
if( in_array( $plugin_path, $active_plugins ) )
continue;
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[$plugin_path]->update->new_version . ')' : '';
$return .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
}
if( is_multisite() ) {
// WordPress Multisite active plugins
$return .= "\n\n" . '------------ NETWORK ACTIVE PLUGINS' . "\n";
$plugins = wp_get_active_network_plugins();
$active_plugins = get_site_option( 'active_sitewide_plugins', array() );
foreach( $plugins as $plugin_path ) {
$plugin_base = plugin_basename( $plugin_path );
if( !array_key_exists( $plugin_base, $active_plugins ) )
continue;
$update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[$plugin_path]->update->new_version . ')' : '';
$plugin = get_plugin_data( $plugin_path );
$return .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
}
}
// Server configuration
$return .= "\n\n" . '------------ WEBSERVER CONFIG' . "\n";
$return .= 'PHP Version: ' . PHP_VERSION . "\n";
$return .= 'MySQL Version: ' . $wpdb->db_version() . "\n";
$return .= 'Webserver Info: ' . sanitize_text_field($_SERVER['SERVER_SOFTWARE']) . "\n";
$return .= 'Write/Read permissions: ' . sek_get_write_permissions_status() . "\n";
// PHP configs
$return .= "\n\n" . '------------ PHP CONFIG' . "\n";
$return .= 'Memory Limit: ' . ini_get( 'memory_limit' ) . "\n";
$return .= 'Upload Max Size: ' . ini_get( 'upload_max_filesize' ) . "\n";
$return .= 'Post Max Size: ' . ini_get( 'post_max_size' ) . "\n";
$return .= 'Upload Max Filesize: ' . ini_get( 'upload_max_filesize' ) . "\n";
$return .= 'Time Limit: ' . ini_get( 'max_execution_time' ) . "\n";
$return .= 'Max Input Vars: ' . ini_get( 'max_input_vars' ) . "\n";
$return .= 'Display Errors: ' . ( ini_get( 'display_errors' ) ? 'On (' . ini_get( 'display_errors' ) . ')' : 'N/A' ) . "\n";
$return .= 'PHP Arg Separator: ' . ini_get( 'arg_separator.output' ) . "\n";
$return .= 'PHP Allow URL File Open: ' . ini_get( 'allow_url_fopen' ) . "\n";
// PHP extensions and such
// $return .= "\n\n" . '------------ PHP EXTENSIONS' . "\n";
// $return .= 'cURL: ' . ( function_exists( 'curl_init' ) ? 'Supported' : 'Not Supported' ) . "\n";
// $return .= 'fsockopen: ' . ( function_exists( 'fsockopen' ) ? 'Supported' : 'Not Supported' ) . "\n";
// $return .= 'SOAP Client: ' . ( class_exists( 'SoapClient' ) ? 'Installed' : 'Not Installed' ) . "\n";
// $return .= 'Suhosin: ' . ( extension_loaded( 'suhosin' ) ? 'Installed' : 'Not Installed' ) . "\n";
$return .= "\n\n" . '### End System Info ###';
return $return;
}
/**
* Does Size Conversions
*/
function sek_let_to_num( $v ) {
$l = substr( $v, -1 );
$ret = substr( $v, 0, -1 );
switch ( strtoupper( $l ) ) {
case 'P': // fall-through
case 'T': // fall-through
case 'G': // fall-through
case 'M': // fall-through
case 'K': // fall-through
$ret *= 1024;
break;
default:
break;
}
return $ret;
}
function sek_get_write_permissions_status() {
$permission_issues = array();
$writing_path_candidates = array();
$wp_upload_dir = wp_upload_dir();
if ( $wp_upload_dir['error'] ) {
$permission_issues[] = 'WordPress root uploads folder';
}
$nimble_css_folder_path = $wp_upload_dir['basedir'] . '/' . NIMBLE_CSS_FOLDER_NAME;
if ( is_dir( $nimble_css_folder_path ) ) {
$writing_path_candidates[ $nimble_css_folder_path ] = 'Nimble uploads folder';
}
$writing_path_candidates[ ABSPATH ] = 'WP root directory';
foreach ( $writing_path_candidates as $dir => $description ) {
if ( !is_writable( $dir ) ) {
$permission_issues[] = $description;
}
}
// oct 2020, for https://github.com/presscustomizr/nimble-builder/issues/749
$base_module_css_uri = NIMBLE_BASE_PATH . '/assets/front/css/modules/';
if ( !is_readable($base_module_css_uri) ) {
$permission_issues[] = 'module css folder not readable';
}
if ( $permission_issues ) {
$message = 'NOK => issues with : ';
$message .= implode( ' and ', $permission_issues );
} else {
$message = 'OK';
}
return $message;
}
?>
@@ -0,0 +1,171 @@
<?php
namespace Nimble;
if ( did_action('nimble_base_fmk_loaded') ) {
if ( ( defined( 'CZR_DEV' ) && CZR_DEV ) || ( defined( 'NIMBLE_DEV' ) && NIMBLE_DEV ) ) {
error_log( __FILE__ . ' => The czr_base_fmk has already been loaded' );
}
return;
}
// Set the namsepace as a global so we can use it when fired from another theme/plugin using the fmk
global $czr_base_fmk_namespace;
$czr_base_fmk_namespace = __NAMESPACE__ . '\\';
do_action( 'nimble_base_fmk_loaded' );
////////////////////////////////////////////////////////////////
// CZR_Fmk_Base
if ( !class_exists( 'CZR_Fmk_Base_Construct' ) ) :
class CZR_Fmk_Base_Construct {
static $instance;
public $registered_modules = array();//stores the collection of dynamic modules registration candidates
public $registered_settings = array();//stores the collection of dynamic settings registration candidates
public $default_dynamic_setting_params = array();
public $default_dynamic_module_params = array();
public $czr_css_attr = array();
public $current_module_params_when_ajaxing;// store the params when ajaxing and allows us to access the currently requested module params at any point of the ajax action
public static function czr_fmk_get_instance( $params ) {
if ( !isset( self::$instance ) && !( self::$instance instanceof CZR_Fmk_Base ) ) {
self::$instance = new CZR_Fmk_Base( $params );
}
return self::$instance;
}
//@param $params = array(
// 'base_url' => '' <= path to root class folder
//)
function __construct( $params = array() ) {
if ( !is_array( $params ) || empty( $params ) ) {
error_log( 'CZR_Fmk_Base => constructor => missing params');
return;
}
if ( empty( $params['base_url'] ) ) {
error_log( 'CZR_Fmk_Base => constructor => wrong params');
return;
}
// DEFINITIONS
if ( !defined( 'NIMBLE_FMK_BASE_URL' ) ) { define( 'NIMBLE_FMK_BASE_URL' , $params['base_url'] ); }
if ( !defined( 'NIMBLE_FMK_BASE_VERSION' ) ) { define( 'NIMBLE_FMK_BASE_VERSION' , isset( $params['version'] ) ? $params['version'] : '1.0.0' ); }
// Cache the css attr used in the tmpl builder and in the localized params
$this->czr_css_attr = $this->czr_fmk_get_customizer_controls_css_attr();
// Cache the default dynamic params
$this->default_dynamic_setting_params = $this->czr_fmk_get_default_dynamic_setting_params();
$this->default_dynamic_module_params = $this->czr_fmk_get_default_dynamic_module_params();
// Enqueue the fmk control js + a module tmpl
$this->czr_enqueue_fmk_resources();
// ajax filters + template generator
$this->czr_setup_ajax_tmpl();
// Dynamic Module Registration
$this->czr_setup_dynamic_settings_registration();
$this->czr_setup_dynamic_modules_registration();
// Content picker
$this->czr_setup_content_picker_ajax_actions();
}//__construct
// fired in the constructor to cache the params in a property
private function czr_fmk_get_default_dynamic_setting_params() {
return array(
'setting_id' => '',
'dynamic_registration' => true,
'module_type' => '',
'option_value' => array(),
'setting' => array(
'type' => 'option',
'default' => array(),
'transport' => 'refresh',
'setting_class' => '',//array( 'path' => '', 'name' => '' )
'sanitize_callback' => '',
'validate_callback' => '',
),
'section' => array(
'id' => '',
'title' => '',
'panel' => '',
'priority' => 10
),
'control' => array(
'label' => '',
'type' => 'czr_module',
'priority' => 10,
'control_class' => ''//array( 'path' => '', 'name' => '' )
)
);
}
// fired in the constructor to cache the params in a property
private function czr_fmk_get_default_dynamic_module_params() {
return array(
'dynamic_registration' => true,
'module_type' => '',
'sanitize_callback' => '', //<= used when dynamically registering a setting
'validate_callback' => '', //<= used when dynamically registering a setting
'customizer_assets' => array(
'control_js' => array(),
'localized_control_js' => array()
),
'tmpl' => array()
);
}
// Copy of czr_fn_get_controls_css_attr() and the equivalent in Hueman Pro
public function czr_fmk_get_customizer_controls_css_attr() {
return apply_filters('czr_fmk_controls_css_attr',
array(
'multi_input_wrapper' => 'czr-multi-input-wrapper',
'sub_set_wrapper' => 'czr-sub-set',
'sub_set_input' => 'czr-input',
'img_upload_container' => 'czr-imgup-container',
'edit_modopt_icon' => 'czr-toggle-modopt',
'close_modopt_icon' => 'czr-close-modopt',
'mod_opt_wrapper' => 'czr-mod-opt-wrapper',
'items_wrapper' => 'czr-items-wrapper',
'single_item' => 'czr-single-item',
'item_content' => 'czr-item-content',
'item_header' => 'czr-item-header',
'item_title' => 'czr-item-title',
'item_btns' => 'czr-item-btns',
'item_sort_handle' => 'czr-item-sort-handle',
//remove dialog
'display_alert_btn' => 'czr-display-alert',
'remove_alert_wrapper' => 'czr-remove-alert-wrapper',
'cancel_alert_btn' => 'czr-cancel-button',
'remove_view_btn' => 'czr-remove-button',
'edit_view_btn' => 'czr-edit-view',
//pre add dialog
'open_pre_add_btn' => 'czr-open-pre-add-new',
'adding_new' => 'czr-adding-new',
'pre_add_wrapper' => 'czr-pre-add-wrapper',
'pre_add_item_content' => 'czr-pre-add-view-content',
'cancel_pre_add_btn' => 'czr-cancel-add-new',
'add_new_btn' => 'czr-add-new',
'pre_add_success' => 'czr-add-success'
)
);
}
}//class
endif;
?>
@@ -0,0 +1,274 @@
<?php
////////////////////////////////////////////////////////////////
// CZR_Fmk_Base
if ( !class_exists( 'CZR_Fmk_Base_Load_Resources' ) ) :
class CZR_Fmk_Base_Load_Resources extends CZR_Fmk_Base_Construct {
// fired in the constructor
function czr_enqueue_fmk_resources() {
// Enqueue the fmk control js
add_action ( 'customize_controls_enqueue_scripts' , array( $this, 'ac_load_additional_controls_js' ) );
add_action ( 'customize_controls_enqueue_scripts' , array( $this, 'ac_load_additional_controls_css' ) );
// Enqueue the base preview js
//hook : customize_preview_init
add_action ( 'customize_preview_init' , array( $this, 'ac_customize_load_preview_js' ) );
// adds specific js templates for the czr_module control
add_action( 'customize_controls_print_footer_scripts', array( $this, 'ac_print_module_control_templates' ) , 1 );
add_action( 'customize_controls_print_footer_scripts', array( $this, 'ac_print_img_uploader_template' ) , 1 );
}
// hook : 'customize_controls_enqueue_scripts'
function ac_load_additional_controls_js() {
// Enqueue scripts/styles for the color picker.
// Probably already enqueued by the theme controls, but let's make sure they are.
wp_enqueue_script( 'wp-color-picker' );
wp_enqueue_style( 'wp-color-picker' );
// July 2020 : compatibility with WP5.5 => wpColorPickerL10n are not loaded by WP core anymore, but we need them for the custom czr-alpha-colorpicker.js
// see https://github.com/presscustomizr/nimble-builder/issues/729
global $wp_version;
if ( version_compare( $wp_version, '5.4.2' , '>=' ) ) {
wp_localize_script(
'wp-color-picker',
'nb_wpColorPickerL10n',
array(
'clear' => __( 'Clear' ),
'clearAriaLabel' => __( 'Clear color' ),
'defaultString' => __( 'Default' ),
'defaultAriaLabel' => __( 'Select default color' ),
'pick' => __( 'Select Color' ),
'defaultLabel' => __( 'Color value' )
)
);
}
//'czr-customizer-fmk' will be enqueued as a dependency of 'font-customizer-control' only in plugin mode
wp_enqueue_script(
'czr-customizer-fmk',
//dev / debug mode mode?
sprintf(
'%1$s/assets/js/%2$s',
NIMBLE_FMK_BASE_URL,
defined('CZR_DEV') && true === CZR_DEV ? '_0_ccat_czr-base-fmk.js' : '_0_ccat_czr-base-fmk.min.js'
),
array('customize-controls' , 'jquery', 'underscore'),
( defined('WP_DEBUG') && true === WP_DEBUG ) ? time() : NIMBLE_FMK_BASE_VERSION,
$in_footer = true
);
// When used with Customizr or Hueman, free and pro, we also need to load the theme js part
if ( false !== strpos( czr_get_parent_theme_slug(), 'customizr' ) || false !== strpos( czr_get_parent_theme_slug(), 'hueman' ) ) {
wp_enqueue_script(
'czr-theme-customizer-fmk',
//dev / debug mode mode?
sprintf(
'%1$s/assets/js/%2$s',
NIMBLE_FMK_BASE_URL,
defined('CZR_DEV') && true === CZR_DEV ? '_1_ccat_czr-theme-fmk.js' : '_1_ccat_czr-theme-fmk.min.js'
),
array( 'czr-customizer-fmk' ),
( defined('WP_DEBUG') && true === WP_DEBUG ) ? time() : NIMBLE_FMK_BASE_VERSION,
$in_footer = true
);
}
$theme_data = wp_get_theme();
$theme = $theme_data->Name . ' ' . $theme_data->Version;
$parent_theme = $theme_data->Template;
if ( !empty( $parent_theme ) ) {
$parent_theme_data = wp_get_theme( $parent_theme );
$parent_theme = $parent_theme_data->Name;
}
$parent_theme =strtolower($parent_theme);
//additional localized param when standalone plugin mode
wp_localize_script(
'czr-customizer-fmk',
'serverControlParams',
apply_filters( 'czr_js_customizer_control_params' ,
array(
'css_attr' => $this->czr_css_attr,
'isDevMode' => ( defined('WP_DEBUG') && true === WP_DEBUG ) || ( defined('CZR_DEV') && true === CZR_DEV ),
'docURL' => esc_url('docs.presscustomizr.com/'),
'i18n' => array(
'edit' => __('Edit', 'text_doma'),
'close' => __('Close', 'text_doma'),
'notset' => __('Not set', 'text_doma'),
'successMessage' => __('Done !', 'text_doma'),
'readDocumentation' => __('Learn more about this in the documentation', 'text_doma'),
'Settings' => __('Settings', 'text_doma'),
'Options for' => __('Options for', 'text_doma'),
// img upload translation
'select_image' => __( 'Select Image', 'text_doma' ),
'change_image' => __( 'Change Image', 'text_doma' ),
'remove_image' => __( 'Remove', 'text_doma' ),
'default_image' => __( 'Default', 'text_doma' ),
'placeholder_image' => __( 'No image selected', 'text_doma' ),
'frame_title_image' => __( 'Select Image', 'text_doma' ),
'frame_button_image' => __( 'Choose Image', 'text_doma' ),
'Customizing' => __('Customizing', 'text_doma'),
),
'paramsForDynamicRegistration' => apply_filters( 'czr_fmk_dynamic_setting_js_params', array() ),
'activeTheme' => $parent_theme
)
)
);
}
// Enqueue the fmk css when standalone plugin
// hook : 'customize_controls_enqueue_scripts'
function ac_load_additional_controls_css() {
wp_enqueue_style(
'czr-fmk-controls-style',
sprintf('%1$s/assets/css/czr-ccat-control-base%2$s.css', NIMBLE_FMK_BASE_URL, ( defined('WP_DEBUG') && true === WP_DEBUG ) ? '' : '.min'),
array( 'customize-controls' ),
( defined('WP_DEBUG') && true === WP_DEBUG ) ? time() : NIMBLE_FMK_BASE_VERSION,
$media = 'all'
);
//select2 stylesheet
//overriden by some specific style in czr-control-base.css
wp_enqueue_style(
'czr-select2-css',
sprintf('%1$s/assets/css/lib/czrSelect2.min.css', NIMBLE_FMK_BASE_URL ),
array( 'customize-controls' ),
( defined('WP_DEBUG') && true === WP_DEBUG ) ? time() : NIMBLE_FMK_BASE_VERSION,
$media = 'all'
);
wp_enqueue_style(
'czr-font-awesome',
sprintf('%1$s/assets/fonts/css/fontawesome-all.min.css', NIMBLE_FMK_BASE_URL ),
array(),
( defined('WP_DEBUG') && true === WP_DEBUG ) ? time() : NIMBLE_FMK_BASE_VERSION,
$media = 'all'
);
}
//hook : customize_preview_init
function ac_customize_load_preview_js() {
global $wp_version;
wp_enqueue_script(
'czr-customizer-preview' ,
sprintf(
'%1$s/assets/js/%2$s',
NIMBLE_FMK_BASE_URL,
defined('CZR_DEV') && true === CZR_DEV ? 'czr-preview-base.js' : 'czr-preview-base.min.js'
),
array( 'customize-preview', 'underscore'),
( defined('WP_DEBUG') && true === WP_DEBUG ) ? time() : NIMBLE_FMK_BASE_VERSION,
true
);
//localizes
wp_localize_script(
'czr-customizer-preview',
'serverPreviewParams',
apply_filters('czr_base_fmk_customizer_preview_params' ,
array(
'themeFolder' => get_template_directory_uri(),
//patch for old wp versions which don't trigger preview-ready signal => since WP 4.1
'preview_ready_event_exists' => version_compare( $wp_version, '4.1' , '>=' ),
'blogname' => get_bloginfo('name'),
'isRTL' => is_rtl()
)
)
);
}
// DO WE STILL NEED TO PRINT THIS TMPL ?
/////////////////////////////////////////////////////
/// WHEN EMBEDDED IN A CONTROL //////////////////////
/////////////////////////////////////////////////////
//add specific js templates for the czr_module control
//this is usually called in the manager for "registered" controls that need to be rendered with js
//for this control, we'll do it another way because we need several js templates
//=> that's why this control has not been "registered" and js templates are printed with the following action
function ac_print_module_control_templates() {
//Render the control wrapper for the CRUD types modules
?>
<?php //Render the control wrapper for the CRUD types modules ?>
<script type="text/html" id="tmpl-customize-control-czr_module-content">
<label for="{{ data.settings['default'] }}-button">
<# if ( data.label ) { #>
<span class="customize-control-title">{{ data.label }}</span>
<# } #>
<# if ( data.description ) { #>
<span class="description customize-control-description">{{{ data.description }}}</span>
<# } #>
</label>
</script>
<?php
}
// this template is used in setupImageUploaderSaveAsId and setupImageUploaderSaveAsUrl
// @see js CZRInputMths
function ac_print_img_uploader_template() {
?>
<script type="text/html" id="tmpl-czr-img-uploader">
<?php // case when a regular attachement object is provided, fetched from an id with wp.media.attachment( id ) ?>
<# if ( ( data.attachment && data.attachment.id ) ) { #>
<div class="attachment-media-view attachment-media-view-{{ data.attachment.type }} {{ data.attachment.orientation }}">
<div class="thumbnail thumbnail-{{ data.attachment.type }}">
<# if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.medium ) { #>
<img class="attachment-thumb" src="{{ data.attachment.sizes.medium.url }}" draggable="false" alt="" />
<# } else if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.full ) { #>
<img class="attachment-thumb" src="{{ data.attachment.sizes.full.url }}" draggable="false" alt="" />
<# } #>
</div>
<div class="actions">
<# if ( data.canUpload ) { #>
<button type="button" class="button remove-button">{{ data.button_labels.remove }}</button>
<button type="button" class="button upload-button control-focus" id="{{ data.settings['default'] }}-button">{{ data.button_labels.change }}</button>
<div style="clear:both"></div>
<# } #>
</div>
</div>
<?php // case when an url is provided ?>
<# } else if ( !_.isEmpty( data.fromUrl ) ) { #>
<div class="attachment-media-view">
<div class="thumbnail thumbnail-thumb">
<img class="attachment-thumb" src="{{ data.fromUrl }}" draggable="false" alt="" />
</div>
<div class="actions">
<# if ( data.canUpload ) { #>
<button type="button" class="button remove-button">{{ data.button_labels.remove }}</button>
<button type="button" class="button upload-button control-focus" id="{{ data.settings['default'] }}-button">{{ data.button_labels.change }}</button>
<div style="clear:both"></div>
<# } #>
</div>
</div>
<?php // case when neither attachement or url are provided => placeholder ?>
<# } else { #>
<div class="attachment-media-view">
<div class="placeholder">
{{ data.button_labels.placeholder }}
</div>
<div class="actions">
<# if ( data.canUpload ) { #>
<button type="button" class="button upload-button" id="{{ data.settings['default'] }}-button">{{ data.button_labels.select }}</button>
<# } #>
<div style="clear:both"></div>
</div>
</div>
<# } #>
</script>
<?php
}
}//class
endif;
?>
@@ -0,0 +1,199 @@
<?php
////////////////////////////////////////////////////////////////
// CZR_Fmk_Base
if ( !class_exists( 'CZR_Fmk_Base_Ajax_Filter' ) ) :
class CZR_Fmk_Base_Ajax_Filter extends CZR_Fmk_Base_Load_Resources {
// fired in the constructor
function czr_setup_ajax_tmpl() {
// this dynamic filter is declared on wp_ajax_ac_get_template
// It allows us to populate the server response with the relevant module html template
// $html = apply_filters( "ac_set_ajax_czr_tmpl___{$module_type}", '', $tmpl );
add_filter( "ac_set_ajax_czr_tmpl___all_modules", array( $this, 'ac_get_all_modules_tmpl' ), 10, 3 );
// fetch templates
add_action( 'wp_ajax_ac_get_template', array( $this, 'ac_set_ajax_czr_tmpl' ) );
}
// hook : 'wp_ajax_ac_get_template'
function ac_set_ajax_czr_tmpl() {
if ( !is_user_logged_in() ) {
wp_send_json_error( 'ac_set_ajax_czr_tmpl => unauthenticated' );
}
if ( !current_user_can( 'customize' ) ) {
status_header( 403 );
wp_send_json_error( 'ac_set_ajax_czr_tmpl => customize_not_allowed' );
} else if ( !isset( $_SERVER['REQUEST_METHOD'] ) || 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
status_header( 405 );
wp_send_json_error( 'ac_set_ajax_czr_tmpl => bad_method' );
}
$action = 'save-customize_' . get_stylesheet();
if ( !check_ajax_referer( $action, 'nonce', false ) ) {
wp_send_json_error( array(
'code' => 'invalid_nonce',
'message' => __( 'ac_set_ajax_czr_tmpl => Security check failed.' ),
) );
}
if ( !isset( $_POST['module_type'] ) || empty( $_POST['module_type'] ) ) {
wp_send_json_error( 'ac_set_ajax_czr_tmpl => missing module_type property in posted data' );
}
if ( !isset( $_POST['tmpl'] ) || empty( $_POST['tmpl'] ) ) {
wp_send_json_error( 'ac_set_ajax_czr_tmpl => missing tmpl property in posted data' );
}
$tmpl = sanitize_text_field($_POST['tmpl']);
$module_type = sanitize_text_field($_POST['module_type']);
///////////////////////////////////////////////////////////////////////
// @param $tmpl = 'item-inputs'
//
// @param $_POST = {
// [tmpl] => item-inputs
// [module_type] => czr_heading_child
// [module_id] => __nimble__51b2f35191b3__main_settings_czr_module
// [cache] => true
// [nonce] => b4b0aea848
// [control_id] => __nimble__51b2f35191b3__main_settings
// [item_model] => Array
// (
// [id] => czr_heading_child_0
// [title] =>
// [heading_text] => This is a heading.
// [heading_tag] => h1
// [h_alignment_css] => Array
// (
// [desktop] => center
// )
// [heading_title] =>
// [link-to] =>
// [link-custom-url] =>
// [link-target] =>
// )
// [action] => ac_get_template
// }
$html = apply_filters( "ac_set_ajax_czr_tmpl___{$module_type}", '', $tmpl, $_POST );
///////////////////////////////////////////////////////////////////////////
if ( empty( $html ) ) {
wp_send_json_error( 'ac_set_ajax_czr_tmpl => module ' . $module_type . ' => template empty for requested tmpl : ' . $tmpl );
} else {
wp_send_json_success( apply_filters( 'tmpl_results', $html, $tmpl ) );
}
}
// hook : ac_set_ajax_czr_tmpl___all_modules
// this dynamic filter is declared on wp_ajax_ac_get_template
// It allows us to populate the server response with the relevant module html template
// $html = apply_filters( "ac_set_ajax_czr_tmpl___{$module_type}", '', $tmpl );
//
// For all modules, there are 3 types of templates :
// 1) the pre-item, rendered when adding an item
// 2) the module meta options, or mod-opt
// 3) the item input options
function ac_get_all_modules_tmpl( $html, $requested_tmpl = '', $posted_params = array() ) {
$css_attr = $this->czr_css_attr;
if ( empty( $requested_tmpl ) ) {
wp_send_json_error( 'ac_get_all_modules_tmpl => the requested tmpl is empty' );
}
ob_start();
switch ( $requested_tmpl ) {
case 'crud-module-part' :
?>
<button class="<?php echo esc_attr($css_attr['open_pre_add_btn']); ?>"><?php _e('Add New', 'text_doma'); ?> <span class="fas fa-plus-square"></span></button>
<div class="<?php echo esc_attr($css_attr['pre_add_wrapper']); ?>">
<div class="<?php echo esc_attr($css_attr['pre_add_success']); ?>"><p></p></div>
<div class="<?php echo esc_attr($css_attr['pre_add_item_content']); ?>">
<span class="<?php echo esc_attr($css_attr['cancel_pre_add_btn']); ?> button"><?php _e('Cancel', 'text_doma'); ?></span> <span class="<?php echo esc_attr($css_attr['add_new_btn']); ?> button"><?php _e('Add it', 'text_doma'); ?></span>
</div>
</div>
<?php
break;
case 'rud-item-part' :
?>
<div class="<?php echo esc_attr($css_attr['item_header']); ?> czr-custom-model">
<# if ( ( true === data.is_sortable ) ) { #>
<div class="<?php echo esc_attr($css_attr['item_title']); ?> <?php echo esc_attr($css_attr['item_sort_handle']); ?>"><h4>{{ data.title }}</h4></div>
<# } else { #>
<div class="<?php echo esc_attr($css_attr['item_title']); ?>"><h4>{{ data.title }}</h4></div>
<# } #>
<div class="<?php echo esc_attr($css_attr['item_btns']); ?>"><a title="<?php _e('Edit', 'text_doma'); ?>" href="javascript:void(0);" class="fas fa-pencil-alt <?php echo esc_attr($css_attr['edit_view_btn']); ?>"></a>&nbsp;<a title="<?php _e('Remove', 'text_doma'); ?>" href="javascript:void(0);" class="fas fa-trash <?php echo esc_attr($css_attr['display_alert_btn']); ?>"></a></div>
<div class="<?php echo esc_attr($css_attr['remove_alert_wrapper']); ?>"></div>
</div>
<?php
break;
case 'rud-item-alert-part' :
?>
<p class="czr-item-removal-title"><?php _e('Are you sure you want to remove : <strong>{{ data.title }} ?</strong>', 'text_doma'); ?></p>
<span class="<?php echo esc_attr($css_attr['remove_view_btn']); ?> button"><?php _e('Yes', 'text_doma'); ?></span> <span class="<?php echo esc_attr($css_attr['cancel_alert_btn']); ?> button"><?php _e('No', 'text_doma'); ?></span>
<?php
break;
// this template is used in setupImageUploaderSaveAsId and setupImageUploaderSaveAsUrl
case 'img-uploader' :
?>
<?php // case when a regular attachement object is provided, fetched from an id with wp.media.attachment( id ) ?>
<# if ( ( data.attachment && data.attachment.id ) ) { #>
<div class="attachment-media-view attachment-media-view-{{ data.attachment.type }} {{ data.attachment.orientation }}">
<div class="thumbnail thumbnail-{{ data.attachment.type }}">
<# if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.medium ) { #>
<img class="attachment-thumb" src="{{ data.attachment.sizes.medium.url }}" draggable="false" alt="" />
<# } else if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.full ) { #>
<img class="attachment-thumb" src="{{ data.attachment.sizes.full.url }}" draggable="false" alt="" />
<# } #>
</div>
<div class="actions">
<# if ( data.canUpload ) { #>
<button type="button" class="button remove-button">{{ data.button_labels.remove }}</button>
<button type="button" class="button upload-button control-focus" id="{{ data.settings['default'] }}-button">{{ data.button_labels.change }}</button>
<div style="clear:both"></div>
<# } #>
</div>
</div>
<?php // case when an url is provided ?>
<# } else if ( !_.isEmpty( data.fromUrl ) ) { #>
<div class="attachment-media-view">
<div class="thumbnail thumbnail-thumb">
<img class="attachment-thumb" src="{{ data.fromUrl }}" draggable="false" alt="" />
</div>
<div class="actions">
<# if ( data.canUpload ) { #>
<button type="button" class="button remove-button">{{ data.button_labels.remove }}</button>
<button type="button" class="button upload-button control-focus" id="{{ data.settings['default'] }}-button">{{ data.button_labels.change }}</button>
<div style="clear:both"></div>
<# } #>
</div>
</div>
<?php // case when neither attachement or url are provided => placeholder ?>
<# } else { #>
<div class="attachment-media-view">
<div class="placeholder">
{{ data.button_labels.placeholder }}
</div>
<div class="actions">
<# if ( data.canUpload ) { #>
<button type="button" class="button upload-button" id="{{ data.settings['default'] }}-button">{{ data.button_labels.select }}</button>
<# } #>
<div style="clear:both"></div>
</div>
</div>
<# } #>
<?php
break;
}//switch
$html = ob_get_clean();
if ( empty( $html ) ) {
wp_send_json_error( 'ac_get_all_modules_tmpl => no template was found for tmpl => ' . $requested_tmpl );
}
return $html;//will be sent by wp_send_json_success() in ::ac_set_ajax_czr_tmpl()
}
}//class
endif;
?>
@@ -0,0 +1,377 @@
<?php
////////////////////////////////////////////////////////////////
// CZR_Fmk_Base
if ( !class_exists( 'CZR_Fmk_Base_Tmpl_Builder' ) ) :
class CZR_Fmk_Base_Tmpl_Builder extends CZR_Fmk_Base_Ajax_Filter {
/*********************************************************
** TMPL BUILDER
*********************************************************/
// This is the standard method to be used in a module to generate the item input template
// for pre-item, mod-opts and item-inputs
// fired in self::ac_get_ajax_module_tmpl
function ac_generate_czr_tmpl_from_map( $tmpl_map ) {
$html = '';
$default_input_entries = array(
'input_type' => 'text',
'title' => '',
'default' => '',
'html_before' => '',
'notice_before_title' => '',
'notice_before' => '',
'notice_after' => '',
'placeholder' => '',
'html_after' => '',
// typically used for the number and range inputs
'step' => '',
'min' => '',
'max' => '',
'orientation' => '',//vertical / horizontal
'unit' => '',//% or px for example
'transport' => '',//<= can be set as a data property of the input wrapper, and used when instanciating the input
'input_template' => '',//<= a static html template can be provided to render the input, in this case it will be used in priority
'tmpl_callback' => '',//<= a callback function to be used to print the entire input template, including the wrapper
'width-100' => false,//<= to force a width of 100%
'title_width' => '',//width-80
'input_width' => '',//width-20
'code_type' => '',//<= used for to specify the language type of the codemirror editor (if not specified full a html editor will be instantiated)
'refresh_markup' => null,
'refresh_stylesheet' => null,
'refresh_fonts' => null,
'refresh_preview' => null,
'sanitize_cb' => '',
'validate_cb' => '',
'css_selectors' => array(), //<= used to specify css selectors on which we will apply the dynamically generated css for a given input id @see \Nimble\sek_add_css_rules_for_generic_css_input_types'
'css_identifier' => '',//<= the identifier allowing us to map a css generation rule. @see \Nimble\sek_add_css_rules_for_css_sniffed_input_id
'important_input_list' => array(),//<= the list of input_id that an important input can flag !important @see \Nimble\sek_add_css_rules_for_css_sniffed_input_id
'choices' => array(), // <= used to declare the option list of a select input
'has_device_switcher' => false, // <= indicates if the input value shall be saved by device or not
'scope' => 'local',// <= used when resetting the sections
// introduced for https://github.com/presscustomizr/nimble-builder/issues/403
'editor_params' => array(),
// introduced for https://github.com/presscustomizr/nimble-builder/issues/431
'section_collection' => array()
);
foreach( $tmpl_map as $input_id => $input_data ) {
if ( !is_string( $input_id ) || empty( $input_id ) ) {
wp_send_json_error( __FUNCTION__ . ' => wrong input id' );
break;
}
if ( !is_array( $input_data ) ) {
wp_send_json_error( __FUNCTION__ . ' => wrong var type for the input_data of input id : ' . esc_attr($input_id) );
break;
}
// check that we have no unknown entries in the provided input_data
$maybe_diff = array_diff_key( $input_data, $default_input_entries );
if ( !empty( $maybe_diff ) ) {
error_log('<' . __FUNCTION__ . '>');
error_log( '=> at least one unknown param in the registered input params for input id : ' . esc_attr($input_id) );
error_log( print_r( $maybe_diff, true ) );
error_log('</' . __FUNCTION__ . '>');
break;
}
// we're clear, let's go
$input_data = wp_parse_args( $input_data, $default_input_entries );
// Do we have a specific template provided ?
if ( !empty( $input_data[ 'tmpl_callback' ] ) && function_exists( $input_data[ 'tmpl_callback' ] ) ) {
$html .= call_user_func_array( $input_data[ 'tmpl_callback' ], array( $input_data ) );
} else {
$html .= $this->ac_get_default_input_tmpl( $input_id, $input_data );
}
}
return $html;////will be sent by wp_send_json_success() in ::ac_set_ajax_czr_tmpl()
}
// Fired in ac_generate_czr_tmpl_from_map
function ac_get_default_input_tmpl( $input_id, $input_data ) {
if ( !array_key_exists( 'input_type', $input_data ) || empty( $input_data[ 'input_type' ] ) ) {
wp_send_json_error( 'ac_get_input_tmpl => missing input type for input id : ' . esc_attr($input_id) );
}
$input_type = $input_data[ 'input_type' ];
// some inputs have a width of 100% even if not specified in the input_data
$is_width_100 = true === $input_data[ 'width-100' ];
if ( in_array( $input_type, array( 'color', 'radio', 'textarea' ) ) ) {
$is_width_100 = true;
}
$css_attr = $this->czr_css_attr;
ob_start();
// <INPUT WRAPPER>
printf( '<div class="%1$s %2$s %3$s" data-input-type="%4$s" %5$s>',
esc_attr($css_attr['sub_set_wrapper']),
$is_width_100 ? 'width-100' : '',
'hidden' === $input_type ? 'hidden' : '',
esc_attr($input_type),
esc_attr(!empty( $input_data['transport'] ) ? 'data-transport="'. $input_data['transport'] .'"' : '')
);
?>
<?php if ( !empty( $input_data['html_before'] ) ) : ?>
<div class="czr-html-before"><?php echo wp_kses_post($input_data['html_before']); ?></div>
<?php endif; ?>
<?php if ( !empty( $input_data['notice_before_title'] ) ) : ?>
<span class="czr-notice"><?php echo wp_kses_post($input_data['notice_before_title']); ?></span><br/>
<?php endif; ?>
<?php
// no need to print a title for an hidden input
if ( $input_type !== 'hidden' ) {
printf( '<div class="customize-control-title %1$s">%2$s</div>',
esc_attr(!empty( $input_data['title_width'] ) ? $input_data['title_width'] : ''),
wp_kses_post($input_data['title'])
);
}
?>
<?php if ( !empty( $input_data['notice_before'] ) ) : ?>
<span class="czr-notice"><?php echo wp_kses_post($input_data['notice_before']); ?></span>
<?php endif; ?>
<?php printf( '<div class="czr-input %1$s">', esc_attr(!empty( $input_data['input_width'] ) ? $input_data['input_width'] : '' ) ); ?>
<?php
if ( !empty( $input_data['input_template'] ) && is_string( $input_data['input_template'] ) ) {
echo wp_kses_post($input_data['input_template']);
} else {
// THIS IS WHERE THE ACTUAL INPUT CONTENT IS SET
$this->ac_set_input_tmpl_content( $input_type, $input_id, $input_data );
}
?>
</div><?php // class="czr-input" ?>
<?php if ( !empty( $input_data['notice_after'] ) ) : ?>
<span class="czr-notice"><?php echo wp_kses_post($input_data['notice_after']); ?></span>
<?php endif; ?>
<?php if ( !empty( $input_data['html_after'] ) ) : ?>
<div class="czr-html-after"><?php echo wp_kses_post($input_data['html_after']); ?></div>
<?php endif; ?>
</div> <?php //class="$css_attr['sub_set_wrapper']" ?>
<?php
// </INPUT WRAPPER>
$tmpl_html = apply_filters( "czr_set_input_tmpl___{$input_type}", ob_get_clean(), $input_id, $input_data );
//error_log( print_r($tmpl_html, true ) );
if ( empty( $tmpl_html ) ) {
wp_send_json_error( 'ac_get_input_tmpl => no html returned for input ' . esc_attr($input_id) );
}
return $tmpl_html;
}//ac_get_input_tmpl()
// fired in ::ac_get_default_input_tmpl();
private function ac_set_input_tmpl_content( $input_type, $input_id, $input_data ) {
$css_attr = $this->czr_css_attr;
$input_tmpl_content = null;
// First fires a hook to allow the input content to be remotely set
// For example the module_picker, the spacing, h_text_alignment... are printed this way
ob_start();
do_action( 'czr_set_input_tmpl_content', $input_type, $input_id, $input_data );
$input_tmpl_content = ob_get_clean();
if ( !empty( $input_tmpl_content ) ) {
echo wp_kses_post($input_tmpl_content);
} else {
// Then, if we have no content yet, let's go thought the default input cases
switch ( $input_type ) {
/* ------------------------------------------------------------------------- *
* HIDDEN
/* ------------------------------------------------------------------------- */
case 'hidden':
?>
<input data-czrtype="<?php echo esc_attr($input_id); ?>" type="hidden" value=""></input>
<?php
break;
/* ------------------------------------------------------------------------- *
* SELECT
/* ------------------------------------------------------------------------- */
case 'czr_layouts'://<= specific to the hueman theme
case 'select'://<= used in the customizr and hueman theme
case 'simpleselect'://<=used in Nimble Builder
?>
<select data-czrtype="<?php echo esc_attr($input_id); ?>"></select>
<?php
break;
// multiselect with select2() js library
case 'multiselect':
case 'category_picker':
?>
<select multiple="multiple" data-czrtype="<?php echo esc_attr($input_id); ?>"></select>
<?php
break;
/* ------------------------------------------------------------------------- *
* TEXT
/* ------------------------------------------------------------------------- */
case 'text' :
?>
<input data-czrtype="<?php echo esc_attr($input_id); ?>" type="text" value="" placeholder="<?php echo esc_attr($input_data['placeholder']); ?>"></input>
<?php
break;
/* ------------------------------------------------------------------------- *
* NUMBER
/* ------------------------------------------------------------------------- */
case 'number' :
?>
<?php
printf( '<input data-czrtype="%4$s" type="number" %1$s %2$s %3$s value="{{ data[\'%4$s\'] }}" />',
esc_attr(!empty( $input_data['step'] ) ? 'step="'. $input_data['step'] .'"' : ''),
esc_attr(!empty( $input_data['min'] ) ? 'min="'. $input_data['min'] .'"' : ''),
esc_attr(!empty( $input_data['max'] ) ? 'max="'. $input_data['max'] .'"' : ''),
esc_attr($input_id)
);
?>
<?php
break;
/* ------------------------------------------------------------------------- *
* COLOR
/* ------------------------------------------------------------------------- */
case 'wp_color_alpha' :
?>
<input data-czrtype="<?php echo esc_attr($input_id); ?>" class="width-100" data-alpha="true" type="text" value="{{ data['<?php echo esc_attr($input_id); ?>'] }}"></input>
<?php
break;
case 'color' :
?>
<input data-czrtype="<?php echo esc_attr($input_id); ?>" type="text" value="{{ data['<?php echo esc_attr($input_id); ?>'] }}"></input>
<?php
break;
/* ------------------------------------------------------------------------- *
* CHECK
/* ------------------------------------------------------------------------- */
case 'checkbox' :
case 'check' :
?>
<#
var _checked = ( false != data['<?php echo esc_attr($input_id); ?>'] ) ? "checked=checked" : '';
#>
<input data-czrtype="<?php echo esc_attr($input_id); ?>" type="checkbox" {{ _checked }}></input>
<?php
break;
// DEPRECATED since april 2nd 2019
case 'gutencheck' :
?>
<#
var _checked = ( false != data['<?php echo esc_attr($input_id); ?>'] ) ? "checked=checked" : '';
#>
<span class="czr-toggle-check"><input class="czr-toggle-check__input" data-czrtype="<?php echo esc_attr($input_id); ?>" type="checkbox" {{ _checked }}><span class="czr-toggle-check__track"></span><span class="czr-toggle-check__thumb"></span></span>
<?php
break;
case 'nimblecheck' :
?>
<#
var _checked = ( false != data['<?php echo esc_attr($input_id); ?>'] ) ? "checked=checked" : '';
#>
<?php
// when input and label are tied by an id - for relationship
// clicking on any of them changes the input
// => We need a unique ID here so that input and label are tied by a unique link
// @see https://www.w3.org/TR/html401/interact/forms.html#h-17.9.1
// @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input/checkbox
$unique_id = sprintf('%04X%04X', mt_rand(0, 65535), mt_rand(0, 65535));
?>
<div class="nimblecheck-wrap">
<input id="nimblecheck-<?php echo esc_attr($unique_id); ?>" data-czrtype="<?php echo esc_attr($input_id); ?>" type="checkbox" {{ _checked }} class="nimblecheck-input">
<label for="nimblecheck-<?php echo esc_attr($unique_id); ?>" class="nimblecheck-label">Switch</label>
</div>
<?php
break;
/* ------------------------------------------------------------------------- *
* TEXTAREA
/* ------------------------------------------------------------------------- */
case 'textarea' :
// Added an id attribute for https://github.com/presscustomizr/nimble-builder/issues/403
// needed to instantiate wp.editor.initialize(...)
?>
<textarea id="textarea-{{ data.id }}" data-czrtype="<?php echo esc_attr($input_id); ?>" class="width-100" name="textarea" rows="10" cols="">{{ data.value }}</textarea>
<?php
break;
/* ------------------------------------------------------------------------- *
* IMG UPLOAD AND UPLOAD URL
/* ------------------------------------------------------------------------- */
case 'upload' :
case 'upload_url' :
?>
<input data-czrtype="<?php echo esc_attr($input_id); ?>" type="hidden"/>
<div class="<?php echo esc_attr($css_attr['img_upload_container']); ?>"></div>
<?php
break;
/* ------------------------------------------------------------------------- *
* RANGE
/* ------------------------------------------------------------------------- */
case 'range_slider' :
case 'range' :
?>
<?php //<# //console.log( 'IN php::ac_get_default_input_tmpl() => data range_slide => ', data ); #> ?>
<?php
printf( '<input data-czrtype="%5$s" type="range" %1$s %2$s %3$s %4$s value="{{ data[\'%5$s\'] }}" />',
esc_attr(!empty( $input_data['orientation'] ) ? 'data-orientation="'. $input_data['orientation'] .'"' : ''),
esc_attr(!empty( $input_data['unit'] ) ? 'data-unit="'. $input_data['unit'] .'"' : ''),
esc_attr(!empty( $input_data['min'] ) ? 'min="'. $input_data['min'] .'"' : ''),
esc_attr(!empty( $input_data['max'] ) ? 'max="'. $input_data['max'] .'"' : ''),
esc_attr($input_id)
);
?>
<?php
break;
/* ------------------------------------------------------------------------- *
* CONTENT PICKER
/* ------------------------------------------------------------------------- */
case 'content_picker' :
?>
<?php
printf( '<span data-czrtype="%1$s"></span>', esc_attr($input_id) );
?>
<?php
break;
/* ------------------------------------------------------------------------- *
* PROBLEM : if we reach this case, it means that
* - the input template has not been populated by the first do_action('czr_set_input_tmpl_content')
* - no default input template is defined for the requested input type
/* ------------------------------------------------------------------------- */
default :
// this input type has no template, this is a problem
wp_send_json_error( 'ERROR => ' . __CLASS__ . '::' . __FUNCTION__ . ' this input type has no template : ' . $input_type );
break;
}//switch ( $input_type ) {
}//if ( empty( $input_tmpl_content ) )()
}//function()
}//class
endif;
?>
@@ -0,0 +1,343 @@
<?php
////////////////////////////////////////////////////////////////
// CZR_Fmk_Base
if ( !class_exists( 'CZR_Fmk_Dyn_Setting_Registration' ) ) :
class CZR_Fmk_Dyn_Setting_Registration extends CZR_Fmk_Base_Tmpl_Builder {
//fired in the constructor
function czr_setup_dynamic_settings_registration() {
add_action( 'customize_register', array( $this, 'czr_setup_dynamic_setting_registration' ), 10 );
// if we have dynamic setting params, let's add a filter to serverControlParams
// filter declared when localizing 'serverControlParams' @see resources
add_filter( 'czr_fmk_dynamic_setting_js_params', array( $this, 'czr_setup_localized_params_for_dynamic_js_registration' ), 20 );
// when not dynamically registered
// TO DEPRECATE ?
//add_action( 'customize_register', array( $this, 'czr_register_not_dynamic_settings' ), 20 );
}
////////////////////////////////////////////////////////////////
// PRE REGISTRATION FOR SETTINGS
// Default params
// array(
// 'setting_id' => '',
// 'dynamic_registration' => true,
// 'module_type' => '',
// 'option_value' => array(),
// 'setting' => array(
// 'type' => 'option',
// 'default' => array(),
// 'transport' => 'refresh',
// 'setting_class' => '',//array( 'path' => '', 'name' => '' )
// 'sanitize_callback' => '',
// 'validate_callback' => '',
// ),
// 'section' => array(
// 'id' => '',
// 'title' => '',
// 'panel' => '',
// 'priority' => 10
// ),
// 'control' => array(
// 'label' => '',
// 'type' => 'czr_module',
// 'priority' => 10,
// 'control_class' => ''//array( 'path' => '', 'name' => '' )
// )
// )
function czr_pre_register_dynamic_setting( $setting_params ) {
if ( !is_array( $setting_params ) || empty( $setting_params ) ) {
error_log( 'czr_pre_register_dynamic_setting => empty $setting_params submitted' );
return;
}
if ( !array_key_exists( 'setting_id', $setting_params ) || empty( $setting_params['setting_id'] ) ) {
error_log( 'czr_pre_register_dynamic_setting => missing setting id' );
return;
}
// normalize
$setting_params = wp_parse_args( $setting_params, $this -> default_dynamic_setting_params );
$registered = $this->registered_settings;
$setting_id_candidate = $setting_params['setting_id'];
// A setting id can be registered only once.
// Already registered ?
if ( array_key_exists( $setting_id_candidate, $registered ) ) {
error_log( 'czr_pre_register_dynamic_setting => setting id already registered => ' . $setting_id_candidate );
return;
}
$registered[ $setting_id_candidate ] = $setting_params;
$this->registered_settings = $registered;
}
////////////////////////////////////////////////////////////////
// FILTER DYNAMIC SETTING AND CLASS ARGS
// hook : customize_register
// Those filters are declared by WP core in class-wp-customize-manager.php
// in => add_action( 'customize_register', array( $this, 'register_dynamic_settings' ), 11 );
function czr_setup_dynamic_setting_registration( $wp_customize ) {
add_filter( 'customize_dynamic_setting_args', array( $this, 'czr_setup_customizer_dynamic_setting_args' ), 10, 2 );
add_filter( 'customize_dynamic_setting_class', array( $this, 'czr_setup_customizer_dynamic_setting_class' ), 10, 3 );
}
// hook : 'customize_dynamic_setting_args'
function czr_setup_customizer_dynamic_setting_args( $setting_args, $setting_id ) {
//sek_error_log( __CLASS__ . '::' . __FUNCTION__ , $this->registered_settings );
if ( !is_array( $this->registered_settings ) || empty( $this->registered_settings ) )
return $setting_args;
// let's initialize the args to the provided param
$registered_setting_args = $setting_args;
// loop on each registered modules
foreach ( $this->registered_settings as $registerered_setting_id => $params ) {
if ( array_key_exists('dynamic_registration', $params) && true !== $params['dynamic_registration'] ) {
continue;
}
$params = wp_parse_args( $params, $this -> default_dynamic_setting_params );
if ( $registerered_setting_id != $setting_id || empty( $registerered_setting_id ) )
continue;
$setting_args = is_array( $params['setting'] ) ? $params['setting'] : array();
$setting_args = wp_parse_args( $setting_args, array(
'type' => 'option',
'default' => array(),
'transport' => 'refresh',
'sanitize_callback' => '',
'validate_callback' => ''
) );
// Provide new setting args
$registered_setting_args = array(
'type' => empty( $setting_args[ 'type' ] ) ? 'option' : $setting_args[ 'type' ],
'default' => array(),
'transport' => $setting_args[ 'transport' ],
'sanitize_callback' => ( !empty( $setting_args[ 'sanitize_callback' ] ) && function_exists( $setting_args[ 'sanitize_callback' ] ) ) ? $setting_args[ 'sanitize_callback' ] : '',
'validate_callback' => ( !empty( $setting_args[ 'validate_callback' ] ) && function_exists( $setting_args[ 'validate_callback' ] ) ) ? $setting_args[ 'validate_callback' ] : ''
);
// if this is a module setting, it can have specific sanitize and validate callback set for the module
// Let's check if the module_type is registered, and if there are any callback set.
// If a match is found, we'll use those callback
$module_params = $this -> czr_get_registered_dynamic_module( $params[ 'module_type' ] );
if ( false !== $module_params && is_array( $module_params ) ) {
if ( array_key_exists( 'validate_callback', $module_params ) && function_exists( $module_params[ 'validate_callback' ] ) ) {
$registered_setting_args[ 'validate_callback' ] = $module_params[ 'validate_callback' ];
}
if ( array_key_exists( 'sanitize_callback', $module_params ) && function_exists( $module_params[ 'sanitize_callback' ] ) ) {
$registered_setting_args[ 'sanitize_callback' ] = $module_params[ 'sanitize_callback' ];
}
}
//error_log( 'REGISTERING DYNAMICALLY for setting =>'. $setting_id );
}
return $registered_setting_args;
}
// hook : 'customize_dynamic_setting_class'
function czr_setup_customizer_dynamic_setting_class( $class, $setting_id, $args ) {
if ( !is_array( $this->registered_settings ) || empty( $this->registered_settings ) )
return $class;
// let's initialize the args to the provided class
$registered_setting_class = $class;//'WP_Customize_Setting' by default
// loop on each registered modules
foreach ( $this->registered_settings as $registerered_setting_id => $params ) {
$params = wp_parse_args( $params, $this -> default_dynamic_setting_params );
if ( true !== $params['dynamic_registration'] ) {
continue;
}
if ( $registerered_setting_id != $setting_id || empty( $registerered_setting_id ) )
continue;
$setting_args = $params['setting'];
if ( is_array( $setting_args ) && array_key_exists( 'setting_class', $setting_args ) ) {
// provide new setting class if exists and not yet loaded
if ( is_array( $setting_args[ 'setting_class' ] ) && array_key_exists( 'name', $setting_args[ 'setting_class' ] ) && array_key_exists( 'path', $setting_args[ 'setting_class' ] ) ) {
if ( !class_exists( $setting_args[ 'setting_class' ][ 'name' ] ) && file_exists( $setting_args[ 'setting_class' ]['path'] ) ) {
require_once( $setting_args[ 'setting_class' ]['path'] );
}
if ( class_exists( $setting_args[ 'setting_class' ][ 'name' ] ) ) {
$registered_setting_class = $setting_args[ 'setting_class' ][ 'name' ];
}
}
}
//error_log( 'REGISTERING CLASS DYNAMICALLY for setting =>'. $setting_id );
}
return $registered_setting_class;
}
////////////////////////////////////////////////////////////////
// Print js params for dynamic control and section registration
// hook : czr_fmk_dynamic_setting_js_params'
// @param js_param = array()
function czr_setup_localized_params_for_dynamic_js_registration( $js_params ) {
// error_log( '<REGISTERED SETTINGS>' );
// error_log( print_r( $this->registered_settings, true ) );
// error_log( '</REGISTERED SETTINGS>' );
if ( !is_array( $this->registered_settings ) || empty( $this->registered_settings ) )
return $js_params;
$js_params = !is_array( $js_params ) ? array() : $js_params;
// 'localized_control_js' => array(
// 'deps' => 'czr-customizer-fmk',
// 'global_var_name' => 'socialLocalized',
// 'params' => array(
// //Social Module
// 'defaultSocialColor' => 'rgb(90,90,90)',
// 'defaultSocialSize' => 14,
// //option value for dynamic registration
//
// )
// 'dynamic_setting_registration' => array(
// 'values' => $args['option_value'],
// 'section' => $args['section']
// )
// )
// loop on each registered modules
foreach ( $this->registered_settings as $registerered_setting_id => $params ) {
$params = wp_parse_args( $params, $this -> default_dynamic_setting_params );
// We need the 'option_value' entry, even if empty
if ( !array_key_exists( 'option_value', $params ) || !is_array( $params['option_value'] ) )
continue;
// Check if not already setup
if ( array_key_exists( $registerered_setting_id, $params ) ) {
error_log( 'czr_setup_localized_params_for_dynamic_js_registration => js_params already setup for setting : ' . $registerered_setting_id );
}
$js_params[ $registerered_setting_id ] = array(
'setting_id' => $registerered_setting_id,
'module_type' => $params[ 'module_type' ],
'module_registration_params' => $this -> czr_get_registered_dynamic_module( $params[ 'module_type' ] ),
'option_value' => $params['option_value'],
// 'setting' => array(
// 'type' => 'option',
// 'default' => array(),
// 'transport' => 'refresh',
// 'setting_class' => '',//array( 'path' => '', 'name' => '' )
// 'sanitize_callback' => '',
// 'validate_callback' => '',
// ),
'setting' => array_key_exists( 'setting', $params ) ? $params[ 'setting' ] : array(),
// 'section' => array(
// 'id' => '',
// 'title' => '',
// 'panel' => '',
// 'priority' => 10
// ),
'section' => array_key_exists( 'section', $params ) ? $params[ 'section' ] : array(),
// 'control' => array(
// 'label' => '',
// 'type' => 'czr_module',
// 'priority' => 10,
// 'control_class' => ''//array( 'path' => '', 'name' => '' )
// ),
'control' => array_key_exists( 'control', $params ) ? $params[ 'control' ] : array(),
);
}
return $js_params;
}
////////////////////////////////////////////////////////////////
// TO DEPRECATE ?
// REGISTER IF NOT DYNAMIC
// hook : customize_register
function czr_register_not_dynamic_settings( $wp_customize ) {
// error_log('<MODULE REGISTRATION>');
// error_log(print_r( $this->registered_settings, true ));
// error_log('</MODULE REGISTRATION>');
if ( !is_array( $this->registered_settings ) || empty( $this->registered_settings ) )
return;
// loop on each registered modules
foreach ( $this->registered_settings as $setting_id => $params ) {
$params = wp_parse_args( $params, $this -> default_dynamic_setting_params );
if ( true === $params['dynamic_registration'] )
continue;
// SETTING
$setting_args = $params['setting'];
$registered_setting_class = 'WP_Customize_Setting';
if ( is_array( $setting_args ) && array_key_exists( 'setting_class', $setting_args ) ) {
// provide new setting class if exists and not yet loaded
if ( is_array( $setting_args[ 'setting_class' ] ) && array_key_exists( 'name', $setting_args[ 'setting_class' ] ) && array_key_exists( 'path', $setting_args[ 'setting_class' ] ) ) {
if ( !class_exists( $setting_args[ 'setting_class' ][ 'name' ] ) && file_exists( $setting_args[ 'setting_class' ]['path'] ) ) {
require_once( $setting_args[ 'setting_class' ]['path'] );
}
if ( class_exists( $setting_args[ 'setting_class' ][ 'name' ] ) ) {
$registered_setting_class = $setting_args[ 'setting_class' ][ 'name' ];
}
}
}
$wp_customize->add_setting( new $registered_setting_class( $wp_customize, $setting_id, array(
'default' => $setting_args[ 'default' ],
'type' => $setting_args[ 'type' ],
'sanitize_callback' => isset( $settings_args[ 'sanitize_callback' ] ) ? $settings_args[ 'sanitize_callback' ] : ''
) ) );
// CONTROL
$control_args = $params['control'];
$registered_control_class = 'WP_Customize_Control';
if ( is_array( $control_args ) && array_key_exists( 'control_class', $control_args ) ) {
// provide new setting class if exists and not yet loaded
if ( is_array( $control_args[ 'control_class' ] ) && array_key_exists( 'name', $control_args[ 'control_class' ] ) && array_key_exists( 'path', $control_args[ 'control_class' ] ) ) {
if ( !class_exists( $control_args[ 'control_class' ][ 'name' ] ) && file_exists( $control_args[ 'control_class' ]['path'] ) ) {
require_once( $control_args[ 'control_class' ]['path'] );
}
if ( class_exists( $control_args[ 'control_class' ][ 'name' ] ) ) {
$registered_control_class = $control_args[ 'control_class' ][ 'name' ];
}
}
}
$wp_customize -> add_control( new $registered_control_class( $wp_customize, $setting_id, array(
'type' => $control_args[ 'type' ],
'label' => $control_args[ 'label' ],
'section' => $params[ 'section' ]['id'],
'module_type' => $params[ 'module_type' ]
) ) );
}//foreach
}//czr_register_not_dynamic_settings
}//class
endif;
?>
@@ -0,0 +1,304 @@
<?php
////////////////////////////////////////////////////////////////
// CZR_Fmk_Base
if ( !class_exists( 'CZR_Fmk_Dyn_Module_Registration' ) ) :
class CZR_Fmk_Dyn_Module_Registration extends CZR_Fmk_Dyn_Setting_Registration {
//fired in the constructor
function czr_setup_dynamic_modules_registration() {
// Dynamic Module Registration
add_action( 'init', array( $this, 'czr_schedule_ajax_tmpl' ) );
// Enqueue the module customizer control assets
add_action( 'customize_controls_enqueue_scripts' , array( $this, 'czr_register_dynamic_modules_customizer_control_assets' ) );
}
////////////////////////////////////////////////////////////////
// PRE REGISTRATION FOR MODULES
// Default params
// array(
// 'module_type' => '',
// 'customizer_assets' => array(
// 'control_js' => array(),
// 'localized_control_js' => array()
// ),
// 'tmpl' => array()
// )
function czr_pre_register_dynamic_module( $module_params ) {
// error_log( '<czr_pre_register_dynamic_module>' );
// error_log( print_r( $module_params, true ) );
// error_log( '</czr_pre_register_dynamic_module>' );
if ( !is_array( $module_params ) || empty( $module_params ) ) {
sek_error_log( 'czr_pre_register_dynamic_module => empty $module_params submitted' );
return;
}
if ( !array_key_exists( 'module_type', $module_params ) || empty( $module_params['module_type'] ) ) {
sek_error_log( 'czr_pre_register_dynamic_module => missing module_type' );
return;
}
// normalize
$module_params = wp_parse_args( $module_params, $this->default_dynamic_module_params );
$registered = $this->registered_modules;
$module_type_candidate = $module_params['module_type'];
// A module type can be registered only once.
// Already registered ?
if ( array_key_exists( $module_type_candidate, $registered ) ) {
//sek_error_log( 'czr_pre_register_dynamic_module => module type already registered => ' . $module_type_candidate );
return;
}
$registered[ $module_type_candidate ] = $module_params;
$this->registered_modules = $registered;
}
// HELPER
// @return boolean or array of module params
function czr_get_registered_dynamic_module( $module_type = '' ) {
$registered = $this->registered_modules;
if ( empty( $module_type ) || !is_array( $registered ) || empty( $registered ) )
return;
return array_key_exists( $module_type , $registered ) ? $registered[ $module_type ] : false;
}
// @return bool
function czr_is_module_registered( $module_type = '' ) {
$registered = $this->registered_modules;
if ( empty( $module_type ) || !is_array( $registered ) || empty( $registered ) )
return;
return array_key_exists( $module_type , $registered );
}
////////////////////////////////////////////////////////////////
// ENQUEUE ASSETS
// hook : customize_controls_enqueue_scripts
//
// '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' => 'socialLocalized',
// 'params' => array(
// //Social Module
// 'defaultSocialColor' => 'rgb(90,90,90)',
// 'defaultSocialSize' => 14,
// //option value for dynamic registration
// )
// )
// ),
function czr_register_dynamic_modules_customizer_control_assets() {
if ( !is_array( $this->registered_modules ) || empty( $this->registered_modules ) )
return;
$wp_scripts = wp_scripts();
// loop on each registered modules
foreach ( $this->registered_modules as $module_type => $params ) {
$params = wp_parse_args( $params, $this->default_dynamic_module_params );
//error_log( print_r( $params, true ) );
$control_js_params = $params[ 'customizer_assets' ][ 'control_js' ];
// Enqueue the list of registered scripts
if ( !empty( $control_js_params ) ) {
foreach ( $control_js_params as $handle => $script_args ) {
if ( !isset( $wp_scripts->registered[$handle] ) ) {
wp_enqueue_script(
$handle,
array_key_exists( 'src', $script_args ) ? $script_args['src'] : null,
array_key_exists( 'deps', $script_args ) ? $script_args['deps'] : null,
array_key_exists( 'ver', $script_args ) ? $script_args['ver'] : null,
array_key_exists( 'in_footer', $script_args ) ? $script_args['in_footer'] : false
);
} else {
error_log( __CLASS__ . '::' . __FUNCTION__ . " => handle already registered : " . $handle . " , this asset won't be enqueued => " . $script_args['src'] );
}
}
}
// 'localized_control_js' => array(
// 'deps' => 'czr-customizer-fmk',
// 'global_var_name' => 'socialLocalized',
// 'params' => array(
// //Social Module
// 'defaultSocialColor' => 'rgb(90,90,90)',
// 'defaultSocialSize' => 14,
// //option value for dynamic registration
// )
// )
// Print localized params if any
if ( array_key_exists( 'localized_control_js', $params[ 'customizer_assets' ] ) ) {
$localized_control_js_params = is_array( $params[ 'customizer_assets' ][ 'localized_control_js' ] ) ? $params[ 'customizer_assets' ][ 'localized_control_js' ] : array();
if ( is_array( $localized_control_js_params ) && !empty( $localized_control_js_params ) ) {
wp_localize_script(
array_key_exists( 'deps', $localized_control_js_params ) ? $localized_control_js_params['deps'] : '',
array_key_exists( 'global_var_name', $localized_control_js_params ) ? $localized_control_js_params['global_var_name'] : '',
array_key_exists( 'params', $localized_control_js_params ) ? $localized_control_js_params['params'] : array()
);
}
}
}//foreach
}
////////////////////////////////////////////////////////////////
// AJAX TEMPLATE FILTERS
// hook : init
function czr_schedule_ajax_tmpl() {
if ( !is_array( $this->registered_modules ) || empty( $this->registered_modules ) )
return;
foreach ( $this->registered_modules as $module_type => $params ) {
$params = wp_parse_args( $params, $this->default_dynamic_module_params );
if ( !empty( $params['tmpl'] ) ) {
$module_type = $params['module_type'];
// filter declared with $html = apply_filters( "ac_set_ajax_czr_tmpl___{$module_type}", '', $tmpl, $_POST );
add_filter( "ac_set_ajax_czr_tmpl___{$module_type}", array( $this, 'ac_get_ajax_module_tmpl'), 10, 3 );
}
}//foreach
}
// AJAX TMPL FILTERS
// this dynamic filter is declared on wp_ajax_ac_get_template
// It allows us to populate the server response with the relevant module html template
// $html = apply_filters( "ac_set_ajax_czr_tmpl___{$module_type}", '', $tmpl );
//
// Each template is built from a map, each input type having its own unique piece of tmpl
//
// 3 types of templates :
// 1) the pre-item, rendered when adding an item
// 2) the module meta options, or mod-opt
// 3) the item input options
// @param $posted_params is the $_POST
// hook : ac_set_ajax_czr_tmpl___{$module_type}
function ac_get_ajax_module_tmpl( $html, $requested_tmpl = '', $posted_params = array() ) {
// error_log( '<REGISTERED MODULES>' );
// error_log( print_r( $this->registered_modules, true ) );
// error_log( '</REGISTERED MODULES>' );
// error_log( '<GET AJAX MODULE TMPL>' );
// error_log( print_r( $posted_params, true ) );
// error_log( '</GET AJAX MODULE TMPL>' );
// the module type is sent in the $posted_params
if ( !is_array( $posted_params ) || empty( $posted_params ) ) {
wp_send_json_error( 'ac_get_ajax_module_tmpl => empty posted_params' );
}
if ( !array_key_exists( 'module_type', $posted_params ) || empty( $posted_params['module_type'] ) ) {
wp_send_json_error( 'ac_get_ajax_module_tmpl => missing module_type' );
}
// if ( !array_key_exists( 'control_id', $posted_params ) || empty( $posted_params['control_id'] ) ) {
// wp_send_json_error( 'ac_get_ajax_module_tmpl => missing control_id' );
// }
// find the requested module_id in the list of registered modules
$registered_modules = $this->registered_modules;
$module_type = $posted_params['module_type'];
if ( !array_key_exists( $module_type, $registered_modules ) || empty( $registered_modules[ $module_type ] ) ) {
return;
}
$module_params = $registered_modules[ $module_type ];
// Store the params now, so we can access them when rendering the input templates
$this->current_module_params_when_ajaxing = $module_params;
$tmpl_params = $module_params[ 'tmpl' ];
// Enqueue the list of registered scripts
if ( empty( $tmpl_params ) ) {
return;
}
// the requested_tmpl can be pre-item, mod-opt or item-inputs
$tmpl_map = array_key_exists( $requested_tmpl, $tmpl_params ) ? $tmpl_params[ $requested_tmpl ] : array();
if ( empty( $tmpl_map ) ) {
return;
}
// Do we have tabs ?
// With tabs
// 'tabs' => array(
// array(
// 'title' => __('Spacing', 'text_doma'),
// 'inputs' => array(
// 'padding' => array(
// 'input_type' => 'number',
// 'title' => __('Padding', 'text_doma')
// ),
// 'margin' => array(
// 'input_type' => 'number',
// 'title' => __('Margin', 'text_doma')
// )
// )
// ),
// array( ... )
//
//
// Without tabs :
// 'padding' => array(
// 'input_type' => 'number',
// 'title' => __('Padding', 'text_doma')
// ),
// 'margin' => array(
// 'input_type' => 'number',
// 'title' => __('Margin', 'text_doma')
// )
if ( array_key_exists( 'tabs', $tmpl_map ) ) {
ob_start();
?>
<div class="tabs tabs-style-topline">
<nav>
<ul>
<?php
// print the tabs nav
foreach ( $tmpl_map['tabs'] as $_key => $tab ) {
printf( '<li data-tab-id="section-topline-%1$s" %2$s><a href="#"><span>%3$s</span></a></li>',
esc_attr($_key + 1),
esc_attr(array_key_exists('attributes', $tab) ? $tab['attributes'] : ''),
esc_html($tab['title'])
);
}//foreach
?>
</ul>
</nav>
<div class="content-wrap">
<?php
foreach ( $tmpl_map['tabs'] as $_key => $tab ) {
printf( '<section id="section-topline-%1$s">%2$s</section>',
esc_attr($_key + 1),
wp_kses_post($this->ac_generate_czr_tmpl_from_map( $tab['inputs'] ))
);
}//foreach
?>
</div><?php //.content-wrap ?>
</div><?php //.tabs ?>
<?php
return ob_get_clean();
} else {
return $this->ac_generate_czr_tmpl_from_map( $tmpl_map );
}
}
}//class
endif;
?>
@@ -0,0 +1,449 @@
<?php
/**
* Customizer ajax content picker actions
*
*/
// CZR_Fmk_Base
if ( !class_exists( 'CZR_Fmk_Base' ) ) :
class CZR_Fmk_Base extends CZR_Fmk_Dyn_Module_Registration {
//fired in the constructor
public function czr_setup_content_picker_ajax_actions() {
if ( current_user_can( 'customize' ) ) {
add_action( 'wp_ajax_load-available-content-items-customizer' , array( $this, 'ajax_load_available_items' ) );
add_action( 'wp_ajax_search-available-content-items-customizer' , array( $this, 'ajax_search_available_items' ) );
}
// CONTENT PICKER INPUT
//add the _custom_ item to the content picker retrieved in ajax
//add_filter( 'content_picker_ajax_items', array( $this, 'czr_add_custom_item_to_ajax_results' ), 10, 3 );
}
// hook : 'content_picker_ajax_items'
function czr_add_custom_item_to_ajax_results( $items, $page, $context ) {
if ( is_numeric( $page ) && $page < 1 ) {
return array_merge(
array(
array(
'title' => sprintf( '<span style="font-weight:bold">%1$s</span>', __('Set a custom url', 'text_doma') ),
'type' => '',
'type_label' => '',
'object' => '',
'id' => '_custom_',
'url' => ''
)
),
$items
);
} else {
return $items;
}
}
//hook : 'pre_post_link'
function dont_use_fancy_permalinks() {
return '';
}
/* ------------------------------------------------------------------------- *
* LOAD
/* ------------------------------------------------------------------------- */
/**
* Ajax handler for loading available content items.
* hook : wp_ajax_load-available-content-items-customizer
*/
public function ajax_load_available_items() {
$action = 'save-customize_' . get_stylesheet();
if ( !check_ajax_referer( $action, 'nonce', false ) ) {
wp_send_json_error( array(
'code' => 'invalid_nonce',
'message' => __( 'ajax_load_available_items => Security check failed.' ),
) );
}
if ( !current_user_can( 'customize' ) ) {
wp_send_json_error('ajax_load_available_items => user_cant_edit_theme_options');
}
if ( !isset( $_POST['wp_object_types'] ) || empty( $_POST['wp_object_types'] ) ) {
wp_send_json_error( 'czr_ajax_content_picker_missing_type_or_object_parameter' );
}
if ( !isset( $_POST['page'] ) ) {
wp_send_json_error( 'czr_ajax_content_picker_missing_pagination_param' );
}
//error_log( print_r($_POST, true ) );
$wp_object_types = json_decode( wp_unslash( $_POST['wp_object_types'] ), true );
//$wp_object_types should look like :
//array(
// post : '',//<= all post types
// taxonomy : ''//<= all taxonomy types
//) OR
//array(
// post : [ 'page', 'cpt1', ...]
// taxonomy : [ 'category', 'tag', 'Custom_Tax_1', ... ]
//) OR
//array(
// post : [ 'page', 'cpt1', ...]
// taxonomy : '_none_'//<= don't load or search taxonomies
//)
if ( !is_array( $wp_object_types ) || empty( $wp_object_types ) ) {
wp_send_json_error( 'czr_ajax_content_picker_missing_object_types' );
}
$page = empty( $_POST['page'] ) ? 0 : absint( $_POST['page'] );
//do we need that ?
// if ( $page < 1 ) {
// $page = 1;
// }
$items = array();
add_filter( 'pre_post_link', array( $this, 'dont_use_fancy_permalinks' ), 999 );
foreach ( $wp_object_types as $_type => $_obj_types ) {
if ( '_none_' == $_obj_types )
continue;
$item_candidates = $this -> load_available_items_query(
array(
'type' => $_type, //<= post or taxonomy
'object_types' => $_obj_types,//<= '' or array( type1, type2, ... )
'page' => $page
)
);
if ( is_array( $item_candidates ) ) {
$items = array_merge(
$items,
$item_candidates
);
}
}
remove_filter( 'pre_post_link', array( $this, 'dont_use_fancy_permalinks' ), 999 );
if ( is_wp_error( $items ) ) {
wp_send_json_error( $items->get_error_code() );
} else {
wp_send_json_success( array(
'items' => apply_filters( 'content_picker_ajax_items', $items, $page, 'ajax_load_available_items' )
) );
}
}
/**
* Performs the post_type and taxonomy queries for loading available items.
*
* @since
* @access public
*
* @param string $type Optional. Accepts any custom object type and has built-in support for
* 'post_type' and 'taxonomy'. Default is 'post_type'.
* @param string $object Optional. Accepts any registered taxonomy or post type name. Default is 'page'.
* @param int $page Optional. The page number used to generate the query offset. Default is '0'.
* @return WP_Error|array Returns either a WP_Error object or an array of menu items.
*/
public function load_available_items_query( $args ) {
//normalize args
$args = wp_parse_args( $args, array(
'type' => 'post',
'object_types' => '_all_',//could be page, post, or any CPT
'page' => 0
) );
$type = $args['type'];
$object_types = $args['object_types'];
$page = $args['page'];
$items = array();
if ( 'post' === $type ) {
//What are the post types we need to fetch ?
if ( '_all_' == $object_types || !is_array( $object_types ) || ( is_array( $object_types ) && empty( $object_types ) ) ) {
$post_types = get_post_types( array( 'public' => true ) );
} else {
$post_types = $object_types;
}
if ( !$post_types || !is_array( $post_types ) || empty( $post_types ) ) {
return new \WP_Error( 'czr_contents_invalid_post_type' );
}
$posts = get_posts( array(
'numberposts' => 5,
'offset' => 5 * $page,
'orderby' => 'date',
'order' => 'DESC',
'post_type' => $post_types,
) );
foreach ( $posts as $post ) {
$post_title = $post->post_title;
if ( '' === $post_title ) {
// translators: %d: ID of a post
$post_title = sprintf( __( '#%d (no title)', 'text_doma' ), $post->ID );
}
$items[] = array(
'title' => html_entity_decode( $post_title, ENT_QUOTES, get_bloginfo( 'charset' ) ),
'type' => 'post',
'type_label' => get_post_type_object( $post->post_type )->labels->singular_name,
'object' => $post->post_type,
'id' => intval( $post->ID ),
'url' => get_permalink( intval( $post->ID ) ),
);
}
} elseif ( 'taxonomy' === $type ) {
//What are the taxonomy types we need to fetch ?
if ( '_all_' == $object_types || !is_array( $object_types ) || ( is_array( $object_types ) && empty( $object_types ) ) ) {
$taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'names' );
} else {
$taxonomies = $object_types;
}
if ( !$taxonomies || !is_array( $taxonomies ) || empty( $taxonomies ) ) {
return new \WP_Error( 'czr_contents_invalid_post_type' );
}
$terms = get_terms( $taxonomies, array(
'child_of' => 0,
'exclude' => '',
'hide_empty' => false,
'hierarchical' => 1,
'include' => '',
'number' => 5,
'offset' => 5 * $page,
'order' => 'DESC',
'orderby' => 'count',
'pad_counts' => false,
) );
if ( is_wp_error( $terms ) ) {
return $terms;
}
foreach ( $terms as $term ) {
$items[] = array(
'title' => html_entity_decode( $term->name, ENT_QUOTES, get_bloginfo( 'charset' ) ),
'type' => 'taxonomy',
'type_label' => get_taxonomy( $term->taxonomy )->labels->singular_name,
'object' => $term->taxonomy,
'id' => intval( $term->term_id ),
'url' => get_term_link( intval( $term->term_id ), $term->taxonomy ),
);
}
}
/**
* Filters the available items.
*
* @since
*
* @param array $items The array of menu items.
* @param string $type The object type.
* @param string $object The object name.
* @param int $page The current page number.
*/
$items = apply_filters( 'czr_customize_content_picker_available_items', $items, $type, $object_types, $page );
return $items;
}
/* ------------------------------------------------------------------------- *
* SEARCH
/* ------------------------------------------------------------------------- */
/**
* Ajax handler for searching available menu items.
* hook : wp_ajax_search-available-content-items-customizer
*/
public function ajax_search_available_items() {
$action = 'save-customize_' . get_stylesheet();
if ( !check_ajax_referer( $action, 'nonce', false ) ) {
wp_send_json_error( array(
'code' => 'invalid_nonce',
'message' => __( 'ajax_load_available_items => Security check failed.' ),
) );
}
if ( !current_user_can( 'customize' ) ) {
wp_send_json_error('ajax_load_available_items => user_cant_edit_theme_options');
}
if ( !isset( $_POST['wp_object_types'] ) || empty( $_POST['wp_object_types'] ) ) {
wp_send_json_error( 'czr_ajax_content_picker_missing_type_or_object_parameter' );
}
if ( empty( $_POST['search'] ) ) {
wp_send_json_error( 'czr_contents_missing_search_parameter' );
}
$p = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 0;
if ( $p < 1 ) {
$p = 1;
}
$s = sanitize_text_field( wp_unslash( $_POST['search'] ) );
$wp_object_types = json_decode( wp_unslash( $_POST['wp_object_types'] ), true );
//$wp_object_types should look like :
//array(
// post : '',//<= all post types
// taxonomy : ''//<= all taxonomy types
//) OR
//array(
// post : [ 'page', 'cpt1', ...]
// taxonomy : [ 'category', 'tag', 'Custom_Tax_1', ... ]
//) OR
//array(
// post : [ 'page', 'cpt1', ...]
// taxonomy : '_none_'//<= don't load or search taxonomies
//)
if ( !is_array( $wp_object_types ) || empty( $wp_object_types ) ) {
wp_send_json_error( 'czr_ajax_content_picker_missing_object_types' );
}
$items = array();
add_filter( 'pre_post_link', array( $this, 'dont_use_fancy_permalinks' ), 999 );
foreach ( $wp_object_types as $_type => $_obj_types ) {
if ( '_none_' == $_obj_types )
continue;
$item_candidates = $this -> search_available_items_query(
array(
'type' => $_type, //<= post or taxonomy
'object_types' => $_obj_types,//<= '' or array( type1, type2, ... )
'pagenum' => $p,
's' => $s
)
);
if ( is_array( $item_candidates ) ) {
$items = array_merge(
$items,
$item_candidates
);
}
}
remove_filter( 'pre_post_link', array( $this, 'dont_use_fancy_permalinks' ), 999 );
if ( empty( $items ) ) {
wp_send_json_success( array( 'message' => __( 'No results found.', 'text_doma') ) );
} else {
wp_send_json_success( array(
'items' => apply_filters( 'content_picker_ajax_items', $items, $p, 'ajax_search_available_items' )
) );
}
}
/**
* Performs post queries for available-item searching.
*
* Based on WP_Editor::wp_link_query().
*
* @since 4.3.0
* @access public
*
* @param array $args Optional. Accepts 'pagenum' and 's' (search) arguments.
* @return array Menu items.
*/
public function search_available_items_query( $args = array() ) {
//normalize args
$args = wp_parse_args( $args, array(
'pagenum' => 1,
's' => '',
'type' => 'post',
'object_types' => '_all_'//could be page, post, or any CPT
) );
$object_types = $args['object_types'];
//TODO: need a search only on the allowed types
$items = array();
if ( 'post' === $args['type'] ) {
//What are the post types we need to fetch ?
if ( '_all_' == $object_types || !is_array( $object_types ) || ( is_array( $object_types ) && empty( $object_types ) ) ) {
$post_types = get_post_types( array( 'public' => true ) );
} else {
$post_types = $object_types;
}
if ( !$post_types || empty( $post_types ) ) {
return new \WP_Error( 'czr_contents_invalid_post_type' );
}
$query = array(
'suppress_filters' => true,
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
'post_status' => 'publish',
'posts_per_page' => 10,
);
$args['pagenum'] = isset( $args['pagenum'] ) ? absint( $args['pagenum'] ) : 1;
$query['offset'] = $args['pagenum'] > 1 ? $query['posts_per_page'] * ( $args['pagenum'] - 1 ) : 0;
$query['post_type'] = $post_types;
if ( isset( $args['s'] ) ) {
$query['s'] = $args['s'];
}
// Query posts.
$get_posts = new \WP_Query( $query );
// Check if any posts were found.
if ( $get_posts->post_count ) {
foreach ( $get_posts->posts as $post ) {
$post_title = $post->post_title;
if ( '' === $post_title ) {
/* translators: %d: ID of a post */
$post_title = sprintf( __( '#%d (no title)', 'text_doma' ), $post->ID );
}
$items[] = array(
'title' => html_entity_decode( $post_title, ENT_QUOTES, get_bloginfo( 'charset' ) ),
'type' => 'post',
'type_label' => get_post_type_object( $post->post_type )->labels->singular_name,
'object' => $post->post_type,
'id' => intval( $post->ID ),
'url' => get_permalink( intval( $post->ID ) ),
);
}
}
} elseif ( 'taxonomy' === $args['type'] ) {
//What are the taxonomy types we need to fetch ?
if ( '_all_' == $object_types || !is_array( $object_types ) || ( is_array( $object_types ) && empty( $object_types ) ) ) {
$taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'names' );
} else {
$taxonomies = $object_types;
}
if ( !$taxonomies || !is_array( $taxonomies ) || empty( $taxonomies ) ) {
return new \WP_Error( 'czr_contents_invalid_post_type' );
}
$terms = get_terms( $taxonomies, array(
'name__like' => $args['s'],
'number' => 10,
'offset' => 10 * ( $args['pagenum'] - 1 )
) );
// Check if any taxonomies were found.
if ( !empty( $terms ) ) {
foreach ( $terms as $term ) {
$items[] = array(
'title' => html_entity_decode( $term->name, ENT_QUOTES, get_bloginfo( 'charset' ) ),
'type' => 'taxonomy',
'type_label' => get_taxonomy( $term->taxonomy )->labels->singular_name,
'object' => $term->taxonomy,
'id' => intval( $term->term_id ),
'url' => get_term_link( intval( $term->term_id ), $term->taxonomy ),
);
}
}
/**
* Filters the available menu items during a search request.
*
* @since 4.5.0
*
* @param array $items The array of menu items.
* @param array $args Includes 'pagenum' and 's' (search) arguments.
*/
$items = apply_filters( 'czr_customize_content_picker_searched_items', $items, $args );
}
return $items;
}
}
endif;
?>
@@ -0,0 +1,48 @@
<?php
/**
* @uses wp_get_theme() the optional stylesheet parameter value takes into account the possible preview of a theme different than the one activated
*/
function czr_get_parent_theme_slug() {
$theme_slug = get_option( 'stylesheet' );
// $_REQUEST['theme'] is set both in live preview and when we're customizing a non active theme
$theme_slug = sanitize_text_field( isset($_REQUEST['theme']) ? $_REQUEST['theme'] : $theme_slug ); //old wp versions
$theme_slug = sanitize_text_field( isset($_REQUEST['customize_theme']) ? $_REQUEST['customize_theme'] : $theme_slug );
//gets the theme name (or parent if child)
$theme_data = wp_get_theme( $theme_slug );
if ( $theme_data -> parent() ) {
$theme_slug = $theme_data -> parent() -> Name;
}
return sanitize_file_name( strtolower( $theme_slug ) );
}
//@return boolean
function czr_is_multi_item_module( $module_type ) {
$is_multi_item = false;
$module_params = CZR_Fmk_Base() -> czr_get_registered_dynamic_module( $module_type );
if ( is_array( $module_params ) ) {
if ( array_key_exists( 'is_crud', $module_params ) ) {
$is_multi_item = (bool)$module_params['is_crud'];
}
if ( array_key_exists( 'is_multi_item', $module_params ) ) {
$is_multi_item = (bool)$module_params['is_multi_item'];
}
}
return $is_multi_item;
}
//Creates a new instance
//@params ex :
//array(
// 'base_url' => NIMBLE_BASE_URL . '/inc/czr-base-fmk'
// )
function CZR_Fmk_Base( $params = array() ) {
return CZR_Fmk_Base::czr_fmk_get_instance( $params );
}
?>
@@ -0,0 +1,22 @@
.czr-sub-set[data-input-type="content_picker"] .customize-control-title {
width: 100%;
}
.czr-sub-set[data-input-type="content_picker"] .czr-input {
width: 100%;
}
.content-item-bar {
line-height: 1.5em;
}
.czr-sub-set[data-input-type="content_picker"] span.item-title {
display: block;
float: left;
max-width: 80%;
}
.czr-sub-set[data-input-type="content_picker"] span.item-type {
display: inline-block;
padding: 0;
padding-right: 10px;
float: right;
}
@@ -0,0 +1 @@
.czr-sub-set[data-input-type=content_picker] .customize-control-title{width:100%}.czr-sub-set[data-input-type=content_picker] .czr-input{width:100%}.content-item-bar{line-height:1.5em}.czr-sub-set[data-input-type=content_picker] span.item-title{display:block;float:left;max-width:80%}.czr-sub-set[data-input-type=content_picker] span.item-type{display:inline-block;padding:0;padding-right:10px;float:right}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,37 @@
/* Rate link */
#customize-footer-actions .collapse-sidebar-label {
display: none;
}
.czr-rate-link {
position: absolute;
bottom: 0;
left: 40px;
right: 0;
padding: 4px 12px 4px 0;
font-size: 10px;
line-height: 14px;
text-align: right;
}
.rtl .tc-rate-link {
text-align: left;
left: auto;
right: 40px;
padding: 4px 0 4px 12px;
}
.wp-full-overlay.collapsed .czr-rate-link {
display: none;
}
.czr-rate-link .czr-stars {
color: #E6B800;
text-shadow: 0px 1px 0px rgba(0, 0, 0, 0.6);
}
@media screen and (min-width: 1025px) {
.wp-customizer .expanded #customize-footer-actions {
height: 85px;
background: inherit;
}
.wp-customizer #customize-controls .wp-full-overlay-sidebar-content {
bottom: 85px;
}
}
@@ -0,0 +1 @@
#customize-footer-actions .collapse-sidebar-label{display:none}.czr-rate-link{position:absolute;bottom:0;left:40px;right:0;padding:4px 12px 4px 0;font-size:10px;line-height:14px;text-align:right}.rtl .tc-rate-link{text-align:left;left:auto;right:40px;padding:4px 0 4px 12px}.wp-full-overlay.collapsed .czr-rate-link{display:none}.czr-rate-link .czr-stars{color:#e6b800;text-shadow:0 1px 0 rgba(0,0,0,.6)}@media screen and (min-width:1025px){.wp-customizer .expanded #customize-footer-actions{height:85px;background:inherit}.wp-customizer #customize-controls .wp-full-overlay-sidebar-content{bottom:85px}}
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

@@ -0,0 +1,482 @@
.czrSelect2-container {
box-sizing: border-box;
display: inline-block;
margin: 0;
position: relative;
vertical-align: middle; }
.czrSelect2-container .czrSelect2-selection--single {
box-sizing: border-box;
cursor: pointer;
display: block;
height: 28px;
user-select: none;
-webkit-user-select: none; }
.czrSelect2-container .czrSelect2-selection--single .czrSelect2-selection__rendered {
display: block;
padding-left: 8px;
padding-right: 20px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; }
.czrSelect2-container .czrSelect2-selection--single .czrSelect2-selection__clear {
position: relative; }
.czrSelect2-container[dir="rtl"] .czrSelect2-selection--single .czrSelect2-selection__rendered {
padding-right: 8px;
padding-left: 20px; }
.czrSelect2-container .czrSelect2-selection--multiple {
box-sizing: border-box;
cursor: pointer;
display: block;
min-height: 32px;
user-select: none;
-webkit-user-select: none; }
.czrSelect2-container .czrSelect2-selection--multiple .czrSelect2-selection__rendered {
display: inline-block;
overflow: hidden;
padding-left: 8px;
text-overflow: ellipsis;
white-space: nowrap; }
.czrSelect2-container .czrSelect2-search--inline {
float: left; }
.czrSelect2-container .czrSelect2-search--inline .czrSelect2-search__field {
box-sizing: border-box;
border: none;
font-size: 100%;
margin-top: 5px;
padding: 0; }
.czrSelect2-container .czrSelect2-search--inline .czrSelect2-search__field::-webkit-search-cancel-button {
-webkit-appearance: none; }
.czrSelect2-dropdown {
background-color: white;
border: 1px solid #aaa;
border-radius: 4px;
box-sizing: border-box;
display: block;
position: absolute;
left: -100000px;
width: 100%;
z-index: 1051; }
.czrSelect2-results {
display: block; }
.czrSelect2-results__options {
list-style: none;
margin: 0;
padding: 0; }
.czrSelect2-results__option {
padding: 6px;
user-select: none;
-webkit-user-select: none; }
.czrSelect2-results__option[aria-selected] {
cursor: pointer; }
.czrSelect2-container--open .czrSelect2-dropdown {
left: 0; }
.czrSelect2-container--open .czrSelect2-dropdown--above {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0; }
.czrSelect2-container--open .czrSelect2-dropdown--below {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0; }
.czrSelect2-search--dropdown {
display: block;
padding: 4px; }
.czrSelect2-search--dropdown .czrSelect2-search__field {
padding: 4px;
width: 100%;
box-sizing: border-box; }
.czrSelect2-search--dropdown .czrSelect2-search__field::-webkit-search-cancel-button {
-webkit-appearance: none; }
.czrSelect2-search--dropdown.czrSelect2-search--hide {
display: none; }
.czrSelect2-close-mask {
border: 0;
margin: 0;
padding: 0;
display: block;
position: fixed;
left: 0;
top: 0;
min-height: 100%;
min-width: 100%;
height: auto;
width: auto;
opacity: 0;
z-index: 99;
background-color: #fff;
filter: alpha(opacity=0); }
.czrSelect2-hidden-accessible {
border: 0 !important;
clip: rect(0 0 0 0) !important;
height: 1px !important;
margin: -1px !important;
overflow: hidden !important;
padding: 0 !important;
position: absolute !important;
width: 1px !important; }
.czrSelect2-container--default .czrSelect2-selection--single {
background-color: #fff;
border: 1px solid #aaa;
border-radius: 4px; }
.czrSelect2-container--default .czrSelect2-selection--single .czrSelect2-selection__rendered {
color: #444;
line-height: 28px; }
.czrSelect2-container--default .czrSelect2-selection--single .czrSelect2-selection__clear {
cursor: pointer;
float: right;
font-weight: bold; }
.czrSelect2-container--default .czrSelect2-selection--single .czrSelect2-selection__placeholder {
color: #999; }
.czrSelect2-container--default .czrSelect2-selection--single .czrSelect2-selection__arrow {
height: 26px;
position: absolute;
top: 1px;
right: 1px;
width: 20px; }
.czrSelect2-container--default .czrSelect2-selection--single .czrSelect2-selection__arrow b {
border-color: #888 transparent transparent transparent;
border-style: solid;
border-width: 5px 4px 0 4px;
height: 0;
left: 50%;
margin-left: -4px;
margin-top: -2px;
position: absolute;
top: 50%;
width: 0; }
.czrSelect2-container--default[dir="rtl"] .czrSelect2-selection--single .czrSelect2-selection__clear {
float: left; }
.czrSelect2-container--default[dir="rtl"] .czrSelect2-selection--single .czrSelect2-selection__arrow {
left: 1px;
right: auto; }
.czrSelect2-container--default.czrSelect2-container--disabled .czrSelect2-selection--single {
background-color: #eee;
cursor: default; }
.czrSelect2-container--default.czrSelect2-container--disabled .czrSelect2-selection--single .czrSelect2-selection__clear {
display: none; }
.czrSelect2-container--default.czrSelect2-container--open .czrSelect2-selection--single .czrSelect2-selection__arrow b {
border-color: transparent transparent #888 transparent;
border-width: 0 4px 5px 4px; }
.czrSelect2-container--default .czrSelect2-selection--multiple {
background-color: white;
border: 1px solid #aaa;
border-radius: 4px;
cursor: text; }
.czrSelect2-container--default .czrSelect2-selection--multiple .czrSelect2-selection__rendered {
box-sizing: border-box;
list-style: none;
margin: 0;
padding: 0 5px;
width: 100%; }
.czrSelect2-container--default .czrSelect2-selection--multiple .czrSelect2-selection__placeholder {
color: #999;
margin-top: 5px;
float: left; }
.czrSelect2-container--default .czrSelect2-selection--multiple .czrSelect2-selection__clear {
cursor: pointer;
float: right;
font-weight: bold;
margin-top: 5px;
margin-right: 10px; }
.czrSelect2-container--default .czrSelect2-selection--multiple .czrSelect2-selection__choice {
background-color: #e4e4e4;
border: 1px solid #aaa;
border-radius: 4px;
cursor: default;
float: left;
margin-right: 5px;
margin-top: 5px;
padding: 0 5px; }
.czrSelect2-container--default .czrSelect2-selection--multiple .czrSelect2-selection__choice__remove {
color: #999;
cursor: pointer;
display: inline-block;
font-weight: bold;
margin-right: 2px; }
.czrSelect2-container--default .czrSelect2-selection--multiple .czrSelect2-selection__choice__remove:hover {
color: #333; }
.czrSelect2-container--default[dir="rtl"] .czrSelect2-selection--multiple .czrSelect2-selection__choice, .czrSelect2-container--default[dir="rtl"] .czrSelect2-selection--multiple .czrSelect2-selection__placeholder, .czrSelect2-container--default[dir="rtl"] .czrSelect2-selection--multiple .czrSelect2-search--inline {
float: right; }
.czrSelect2-container--default[dir="rtl"] .czrSelect2-selection--multiple .czrSelect2-selection__choice {
margin-left: 5px;
margin-right: auto; }
.czrSelect2-container--default[dir="rtl"] .czrSelect2-selection--multiple .czrSelect2-selection__choice__remove {
margin-left: 2px;
margin-right: auto; }
.czrSelect2-container--default.czrSelect2-container--focus .czrSelect2-selection--multiple {
border: solid black 1px;
outline: 0; }
.czrSelect2-container--default.czrSelect2-container--disabled .czrSelect2-selection--multiple {
background-color: #eee;
cursor: default; }
.czrSelect2-container--default.czrSelect2-container--disabled .czrSelect2-selection__choice__remove {
display: none; }
.czrSelect2-container--default.czrSelect2-container--open.czrSelect2-container--above .czrSelect2-selection--single, .czrSelect2-container--default.czrSelect2-container--open.czrSelect2-container--above .czrSelect2-selection--multiple {
border-top-left-radius: 0;
border-top-right-radius: 0; }
.czrSelect2-container--default.czrSelect2-container--open.czrSelect2-container--below .czrSelect2-selection--single, .czrSelect2-container--default.czrSelect2-container--open.czrSelect2-container--below .czrSelect2-selection--multiple {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0; }
.czrSelect2-container--default .czrSelect2-search--dropdown .czrSelect2-search__field {
border: 1px solid #aaa; }
.czrSelect2-container--default .czrSelect2-search--inline .czrSelect2-search__field {
background: transparent;
border: none;
outline: 0;
box-shadow: none;
-webkit-appearance: textfield; }
.czrSelect2-container--default .czrSelect2-results > .czrSelect2-results__options {
max-height: 200px;
overflow-y: auto; }
.czrSelect2-container--default .czrSelect2-results__option[role=group] {
padding: 0; }
.czrSelect2-container--default .czrSelect2-results__option[aria-disabled=true] {
color: #999; }
.czrSelect2-container--default .czrSelect2-results__option[aria-selected=true] {
background-color: #ddd; }
.czrSelect2-container--default .czrSelect2-results__option .czrSelect2-results__option {
padding-left: 1em; }
.czrSelect2-container--default .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__group {
padding-left: 0; }
.czrSelect2-container--default .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option {
margin-left: -1em;
padding-left: 2em; }
.czrSelect2-container--default .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option {
margin-left: -2em;
padding-left: 3em; }
.czrSelect2-container--default .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option {
margin-left: -3em;
padding-left: 4em; }
.czrSelect2-container--default .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option {
margin-left: -4em;
padding-left: 5em; }
.czrSelect2-container--default .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option .czrSelect2-results__option {
margin-left: -5em;
padding-left: 6em; }
.czrSelect2-container--default .czrSelect2-results__option--highlighted[aria-selected] {
background-color: #5897fb;
color: white; }
.czrSelect2-container--default .czrSelect2-results__group {
cursor: default;
display: block;
padding: 6px; }
.czrSelect2-container--classic .czrSelect2-selection--single {
background-color: #f7f7f7;
border: 1px solid #aaa;
border-radius: 4px;
outline: 0;
background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
.czrSelect2-container--classic .czrSelect2-selection--single:focus {
border: 1px solid #5897fb; }
.czrSelect2-container--classic .czrSelect2-selection--single .czrSelect2-selection__rendered {
color: #444;
line-height: 28px; }
.czrSelect2-container--classic .czrSelect2-selection--single .czrSelect2-selection__clear {
cursor: pointer;
float: right;
font-weight: bold;
margin-right: 10px; }
.czrSelect2-container--classic .czrSelect2-selection--single .czrSelect2-selection__placeholder {
color: #999; }
.czrSelect2-container--classic .czrSelect2-selection--single .czrSelect2-selection__arrow {
background-color: #ddd;
border: none;
border-left: 1px solid #aaa;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
height: 26px;
position: absolute;
top: 1px;
right: 1px;
width: 20px;
background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }
.czrSelect2-container--classic .czrSelect2-selection--single .czrSelect2-selection__arrow b {
border-color: #888 transparent transparent transparent;
border-style: solid;
border-width: 5px 4px 0 4px;
height: 0;
left: 50%;
margin-left: -4px;
margin-top: -2px;
position: absolute;
top: 50%;
width: 0; }
.czrSelect2-container--classic[dir="rtl"] .czrSelect2-selection--single .czrSelect2-selection__clear {
float: left; }
.czrSelect2-container--classic[dir="rtl"] .czrSelect2-selection--single .czrSelect2-selection__arrow {
border: none;
border-right: 1px solid #aaa;
border-radius: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
left: 1px;
right: auto; }
.czrSelect2-container--classic.czrSelect2-container--open .czrSelect2-selection--single {
border: 1px solid #5897fb; }
.czrSelect2-container--classic.czrSelect2-container--open .czrSelect2-selection--single .czrSelect2-selection__arrow {
background: transparent;
border: none; }
.czrSelect2-container--classic.czrSelect2-container--open .czrSelect2-selection--single .czrSelect2-selection__arrow b {
border-color: transparent transparent #888 transparent;
border-width: 0 4px 5px 4px; }
.czrSelect2-container--classic.czrSelect2-container--open.czrSelect2-container--above .czrSelect2-selection--single {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0;
background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
.czrSelect2-container--classic.czrSelect2-container--open.czrSelect2-container--below .czrSelect2-selection--single {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }
.czrSelect2-container--classic .czrSelect2-selection--multiple {
background-color: white;
border: 1px solid #aaa;
border-radius: 4px;
cursor: text;
outline: 0; }
.czrSelect2-container--classic .czrSelect2-selection--multiple:focus {
border: 1px solid #5897fb; }
.czrSelect2-container--classic .czrSelect2-selection--multiple .czrSelect2-selection__rendered {
list-style: none;
margin: 0;
padding: 0 5px; }
.czrSelect2-container--classic .czrSelect2-selection--multiple .czrSelect2-selection__clear {
display: none; }
.czrSelect2-container--classic .czrSelect2-selection--multiple .czrSelect2-selection__choice {
background-color: #e4e4e4;
border: 1px solid #aaa;
border-radius: 4px;
cursor: default;
float: left;
margin-right: 5px;
margin-top: 5px;
padding: 0 5px; }
.czrSelect2-container--classic .czrSelect2-selection--multiple .czrSelect2-selection__choice__remove {
color: #888;
cursor: pointer;
display: inline-block;
font-weight: bold;
margin-right: 2px; }
.czrSelect2-container--classic .czrSelect2-selection--multiple .czrSelect2-selection__choice__remove:hover {
color: #555; }
.czrSelect2-container--classic[dir="rtl"] .czrSelect2-selection--multiple .czrSelect2-selection__choice {
float: right; }
.czrSelect2-container--classic[dir="rtl"] .czrSelect2-selection--multiple .czrSelect2-selection__choice {
margin-left: 5px;
margin-right: auto; }
.czrSelect2-container--classic[dir="rtl"] .czrSelect2-selection--multiple .czrSelect2-selection__choice__remove {
margin-left: 2px;
margin-right: auto; }
.czrSelect2-container--classic.czrSelect2-container--open .czrSelect2-selection--multiple {
border: 1px solid #5897fb; }
.czrSelect2-container--classic.czrSelect2-container--open.czrSelect2-container--above .czrSelect2-selection--multiple {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0; }
.czrSelect2-container--classic.czrSelect2-container--open.czrSelect2-container--below .czrSelect2-selection--multiple {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0; }
.czrSelect2-container--classic .czrSelect2-search--dropdown .czrSelect2-search__field {
border: 1px solid #aaa;
outline: 0; }
.czrSelect2-container--classic .czrSelect2-search--inline .czrSelect2-search__field {
outline: 0;
box-shadow: none; }
.czrSelect2-container--classic .czrSelect2-dropdown {
background-color: white;
border: 1px solid transparent; }
.czrSelect2-container--classic .czrSelect2-dropdown--above {
border-bottom: none; }
.czrSelect2-container--classic .czrSelect2-dropdown--below {
border-top: none; }
.czrSelect2-container--classic .czrSelect2-results > .czrSelect2-results__options {
max-height: 200px;
overflow-y: auto; }
.czrSelect2-container--classic .czrSelect2-results__option[role=group] {
padding: 0; }
.czrSelect2-container--classic .czrSelect2-results__option[aria-disabled=true] {
color: grey; }
.czrSelect2-container--classic .czrSelect2-results__option--highlighted[aria-selected] {
background-color: #3875d7;
color: white; }
.czrSelect2-container--classic .czrSelect2-results__group {
cursor: default;
display: block;
padding: 6px; }
.czrSelect2-container--classic.czrSelect2-container--open .czrSelect2-dropdown {
border-color: #5897fb; }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 730 KiB

@@ -0,0 +1,801 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<metadata>
Created by FontForge 20200314 at Wed Jan 13 11:57:54 2021
By Robert Madole
Copyright (c) Font Awesome
</metadata>
<!-- Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><defs>
<font id="FontAwesome5Free-Regular" horiz-adv-x="512" >
<font-face
font-family="Font Awesome 5 Free Regular"
font-weight="400"
font-stretch="normal"
units-per-em="512"
panose-1="2 0 5 3 0 0 0 0 0 0"
ascent="448"
descent="-64"
bbox="-0.0663408 -64.0662 640.004 448.1"
underline-thickness="25"
underline-position="-50"
unicode-range="U+0020-F5C8"
/>
<missing-glyph />
<glyph glyph-name="heart" unicode="&#xf004;"
d="M458.4 383.7c75.2998 -63.4004 64.0996 -166.601 10.5996 -221.3l-175.4 -178.7c-10 -10.2002 -23.2998 -15.7998 -37.5996 -15.7998c-14.2002 0 -27.5996 5.69922 -37.5996 15.8994l-175.4 178.7c-53.5996 54.7002 -64.5996 157.9 10.5996 221.2
c57.8008 48.7002 147.101 41.2998 202.4 -15c55.2998 56.2998 144.6 63.5996 202.4 15zM434.8 196.2c36.2002 36.8994 43.7998 107.7 -7.2998 150.8c-38.7002 32.5996 -98.7002 27.9004 -136.5 -10.5996l-35 -35.7002l-35 35.7002
c-37.5996 38.2998 -97.5996 43.1992 -136.5 10.5c-51.2002 -43.1006 -43.7998 -113.5 -7.2998 -150.7l175.399 -178.7c2.40039 -2.40039 4.40039 -2.40039 6.80078 0z" />
<glyph glyph-name="star" unicode="&#xf005;" horiz-adv-x="576"
d="M528.1 276.5c26.2002 -3.7998 36.7002 -36.0996 17.7002 -54.5996l-105.7 -103l25 -145.5c4.5 -26.3008 -23.1992 -45.9004 -46.3994 -33.7002l-130.7 68.7002l-130.7 -68.7002c-23.2002 -12.2998 -50.8994 7.39941 -46.3994 33.7002l25 145.5l-105.7 103
c-19 18.5 -8.5 50.7998 17.7002 54.5996l146.1 21.2998l65.2998 132.4c11.7998 23.8994 45.7002 23.5996 57.4004 0l65.2998 -132.4zM388.6 135.7l100.601 98l-139 20.2002l-62.2002 126l-62.2002 -126l-139 -20.2002l100.601 -98l-23.7002 -138.4l124.3 65.2998
l124.3 -65.2998z" />
<glyph glyph-name="user" unicode="&#xf007;" horiz-adv-x="448"
d="M313.6 144c74.2002 0 134.4 -60.2002 134.4 -134.4v-25.5996c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v25.5996c0 74.2002 60.2002 134.4 134.4 134.4c28.7998 0 42.5 -16 89.5996 -16s60.9004 16 89.5996 16zM400 -16v25.5996
c0 47.6006 -38.7998 86.4004 -86.4004 86.4004c-14.6992 0 -37.8994 -16 -89.5996 -16c-51.2998 0 -75 16 -89.5996 16c-47.6006 0 -86.4004 -38.7998 -86.4004 -86.4004v-25.5996h352zM224 160c-79.5 0 -144 64.5 -144 144s64.5 144 144 144s144 -64.5 144 -144
s-64.5 -144 -144 -144zM224 400c-52.9004 0 -96 -43.0996 -96 -96s43.0996 -96 96 -96s96 43.0996 96 96s-43.0996 96 -96 96z" />
<glyph glyph-name="clock" unicode="&#xf017;"
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM317.8 96.4004l-84.8994 61.6992
c-3.10059 2.30078 -4.90039 5.90039 -4.90039 9.7002v164.2c0 6.59961 5.40039 12 12 12h32c6.59961 0 12 -5.40039 12 -12v-141.7l66.7998 -48.5996c5.40039 -3.90039 6.5 -11.4004 2.60059 -16.7998l-18.8008 -25.9004c-3.89941 -5.2998 -11.3994 -6.5 -16.7998 -2.59961z
" />
<glyph glyph-name="list-alt" unicode="&#xf022;"
d="M464 416c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h416zM458 16c3.31152 0 6 2.68848 6 6v340c0 3.31152 -2.68848 6 -6 6h-404c-3.31152 0 -6 -2.68848 -6 -6v-340
c0 -3.31152 2.68848 -6 6 -6h404zM416 108v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM416 204v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12
v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM416 300v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM164 288c0 -19.8818 -16.1182 -36 -36 -36
s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36zM164 192c0 -19.8818 -16.1182 -36 -36 -36s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36zM164 96c0 -19.8818 -16.1182 -36 -36 -36s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36z" />
<glyph glyph-name="flag" unicode="&#xf024;"
d="M336.174 368c35.4668 0 73.0195 12.6914 108.922 28.1797c31.6406 13.6514 66.9043 -9.65723 66.9043 -44.1162v-239.919c0 -16.1953 -8.1543 -31.3057 -21.7129 -40.1631c-26.5762 -17.3643 -70.0693 -39.9814 -128.548 -39.9814c-68.6084 0 -112.781 32 -161.913 32
c-56.5674 0 -89.957 -11.2803 -127.826 -28.5566v-83.4434c0 -8.83691 -7.16309 -16 -16 -16h-16c-8.83691 0 -16 7.16309 -16 16v406.438c-14.3428 8.2998 -24 23.7979 -24 41.5615c0 27.5693 23.2422 49.71 51.2012 47.8965
c22.9658 -1.49023 41.8662 -19.4717 44.4805 -42.3379c0.213867 -1.83398 0.308594 -3.65918 0.308594 -5.5498c0 -5.30273 -0.860352 -10.4053 -2.4502 -15.1768c22.418 8.68555 49.4199 15.168 80.7207 15.168c68.6084 0 112.781 -32 161.913 -32zM464 112v240
c-31.5059 -14.6338 -84.5547 -32 -127.826 -32c-59.9111 0 -101.968 32 -161.913 32c-41.4365 0 -80.4766 -16.5879 -102.261 -32v-232c31.4473 14.5967 84.4648 24 127.826 24c59.9111 0 101.968 -32 161.913 -32c41.4365 0 80.4775 16.5879 102.261 32z" />
<glyph glyph-name="bookmark" unicode="&#xf02e;" horiz-adv-x="384"
d="M336 448c26.5098 0 48 -21.4902 48 -48v-464l-192 112l-192 -112v464c0 26.5098 21.4902 48 48 48h288zM336 19.5703v374.434c0 3.31348 -2.68555 5.99609 -6 5.99609h-276c-3.31152 0 -6 -2.68848 -6 -6v-374.43l144 84z" />
<glyph glyph-name="image" unicode="&#xf03e;"
d="M464 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h416zM458 48c3.31152 0 6 2.68848 6 6v276c0 3.31152 -2.68848 6 -6 6h-404c-3.31152 0 -6 -2.68848 -6 -6v-276
c0 -3.31152 2.68848 -6 6 -6h404zM128 296c22.0908 0 40 -17.9092 40 -40s-17.9092 -40 -40 -40s-40 17.9092 -40 40s17.9092 40 40 40zM96 96v48l39.5137 39.5146c4.6875 4.68652 12.2852 4.68652 16.9717 0l39.5146 -39.5146l119.514 119.515
c4.6875 4.68652 12.2852 4.68652 16.9717 0l87.5146 -87.5146v-80h-320z" />
<glyph glyph-name="edit" unicode="&#xf044;" horiz-adv-x="576"
d="M402.3 103.1l32 32c5 5 13.7002 1.5 13.7002 -5.69922v-145.4c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h273.5c7.09961 0 10.7002 -8.59961 5.7002 -13.7002l-32 -32c-1.5 -1.5 -3.5 -2.2998 -5.7002 -2.2998h-241.5v-352h352
v113.5c0 2.09961 0.799805 4.09961 2.2998 5.59961zM558.9 304.9l-262.601 -262.601l-90.3994 -10c-26.2002 -2.89941 -48.5 19.2002 -45.6006 45.6006l10 90.3994l262.601 262.601c22.8994 22.8994 59.8994 22.8994 82.6992 0l43.2002 -43.2002
c22.9004 -22.9004 22.9004 -60 0.100586 -82.7998zM460.1 274l-58.0996 58.0996l-185.8 -185.899l-7.2998 -65.2998l65.2998 7.2998zM524.9 353.7l-43.2002 43.2002c-4.10059 4.09961 -10.7998 4.09961 -14.7998 0l-30.9004 -30.9004l58.0996 -58.0996l30.9004 30.8994
c4 4.2002 4 10.7998 -0.0996094 14.9004z" />
<glyph glyph-name="times-circle" unicode="&#xf057;"
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM357.8 254.2l-62.2002 -62.2002l62.2002 -62.2002
c4.7002 -4.7002 4.7002 -12.2998 0 -17l-22.5996 -22.5996c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-62.2002 62.2002l-62.2002 -62.2002c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-22.5996 22.5996c-4.7002 4.7002 -4.7002 12.2998 0 17l62.2002 62.2002l-62.2002 62.2002
c-4.7002 4.7002 -4.7002 12.2998 0 17l22.5996 22.5996c4.7002 4.7002 12.2998 4.7002 17 0l62.2002 -62.2002l62.2002 62.2002c4.7002 4.7002 12.2998 4.7002 17 0l22.5996 -22.5996c4.7002 -4.7002 4.7002 -12.2998 0 -17z" />
<glyph glyph-name="check-circle" unicode="&#xf058;"
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 392c-110.549 0 -200 -89.4678 -200 -200c0 -110.549 89.4678 -200 200 -200c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200z
M396.204 261.733c4.66699 -4.70508 4.63672 -12.3037 -0.0673828 -16.9717l-172.589 -171.204c-4.70508 -4.66797 -12.3027 -4.63672 -16.9697 0.0683594l-90.7812 91.5156c-4.66797 4.70605 -4.63672 12.3047 0.0683594 16.9717l22.7188 22.5361
c4.70508 4.66699 12.3027 4.63574 16.9697 -0.0693359l59.792 -60.2773l141.353 140.216c4.70508 4.66797 12.3027 4.6377 16.9697 -0.0673828z" />
<glyph glyph-name="question-circle" unicode="&#xf059;"
d="M256 440c136.957 0 248 -111.083 248 -248c0 -136.997 -111.043 -248 -248 -248s-248 111.003 -248 248c0 136.917 111.043 248 248 248zM256 -8c110.569 0 200 89.4697 200 200c0 110.529 -89.5088 200 -200 200c-110.528 0 -200 -89.5049 -200 -200
c0 -110.569 89.4678 -200 200 -200zM363.244 247.2c0 -67.0518 -72.4209 -68.084 -72.4209 -92.8633v-6.33691c0 -6.62695 -5.37305 -12 -12 -12h-45.6475c-6.62695 0 -12 5.37305 -12 12v8.65918c0 35.7451 27.1006 50.0342 47.5791 61.5156
c17.5615 9.84473 28.3242 16.541 28.3242 29.5791c0 17.2461 -21.999 28.6934 -39.7842 28.6934c-23.1885 0 -33.8936 -10.9775 -48.9424 -29.9697c-4.05664 -5.11914 -11.46 -6.07031 -16.666 -2.12402l-27.8232 21.0986
c-5.10742 3.87207 -6.25098 11.0654 -2.64453 16.3633c23.627 34.6934 53.7217 54.1846 100.575 54.1846c49.0713 0 101.45 -38.3037 101.45 -88.7998zM298 80c0 -23.1592 -18.8408 -42 -42 -42s-42 18.8408 -42 42s18.8408 42 42 42s42 -18.8408 42 -42z" />
<glyph glyph-name="eye" unicode="&#xf06e;" horiz-adv-x="576"
d="M288 304c0.114258 0 0.240234 -0.0175781 0.354492 -0.0175781c61.6543 0 111.71 -50.0557 111.71 -111.71s-50.0557 -111.71 -111.71 -111.71s-111.71 50.0557 -111.71 111.71c0 10.7422 1.51953 21.1328 4.35547 30.9678
c7.95898 -4.52637 17.2129 -7.17188 27 -7.24023c30.9072 0 56 25.0928 56 56c-0.0683594 9.78711 -2.71387 19.041 -7.24023 27c9.88379 3.07617 20.3896 4.83008 31.2402 5zM572.52 206.6c2.21387 -4.37793 3.46094 -9.38965 3.46094 -14.626
c0 -5.2373 -1.24707 -10.1855 -3.46094 -14.5635c-54.1992 -105.771 -161.59 -177.41 -284.52 -177.41s-230.29 71.5898 -284.52 177.4c-2.21387 4.37793 -3.46094 9.38965 -3.46094 14.626c0 5.2373 1.24707 10.1855 3.46094 14.5635
c54.1992 105.771 161.59 177.41 284.52 177.41s230.29 -71.5898 284.52 -177.4zM288 48c98.6602 0 189.1 55 237.93 144c-48.8398 89 -139.27 144 -237.93 144s-189.09 -55 -237.93 -144c48.8398 -89 139.279 -144 237.93 -144z" />
<glyph glyph-name="eye-slash" unicode="&#xf070;" horiz-adv-x="640"
d="M634 -23c3.66895 -2.93262 6.00391 -7.45117 6.00391 -12.5088c0 -3.7832 -1.31543 -7.26074 -3.51367 -10.001l-10 -12.4902c-2.93359 -3.66309 -7.44824 -5.99414 -12.502 -5.99414c-3.77637 0 -7.25 1.31152 -9.98828 3.50391l-598 467.49
c-3.66895 2.93262 -6.00391 7.45117 -6.00391 12.5088c0 3.7832 1.31543 7.26074 3.51367 10.001l10 12.4902c2.93359 3.66309 7.44824 5.99414 12.502 5.99414c3.77637 0 7.25 -1.31152 9.98828 -3.50391zM296.79 301.53c7.51172 1.60254 15.2266 2.45508 23.21 2.46973
c60.4805 0 109.36 -47.9102 111.58 -107.85zM343.21 82.46c-7.51367 -1.59375 -15.2285 -2.44336 -23.21 -2.45996c-60.4697 0 -109.35 47.9102 -111.58 107.84zM320 336c-19.8799 0 -39.2803 -2.7998 -58.2197 -7.09961l-46.4102 36.29
c32.9199 11.8096 67.9297 18.8096 104.63 18.8096c122.93 0 230.29 -71.5898 284.57 -177.4c2.21289 -4.37793 3.45996 -9.38965 3.45996 -14.626c0 -5.2373 -1.24707 -10.1855 -3.45996 -14.5635c-14.1924 -27.5625 -31.9229 -52.6689 -52.9004 -75.1104l-37.7402 29.5
c17.2305 18.0527 31.9385 38.1318 44 60.2002c-48.8398 89 -139.279 144 -237.93 144zM320 48c19.8896 0 39.2803 2.7998 58.2197 7.08984l46.4102 -36.2803c-32.9199 -11.7598 -67.9297 -18.8096 -104.63 -18.8096c-122.92 0 -230.28 71.5898 -284.51 177.4
c-2.21387 4.37793 -3.46094 9.38965 -3.46094 14.626c0 5.2373 1.24707 10.1855 3.46094 14.5635c14.1885 27.5586 31.916 52.6621 52.8896 75.1006l37.7402 -29.5c-17.249 -18.0469 -31.9727 -38.1221 -44.0498 -60.1904c48.8496 -89 139.279 -144 237.93 -144z" />
<glyph glyph-name="calendar-alt" unicode="&#xf073;" horiz-adv-x="448"
d="M148 160h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12zM256 172c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40
c6.59961 0 12 -5.40039 12 -12v-40zM352 172c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM256 76c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM160 76c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM352 76c0 -6.59961 -5.40039 -12 -12 -12h-40
c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40
c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="comment" unicode="&#xf075;"
d="M256 416c141.4 0 256 -93.0996 256 -208s-114.6 -208 -256 -208c-32.7998 0 -64 5.2002 -92.9004 14.2998c-29.0996 -20.5996 -77.5996 -46.2998 -139.1 -46.2998c-9.59961 0 -18.2998 5.7002 -22.0996 14.5c-3.80078 8.7998 -2 19 4.59961 26
c0.5 0.400391 31.5 33.7998 46.4004 73.2002c-33 35.0996 -52.9004 78.7002 -52.9004 126.3c0 114.9 114.6 208 256 208zM256 48c114.7 0 208 71.7998 208 160s-93.2998 160 -208 160s-208 -71.7998 -208 -160c0 -42.2002 21.7002 -74.0996 39.7998 -93.4004
l20.6006 -21.7998l-10.6006 -28.0996c-5.5 -14.5 -12.5996 -28.1006 -19.8994 -40.2002c23.5996 7.59961 43.1992 18.9004 57.5 29l19.5 13.7998l22.6992 -7.2002c25.3008 -8 51.7002 -12.0996 78.4004 -12.0996z" />
<glyph glyph-name="folder" unicode="&#xf07b;"
d="M464 320c26.5098 0 48 -21.4902 48 -48v-224c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h146.74c8.49023 0 16.6299 -3.37012 22.6299 -9.37012l54.6299 -54.6299h192zM464 48v224h-198.62
c-8.49023 0 -16.6299 3.37012 -22.6299 9.37012l-54.6299 54.6299h-140.12v-288h416z" />
<glyph glyph-name="folder-open" unicode="&#xf07c;" horiz-adv-x="576"
d="M527.9 224c37.6992 0 60.6992 -41.5 40.6992 -73.4004l-79.8994 -128c-8.7998 -14.0996 -24.2002 -22.5996 -40.7002 -22.5996h-400c-26.5 0 -48 21.5 -48 48v288c0 26.5 21.5 48 48 48h160l64 -64h160c26.5 0 48 -21.5 48 -48v-48h47.9004zM48 330v-233.4l62.9004 104.2
c8.69922 14.4004 24.2998 23.2002 41.0996 23.2002h280v42c0 3.2998 -2.7002 6 -6 6h-173.9l-64 64h-134.1c-3.2998 0 -6 -2.7002 -6 -6zM448 48l80 128h-378.8l-77.2002 -128h376z" />
<glyph glyph-name="chart-bar" unicode="&#xf080;"
d="M396.8 96c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v230.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-230.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM204.8 96
c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v198.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-198.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM300.8 96
c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v134.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-134.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM496 48c8.83984 0 16 -7.16016 16 -16v-16
c0 -8.83984 -7.16016 -16 -16 -16h-464c-17.6699 0 -32 14.3301 -32 32v336c0 8.83984 7.16016 16 16 16h16c8.83984 0 16 -7.16016 16 -16v-320h448zM108.8 96c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v70.4004c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004
c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-70.4004c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004z" />
<glyph glyph-name="comments" unicode="&#xf086;" horiz-adv-x="576"
d="M532 61.7998c15.2998 -30.7002 37.4004 -54.5 37.7998 -54.7998c6.2998 -6.7002 8 -16.5 4.40039 -25c-3.7002 -8.5 -12 -14 -21.2002 -14c-53.5996 0 -96.7002 20.2998 -125.2 38.7998c-19 -4.39941 -39 -6.7998 -59.7998 -6.7998
c-86.2002 0 -159.9 40.4004 -191.3 97.7998c-9.7002 1.2002 -19.2002 2.7998 -28.4004 4.90039c-28.5 -18.6006 -71.7002 -38.7998 -125.2 -38.7998c-9.19922 0 -17.5996 5.5 -21.1992 14c-3.7002 8.5 -1.90039 18.2998 4.39941 25
c0.400391 0.399414 22.4004 24.1992 37.7002 54.8994c-27.5 27.2002 -44 61.2002 -44 98.2002c0 88.4004 93.0996 160 208 160c86.2998 0 160.3 -40.5 191.8 -98.0996c99.7002 -11.8008 176.2 -77.9004 176.2 -157.9c0 -37.0996 -16.5 -71.0996 -44 -98.2002zM139.2 154.1
l19.7998 -4.5c16 -3.69922 32.5 -5.59961 49 -5.59961c86.7002 0 160 51.2998 160 112s-73.2998 112 -160 112s-160 -51.2998 -160 -112c0 -28.7002 16.2002 -50.5996 29.7002 -64l24.7998 -24.5l-15.5 -31.0996c-2.59961 -5.10059 -5.2998 -10.1006 -8 -14.8008
c14.5996 5.10059 29 12.3008 43.0996 21.4004zM498.3 96c13.5 13.4004 29.7002 35.2998 29.7002 64c0 49.2002 -48.2998 91.5 -112.7 106c0.299805 -3.2998 0.700195 -6.59961 0.700195 -10c0 -80.9004 -78 -147.5 -179.3 -158.3
c29.0996 -29.6006 77.2998 -49.7002 131.3 -49.7002c16.5 0 33 1.90039 49 5.59961l19.9004 4.60059l17.0996 -11.1006c14.0996 -9.09961 28.5 -16.2998 43.0996 -21.3994c-2.69922 4.7002 -5.39941 9.7002 -8 14.7998l-15.5 31.0996z" />
<glyph glyph-name="star-half" unicode="&#xf089;" horiz-adv-x="576"
d="M288 62.7002v-54.2998l-130.7 -68.6006c-23.3994 -12.2998 -50.8994 7.60059 -46.3994 33.7002l25 145.5l-105.7 103c-19 18.5 -8.5 50.7998 17.7002 54.5996l146.1 21.2002l65.2998 132.4c5.90039 11.8994 17.2998 17.7998 28.7002 17.7998v-68.0996l-62.2002 -126
l-139 -20.2002l100.601 -98l-23.7002 -138.4z" />
<glyph glyph-name="lemon" unicode="&#xf094;"
d="M484.112 420.111c28.1221 -28.123 35.9434 -68.0039 19.0215 -97.0547c-23.0576 -39.584 50.1436 -163.384 -82.3311 -295.86c-132.301 -132.298 -256.435 -59.3594 -295.857 -82.3291c-29.0459 -16.917 -68.9219 -9.11426 -97.0576 19.0205
c-28.1221 28.1221 -35.9434 68.0029 -19.0215 97.0547c23.0566 39.5859 -50.1436 163.386 82.3301 295.86c132.308 132.309 256.407 59.3496 295.862 82.332c29.0498 16.9219 68.9307 9.09863 97.0537 -19.0234zM461.707 347.217
c13.5166 23.2031 -27.7578 63.7314 -50.4883 50.4912c-66.6025 -38.7939 -165.646 45.5898 -286.081 -74.8457c-120.444 -120.445 -36.0449 -219.472 -74.8447 -286.08c-13.542 -23.2471 27.8145 -63.6953 50.4932 -50.4883
c66.6006 38.7949 165.636 -45.5996 286.076 74.8428c120.444 120.445 36.0449 219.472 74.8447 286.08zM291.846 338.481c1.37012 -10.96 -6.40332 -20.957 -17.3643 -22.3271c-54.8467 -6.85547 -135.779 -87.7871 -142.636 -142.636
c-1.37305 -10.9883 -11.3984 -18.7334 -22.3262 -17.3643c-10.9609 1.37012 -18.7344 11.3652 -17.3643 22.3262c9.16211 73.2852 104.167 168.215 177.364 177.364c10.9531 1.36816 20.9561 -6.40234 22.3262 -17.3633z" />
<glyph glyph-name="credit-card" unicode="&#xf09d;" horiz-adv-x="576"
d="M527.9 416c26.5996 0 48.0996 -21.5 48.0996 -48v-352c0 -26.5 -21.5 -48 -48.0996 -48h-479.801c-26.5996 0 -48.0996 21.5 -48.0996 48v352c0 26.5 21.5 48 48.0996 48h479.801zM54.0996 368c-3.2998 0 -6 -2.7002 -6 -6v-42h479.801v42c0 3.2998 -2.7002 6 -6 6
h-467.801zM521.9 16c3.2998 0 6 2.7002 6 6v170h-479.801v-170c0 -3.2998 2.7002 -6 6 -6h467.801zM192 116v-40c0 -6.59961 -5.40039 -12 -12 -12h-72c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h72c6.59961 0 12 -5.40039 12 -12zM384 116v-40
c0 -6.59961 -5.40039 -12 -12 -12h-136c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h136c6.59961 0 12 -5.40039 12 -12z" />
<glyph glyph-name="hdd" unicode="&#xf0a0;" horiz-adv-x="576"
d="M567.403 212.358c5.59668 -8.04688 8.59668 -17.6113 8.59668 -27.4121v-136.946c0 -26.5098 -21.4902 -48 -48 -48h-480c-26.5098 0 -48 21.4902 -48 48v136.946c0 10.167 3.19531 19.6465 8.59668 27.4121l105.08 151.053
c8.67383 12.4678 23.0791 20.5889 39.4043 20.5889h269.838c16.3252 0 30.7305 -8.12109 39.4043 -20.5889zM153.081 336l-77.9131 -112h425.664l-77.9131 112h-269.838zM528 48v128h-480v-128h480zM496 112c0 -17.6729 -14.3271 -32 -32 -32s-32 14.3271 -32 32
s14.3271 32 32 32s32 -14.3271 32 -32zM400 112c0 -17.6729 -14.3271 -32 -32 -32s-32 14.3271 -32 32s14.3271 32 32 32s32 -14.3271 32 -32z" />
<glyph glyph-name="hand-point-right" unicode="&#xf0a4;"
d="M428.8 310.4c45.0996 0 83.2002 -38.1016 83.2002 -83.2002c0 -45.6162 -37.7646 -83.2002 -83.2002 -83.2002h-35.6475c-1.71387 -7.70605 -4.43555 -15.2051 -7.92969 -22.0645c2.50586 -22.0059 -3.50293 -44.9775 -15.9844 -62.791
c-1.14062 -52.4863 -37.3984 -91.1445 -99.9404 -91.1445h-21.2988c-60.0635 0 -98.5117 40 -127.2 40h-2.67871c-5.74707 -4.95215 -13.5361 -8 -22.1201 -8h-64c-17.6729 0 -32 12.8936 -32 28.7998v230.4c0 15.9062 14.3271 28.7998 32 28.7998h64.001
c8.58398 0 16.373 -3.04785 22.1201 -8h2.67871c6.96387 0 14.8623 6.19336 30.1816 23.6689l0.128906 0.148438l0.130859 0.145508c8.85645 9.93652 18.1162 20.8398 25.8506 33.2529c18.7051 30.2471 30.3936 78.7842 75.707 78.7842c56.9277 0 92 -35.2861 92 -83.2002
c0 -0.0283203 0 0.0361328 0 0.0078125c0 -7.66602 -0.748047 -15.1582 -2.17578 -22.4072h86.1768zM428.8 192c18.9756 0 35.2002 16.2246 35.2002 35.2002c0 18.7002 -16.7754 35.2002 -35.2002 35.2002h-158.399c0 17.3242 26.3994 35.1992 26.3994 70.3994
c0 26.4004 -20.625 35.2002 -44 35.2002c-8.79395 0 -20.4443 -32.7119 -34.9258 -56.0996c-9.07422 -14.5752 -19.5244 -27.2256 -30.7988 -39.875c-16.1094 -18.374 -33.8359 -36.6328 -59.0752 -39.5967v-176.753c42.79 -3.7627 74.5088 -39.6758 120 -39.6758h21.2988
c40.5244 0 57.124 22.1973 50.6006 61.3252c14.6113 8.00098 24.1514 33.9785 12.9248 53.625c19.3652 18.2246 17.7871 46.3809 4.9502 61.0498h91.0254zM88 64c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" />
<glyph glyph-name="hand-point-left" unicode="&#xf0a5;"
d="M0 227.2c0 45.0986 38.1006 83.2002 83.2002 83.2002h86.1758c-1.3623 6.91016 -2.17578 14.374 -2.17578 22.3994c0 47.9141 35.0723 83.2002 92 83.2002c45.3135 0 57.002 -48.5371 75.7061 -78.7852c7.73438 -12.4121 16.9951 -23.3154 25.8506 -33.2529
l0.130859 -0.145508l0.128906 -0.148438c15.3213 -17.4746 23.2197 -23.668 30.1836 -23.668h2.67871c5.74707 4.95215 13.5361 8 22.1201 8h64c17.6729 0 32 -12.8936 32 -28.7998v-230.4c0 -15.9062 -14.3271 -28.7998 -32 -28.7998h-64
c-8.58398 0 -16.373 3.04785 -22.1201 8h-2.67871c-28.6885 0 -67.1367 -40 -127.2 -40h-21.2988c-62.542 0 -98.8008 38.6582 -99.9404 91.1445c-12.4814 17.8135 -18.4922 40.7852 -15.9844 62.791c-3.49414 6.85938 -6.21582 14.3584 -7.92969 22.0645h-35.6465
c-45.4355 0 -83.2002 37.584 -83.2002 83.2002zM48 227.2c0 -18.9756 16.2246 -35.2002 35.2002 -35.2002h91.0244c-12.8369 -14.6689 -14.415 -42.8252 4.9502 -61.0498c-11.2256 -19.6465 -1.68652 -45.624 12.9248 -53.625
c-6.52246 -39.1279 10.0771 -61.3252 50.6016 -61.3252h21.2988c45.4912 0 77.21 35.9131 120 39.6768v176.752c-25.2393 2.96289 -42.9658 21.2227 -59.0752 39.5967c-11.2744 12.6494 -21.7246 25.2998 -30.7988 39.875
c-14.4814 23.3877 -26.1318 56.0996 -34.9258 56.0996c-23.375 0 -44 -8.7998 -44 -35.2002c0 -35.2002 26.3994 -53.0752 26.3994 -70.3994h-158.399c-18.4248 0 -35.2002 -16.5 -35.2002 -35.2002zM448 88c-13.2549 0 -24 -10.7451 -24 -24s10.7451 -24 24 -24
s24 10.7451 24 24s-10.7451 24 -24 24z" />
<glyph glyph-name="hand-point-up" unicode="&#xf0a6;" horiz-adv-x="448"
d="M105.6 364.8c0 45.0996 38.1016 83.2002 83.2002 83.2002c45.6162 0 83.2002 -37.7646 83.2002 -83.2002v-35.6465c7.70605 -1.71387 15.2051 -4.43555 22.0645 -7.92969c22.0059 2.50684 44.9775 -3.50293 62.791 -15.9844
c52.4863 -1.14062 91.1445 -37.3984 91.1445 -99.9404v-21.2988c0 -60.0635 -40 -98.5117 -40 -127.2v-2.67871c4.95215 -5.74707 8 -13.5361 8 -22.1201v-64c0 -17.6729 -12.8936 -32 -28.7998 -32h-230.4c-15.9062 0 -28.7998 14.3271 -28.7998 32v64
c0 8.58398 3.04785 16.373 8 22.1201v2.67871c0 6.96387 -6.19336 14.8623 -23.6689 30.1816l-0.148438 0.128906l-0.145508 0.130859c-9.93652 8.85645 -20.8398 18.1162 -33.2529 25.8506c-30.2471 18.7051 -78.7842 30.3936 -78.7842 75.707
c0 56.9277 35.2861 92 83.2002 92c0.0283203 0 -0.0361328 0 -0.0078125 0c7.66602 0 15.1582 -0.748047 22.4072 -2.17578v86.1768zM224 364.8c0 18.9756 -16.2246 35.2002 -35.2002 35.2002c-18.7002 0 -35.2002 -16.7754 -35.2002 -35.2002v-158.399
c-17.3242 0 -35.1992 26.3994 -70.3994 26.3994c-26.4004 0 -35.2002 -20.625 -35.2002 -44c0 -8.79395 32.7119 -20.4443 56.0996 -34.9258c14.5752 -9.07422 27.2256 -19.5244 39.875 -30.7988c18.374 -16.1094 36.6328 -33.8359 39.5967 -59.0752h176.753
c3.7627 42.79 39.6758 74.5088 39.6758 120v21.2988c0 40.5244 -22.1973 57.124 -61.3252 50.6006c-8.00098 14.6113 -33.9785 24.1514 -53.625 12.9248c-18.2246 19.3652 -46.3809 17.7871 -61.0498 4.9502v91.0254zM352 24c-13.2549 0 -24 -10.7451 -24 -24
s10.7451 -24 24 -24s24 10.7451 24 24s-10.7451 24 -24 24z" />
<glyph glyph-name="hand-point-down" unicode="&#xf0a7;" horiz-adv-x="448"
d="M188.8 -64c-45.0986 0 -83.2002 38.1006 -83.2002 83.2002v86.1758c-6.91016 -1.3623 -14.374 -2.17578 -22.3994 -2.17578c-47.9141 0 -83.2002 35.0723 -83.2002 92c0 45.3135 48.5371 57.002 78.7852 75.707c12.4121 7.73438 23.3154 16.9951 33.2529 25.8506
l0.145508 0.130859l0.148438 0.128906c17.4746 15.3213 23.668 23.2197 23.668 30.1836v2.67871c-4.95215 5.74707 -8 13.5361 -8 22.1201v64c0 17.6729 12.8936 32 28.7998 32h230.4c15.9062 0 28.7998 -14.3271 28.7998 -32v-64.001
c0 -8.58398 -3.04785 -16.373 -8 -22.1201v-2.67871c0 -28.6885 40 -67.1367 40 -127.2v-21.2988c0 -62.542 -38.6582 -98.8008 -91.1445 -99.9404c-17.8135 -12.4814 -40.7852 -18.4922 -62.791 -15.9844c-6.85938 -3.49414 -14.3584 -6.21582 -22.0645 -7.92969v-35.6465
c0 -45.4355 -37.584 -83.2002 -83.2002 -83.2002zM188.8 -16c18.9756 0 35.2002 16.2246 35.2002 35.2002v91.0244c14.6689 -12.8369 42.8252 -14.415 61.0498 4.9502c19.6465 -11.2256 45.624 -1.68652 53.625 12.9248c39.1279 -6.52246 61.3252 10.0771 61.3252 50.6016
v21.2988c0 45.4912 -35.9131 77.21 -39.6768 120h-176.752c-2.96289 -25.2393 -21.2227 -42.9658 -39.5967 -59.0752c-12.6494 -11.2744 -25.2998 -21.7246 -39.875 -30.7988c-23.3877 -14.4814 -56.0996 -26.1318 -56.0996 -34.9258c0 -23.375 8.7998 -44 35.2002 -44
c35.2002 0 53.0752 26.3994 70.3994 26.3994v-158.399c0 -18.4248 16.5 -35.2002 35.2002 -35.2002zM328 384c0 -13.2549 10.7451 -24 24 -24s24 10.7451 24 24s-10.7451 24 -24 24s-24 -10.7451 -24 -24z" />
<glyph glyph-name="copy" unicode="&#xf0c5;" horiz-adv-x="448"
d="M433.941 382.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-80v-48c0 -26.5098 -21.4902 -48 -48 -48h-224c-26.5098 0 -48 21.4902 -48 48v320c0 26.5098 21.4902 48 48 48h80v48c0 26.5098 21.4902 48 48 48
h172.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM266 -16c3.31152 0 6 2.68848 6 6v42h-96c-26.5098 0 -48 21.4902 -48 48v224h-74c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM394 80c3.31152 0 6 2.68848 6 6v202h-88
c-13.2549 0 -24 10.7451 -24 24v88h-106c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM400 336v9.63184c0 1.65527 -0.670898 3.15723 -1.75684 4.24316l-48.3682 48.3682c-1.12598 1.125 -2.65234 1.75684 -4.24316 1.75684h-9.63184v-64h64z" />
<glyph glyph-name="save" unicode="&#xf0c7;" horiz-adv-x="448"
d="M433.941 318.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h268.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM272 368h-128v-80h128v80z
M394 16c3.31152 0 6 2.68848 6 6v259.632c0 1.65527 -0.670898 3.15723 -1.75684 4.24316l-78.2432 78.2432v-100.118c0 -13.2549 -10.7451 -24 -24 -24h-176c-13.2549 0 -24 10.7451 -24 24v104h-42c-3.31152 0 -6 -2.68848 -6 -6v-340c0 -3.31152 2.68848 -6 6 -6h340z
M224 216c48.5234 0 88 -39.4766 88 -88s-39.4766 -88 -88 -88s-88 39.4766 -88 88s39.4766 88 88 88zM224 88c22.0557 0 40 17.9443 40 40s-17.9443 40 -40 40s-40 -17.9443 -40 -40s17.9443 -40 40 -40z" />
<glyph glyph-name="square" unicode="&#xf0c8;" horiz-adv-x="448"
d="M400 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352zM394 16c3.2998 0 6 2.7002 6 6v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340z" />
<glyph glyph-name="envelope" unicode="&#xf0e0;"
d="M464 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h416zM464 336h-416v-40.8047c22.4248 -18.2627 58.1797 -46.6602 134.587 -106.49
c16.834 -13.2422 50.2051 -45.0762 73.4131 -44.7012c23.2119 -0.371094 56.5723 31.4541 73.4131 44.7012c76.4189 59.8389 112.165 88.2305 134.587 106.49v40.8047zM48 48h416v185.601c-22.915 -18.252 -55.4189 -43.8691 -104.947 -82.6523
c-22.5439 -17.748 -60.3359 -55.1787 -103.053 -54.9473c-42.9277 -0.231445 -81.2051 37.75 -103.062 54.9551c-49.5293 38.7842 -82.0244 64.3945 -104.938 82.6455v-185.602z" />
<glyph glyph-name="lightbulb" unicode="&#xf0eb;" horiz-adv-x="352"
d="M176 368c8.83984 0 16 -7.16016 16 -16s-7.16016 -16 -16 -16c-35.2803 0 -64 -28.7002 -64 -64c0 -8.83984 -7.16016 -16 -16 -16s-16 7.16016 -16 16c0 52.9404 43.0596 96 96 96zM96.0596 -11.1699l-0.0400391 43.1797h159.961l-0.0507812 -43.1797
c-0.00976562 -3.13965 -0.939453 -6.21973 -2.67969 -8.83984l-24.5098 -36.8398c-2.95996 -4.45996 -7.95996 -7.14062 -13.3203 -7.14062h-78.8496c-5.35059 0 -10.3506 2.68066 -13.3203 7.14062l-24.5098 36.8398c-1.75 2.62012 -2.68066 5.68945 -2.68066 8.83984z
M176 448c97.2002 0 176 -78.7998 176 -176c0 -44.3701 -16.4502 -84.8496 -43.5498 -115.79c-16.6406 -18.9795 -42.7402 -58.79 -52.4199 -92.1602v-0.0498047h-48v0.0996094c0.00488281 4.98145 0.790039 9.78809 2.21973 14.3008
c5.67969 17.9893 22.9902 64.8496 62.0996 109.46c20.4102 23.29 31.6504 53.1699 31.6504 84.1396c0 70.5801 -57.4199 128 -128 128c-68.2803 0 -128.15 -54.3604 -127.95 -128c0.0898438 -30.9902 11.0703 -60.71 31.6104 -84.1396
c39.3496 -44.9004 56.5801 -91.8604 62.1699 -109.67c1.42969 -4.56055 2.13965 -9.30078 2.15039 -14.0703v-0.120117h-48v0.0595703c-9.68066 33.3604 -35.7803 73.1709 -52.4209 92.1602c-27.1094 30.9307 -43.5596 71.4102 -43.5596 115.78
c0 93.0303 73.7197 176 176 176z" />
<glyph glyph-name="bell" unicode="&#xf0f3;" horiz-adv-x="448"
d="M439.39 85.71c6 -6.44043 8.66016 -14.1602 8.61035 -21.71c-0.0996094 -16.4004 -12.9805 -32 -32.0996 -32h-383.801c-19.1191 0 -31.9893 15.5996 -32.0996 32c-0.0498047 7.5498 2.61035 15.2598 8.61035 21.71c19.3193 20.7598 55.4697 51.9902 55.4697 154.29
c0 77.7002 54.4795 139.9 127.939 155.16v20.8398c0 17.6699 14.3203 32 31.9805 32s31.9805 -14.3301 31.9805 -32v-20.8398c73.46 -15.2598 127.939 -77.46 127.939 -155.16c0 -102.3 36.1504 -133.53 55.4697 -154.29zM67.5303 80h312.939
c-21.2197 27.96 -44.4199 74.3203 -44.5293 159.42c0 0.200195 0.0595703 0.379883 0.0595703 0.580078c0 61.8604 -50.1396 112 -112 112s-112 -50.1396 -112 -112c0 -0.200195 0.0595703 -0.379883 0.0595703 -0.580078
c-0.109375 -85.0898 -23.3096 -131.45 -44.5293 -159.42zM224 -64c-35.3203 0 -63.9697 28.6504 -63.9697 64h127.939c0 -35.3496 -28.6494 -64 -63.9697 -64z" />
<glyph glyph-name="hospital" unicode="&#xf0f8;" horiz-adv-x="448"
d="M128 204v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40c0 -6.62695 -5.37305 -12 -12 -12h-40c-6.62695 0 -12 5.37305 -12 12zM268 192c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40
c0 -6.62695 -5.37305 -12 -12 -12h-40zM192 108c0 -6.62695 -5.37305 -12 -12 -12h-40c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40zM268 96c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40
c6.62695 0 12 -5.37305 12 -12v-40c0 -6.62695 -5.37305 -12 -12 -12h-40zM448 -28v-36h-448v36c0 6.62695 5.37305 12 12 12h19.5v378.965c0 11.6172 10.7451 21.0352 24 21.0352h88.5v40c0 13.2549 10.7451 24 24 24h112c13.2549 0 24 -10.7451 24 -24v-40h88.5
c13.2549 0 24 -9.41797 24 -21.0352v-378.965h19.5c6.62695 0 12 -5.37305 12 -12zM79.5 -15h112.5v67c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-67h112.5v351h-64.5v-24c0 -13.2549 -10.7451 -24 -24 -24h-112c-13.2549 0 -24 10.7451 -24 24v24
h-64.5v-351zM266 384h-26v26c0 3.31152 -2.68848 6 -6 6h-20c-3.31152 0 -6 -2.68848 -6 -6v-26h-26c-3.31152 0 -6 -2.68848 -6 -6v-20c0 -3.31152 2.68848 -6 6 -6h26v-26c0 -3.31152 2.68848 -6 6 -6h20c3.31152 0 6 2.68848 6 6v26h26c3.31152 0 6 2.68848 6 6v20
c0 3.31152 -2.68848 6 -6 6z" />
<glyph glyph-name="plus-square" unicode="&#xf0fe;" horiz-adv-x="448"
d="M352 208v-32c0 -6.59961 -5.40039 -12 -12 -12h-88v-88c0 -6.59961 -5.40039 -12 -12 -12h-32c-6.59961 0 -12 5.40039 -12 12v88h-88c-6.59961 0 -12 5.40039 -12 12v32c0 6.59961 5.40039 12 12 12h88v88c0 6.59961 5.40039 12 12 12h32c6.59961 0 12 -5.40039 12 -12
v-88h88c6.59961 0 12 -5.40039 12 -12zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340
c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="circle" unicode="&#xf111;"
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200z" />
<glyph glyph-name="smile" unicode="&#xf118;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM332 135.4c8.5 10.1992 23.7002 11.5 33.7998 3.09961c10.2002 -8.5 11.6006 -23.5996 3.10059 -33.7998
c-30 -36 -74.1006 -56.6006 -120.9 -56.6006s-90.9004 20.6006 -120.9 56.6006c-8.39941 10.2002 -7.09961 25.2998 3.10059 33.7998c10.0996 8.40039 25.2998 7.09961 33.7998 -3.09961c20.7998 -25.1006 51.5 -39.4004 84 -39.4004s63.2002 14.4004 84 39.4004z" />
<glyph glyph-name="frown" unicode="&#xf119;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM248 144c40.2002 0 78 -17.7002 103.8 -48.5996c8.40039 -10.2002 7.10059 -25.3008 -3.09961 -33.8008
c-10.7002 -8.7998 -25.7002 -6.59961 -33.7998 3.10059c-16.6006 20 -41 31.3994 -66.9004 31.3994s-50.2998 -11.5 -66.9004 -31.3994c-8.5 -10.2002 -23.5996 -11.5 -33.7998 -3.10059c-10.2002 8.5 -11.5996 23.6006 -3.09961 33.8008
c25.7998 30.8994 63.5996 48.5996 103.8 48.5996z" />
<glyph glyph-name="meh" unicode="&#xf11a;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM336 128c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-176c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h176z
" />
<glyph glyph-name="keyboard" unicode="&#xf11c;" horiz-adv-x="576"
d="M528 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-480c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h480zM536 48v288c0 4.41113 -3.58887 8 -8 8h-480c-4.41113 0 -8 -3.58887 -8 -8v-288c0 -4.41113 3.58887 -8 8 -8
h480c4.41113 0 8 3.58887 8 8zM170 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM266 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28
c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM362 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM458 178c0 -6.62695 -5.37305 -12 -12 -12h-28
c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM122 96c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM506 96
c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM122 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28
c6.62695 0 12 -5.37305 12 -12v-28zM218 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM314 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28
c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM410 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM506 260c0 -6.62695 -5.37305 -12 -12 -12h-28
c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM408 102c0 -6.62695 -5.37305 -12 -12 -12h-216c-6.62695 0 -12 5.37305 -12 12v16c0 6.62695 5.37305 12 12 12h216c6.62695 0 12 -5.37305 12 -12v-16z" />
<glyph glyph-name="calendar" unicode="&#xf133;" horiz-adv-x="448"
d="M400 384c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12
v-52h48zM394 -16c3.2998 0 6 2.7002 6 6v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340z" />
<glyph glyph-name="play-circle" unicode="&#xf144;"
d="M371.7 210c16.3994 -9.2002 16.3994 -32.9004 0 -42l-176 -101c-15.9004 -8.7998 -35.7002 2.59961 -35.7002 21v208c0 18.5 19.9004 29.7998 35.7002 21zM504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192
c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200z" />
<glyph glyph-name="minus-square" unicode="&#xf146;" horiz-adv-x="448"
d="M108 164c-6.59961 0 -12 5.40039 -12 12v32c0 6.59961 5.40039 12 12 12h232c6.59961 0 12 -5.40039 12 -12v-32c0 -6.59961 -5.40039 -12 -12 -12h-232zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352
c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="check-square" unicode="&#xf14a;" horiz-adv-x="448"
d="M400 416c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h352zM400 16v352h-352v-352h352zM364.136 257.724l-172.589 -171.204
c-4.70508 -4.66699 -12.3027 -4.63672 -16.9697 0.0683594l-90.7812 91.5156c-4.66699 4.70508 -4.63672 12.3037 0.0693359 16.9717l22.7188 22.5361c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0693359l59.792 -60.2773l141.353 140.217
c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0683594l22.5361 -22.7178c4.66699 -4.70605 4.63672 -12.3047 -0.0683594 -16.9717z" />
<glyph glyph-name="share-square" unicode="&#xf14d;" horiz-adv-x="576"
d="M561.938 289.94c18.75 -18.7402 18.75 -49.1406 0 -67.8809l-143.998 -144c-29.9727 -29.9727 -81.9404 -9.05273 -81.9404 33.9404v53.7998c-101.266 -7.83691 -99.625 -31.6406 -84.1104 -78.7598c14.2285 -43.0889 -33.4736 -79.248 -71.0195 -55.7402
c-51.6924 32.3057 -84.8701 83.0635 -84.8701 144.76c0 39.3408 12.2197 72.7402 36.3301 99.3008c19.8398 21.8398 47.7402 38.4697 82.9102 49.4199c36.7295 11.4395 78.3096 16.1094 120.76 17.9893v57.1982c0 42.9355 51.9258 63.9541 81.9404 33.9404zM384 112l144 144
l-144 144v-104.09c-110.86 -0.90332 -240 -10.5166 -240 -119.851c0 -52.1396 32.79 -85.6094 62.3096 -104.06c-39.8174 120.65 48.999 141.918 177.69 143.84v-103.84zM408.74 27.5068c7.4375 2.125 14.5508 5.30566 20.9736 9.30273
c7.97656 4.95215 18.2861 -0.825195 18.2861 -10.2139v-42.5957c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h132c6.62695 0 12 -5.37305 12 -12v-4.48633c0 -4.91699 -2.9873 -9.36914 -7.56934 -11.1514
c-13.7021 -5.33105 -26.3955 -11.5371 -38.0498 -18.585c-1.82715 -1.11523 -3.98633 -1.76953 -6.28027 -1.77734h-86.1006c-3.31152 0 -6 -2.68848 -6 -6v-340c0 -3.31152 2.68848 -6 6 -6h340c3.31152 0 6 2.68848 6 6v25.9658c0 5.37012 3.5791 10.0596 8.74023 11.541z
" />
<glyph glyph-name="compass" unicode="&#xf14e;" horiz-adv-x="496"
d="M347.94 318.14c16.6592 7.61035 33.8096 -9.54004 26.1992 -26.1992l-65.9697 -144.341c-3.19238 -6.9834 -8.78613 -12.5771 -15.7695 -15.7695l-144.341 -65.9697c-16.6592 -7.61035 -33.8096 9.5498 -26.1992 26.1992l65.9697 144.341
c3.19238 6.9834 8.78613 12.5771 15.7695 15.7695zM270.58 169.42c12.4697 12.4697 12.4697 32.6904 0 45.1602s-32.6904 12.4697 -45.1602 0s-12.4697 -32.6904 0 -45.1602s32.6904 -12.4697 45.1602 0zM248 440c136.97 0 248 -111.03 248 -248s-111.03 -248 -248 -248
s-248 111.03 -248 248s111.03 248 248 248zM248 -8c110.28 0 200 89.7197 200 200s-89.7197 200 -200 200s-200 -89.7197 -200 -200s89.7197 -200 200 -200z" />
<glyph glyph-name="caret-square-down" unicode="&#xf150;" horiz-adv-x="448"
d="M125.1 240h197.801c10.6992 0 16.0996 -13 8.5 -20.5l-98.9004 -98.2998c-4.7002 -4.7002 -12.2002 -4.7002 -16.9004 0l-98.8994 98.2998c-7.7002 7.5 -2.2998 20.5 8.39941 20.5zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="caret-square-up" unicode="&#xf151;" horiz-adv-x="448"
d="M322.9 144h-197.801c-10.6992 0 -16.0996 13 -8.5 20.5l98.9004 98.2998c4.7002 4.7002 12.2002 4.7002 16.9004 0l98.8994 -98.2998c7.7002 -7.5 2.2998 -20.5 -8.39941 -20.5zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="caret-square-right" unicode="&#xf152;" horiz-adv-x="448"
d="M176 93.0996v197.801c0 10.6992 13 16.0996 20.5 8.5l98.2998 -98.9004c4.7002 -4.7002 4.7002 -12.2002 0 -16.9004l-98.2998 -98.8994c-7.5 -7.7002 -20.5 -2.2998 -20.5 8.39941zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="file" unicode="&#xf15b;" horiz-adv-x="384"
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416z" />
<glyph glyph-name="file-alt" unicode="&#xf15c;" horiz-adv-x="384"
d="M288 200v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12v28c0 6.59961 5.40039 12 12 12h168c6.59961 0 12 -5.40039 12 -12zM276 128c6.59961 0 12 -5.40039 12 -12v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12
v28c0 6.59961 5.40039 12 12 12h168zM384 316.1v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996l83.9004 -83.9004c9 -8.90039 14.0996 -21.2002 14.0996 -33.9004z
M256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416h288z" />
<glyph glyph-name="thumbs-up" unicode="&#xf164;"
d="M466.27 161.31c4.6748 -22.6465 0.864258 -44.5371 -8.98926 -62.9893c2.95898 -23.8682 -4.02148 -48.5654 -17.3398 -66.9902c-0.954102 -55.9072 -35.8232 -95.3301 -112.94 -95.3301c-7 0 -15 0.00976562 -22.2197 0.00976562
c-102.742 0 -133.293 38.9395 -177.803 39.9404c-3.56934 -13.7764 -16.085 -23.9502 -30.9775 -23.9502h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h98.7598c19.1455 16.9531 46.0137 60.6533 68.7598 83.4004
c13.667 13.667 10.1533 108.6 71.7607 108.6c57.5801 0 95.2695 -31.9355 95.2695 -104.73c0 -18.4092 -3.92969 -33.7295 -8.84961 -46.5391h36.4795c48.6025 0 85.8203 -41.5654 85.8203 -85.5801c0 -19.1504 -4.95996 -34.9902 -13.7305 -49.8408zM404.52 107.48
c21.5811 20.3838 18.6992 51.0645 5.21094 65.6191c9.44922 0 22.3594 18.9102 22.2695 37.8105c-0.0898438 18.9102 -16.71 37.8203 -37.8203 37.8203h-103.989c0 37.8193 28.3594 55.3691 28.3594 94.5391c0 23.75 0 56.7305 -47.2695 56.7305
c-18.9102 -18.9102 -9.45996 -66.1797 -37.8203 -94.54c-26.5596 -26.5703 -66.1797 -97.46 -94.54 -97.46h-10.9199v-186.17c53.6113 0 100.001 -37.8203 171.64 -37.8203h37.8203c35.5117 0 60.8203 17.1201 53.1201 65.9004
c15.2002 8.16016 26.5 36.4395 13.9395 57.5703zM88 16c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" />
<glyph glyph-name="thumbs-down" unicode="&#xf165;"
d="M466.27 222.69c8.77051 -14.8506 13.7305 -30.6904 13.7305 -49.8408c0 -44.0146 -37.2178 -85.5801 -85.8203 -85.5801h-36.4795c4.91992 -12.8096 8.84961 -28.1299 8.84961 -46.5391c0 -72.7949 -37.6895 -104.73 -95.2695 -104.73
c-61.6074 0 -58.0938 94.9326 -71.7607 108.6c-22.7461 22.7471 -49.6133 66.4473 -68.7598 83.4004h-7.05176c-5.5332 -9.56152 -15.8662 -16 -27.708 -16h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h64c8.11328 0 15.5146 -3.02539 21.1553 -8
h10.8447c40.9971 0 73.1953 39.9902 176.78 39.9902c7.21973 0 15.2197 0.00976562 22.2197 0.00976562c77.1172 0 111.986 -39.4229 112.94 -95.3301c13.3184 -18.4248 20.2979 -43.1221 17.3398 -66.9902c9.85352 -18.4521 13.6641 -40.3428 8.98926 -62.9893zM64 152
c13.2549 0 24 10.7451 24 24s-10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24zM394.18 135.27c21.1104 0 37.7305 18.9102 37.8203 37.8203c0.0898438 18.9004 -12.8203 37.8105 -22.2695 37.8105c13.4883 14.5547 16.3701 45.2354 -5.21094 65.6191
c12.5605 21.1309 1.26074 49.4102 -13.9395 57.5703c7.7002 48.7803 -17.6084 65.9004 -53.1201 65.9004h-37.8203c-71.6387 0 -118.028 -37.8203 -171.64 -37.8203v-186.17h10.9199c28.3604 0 67.9805 -70.8896 94.54 -97.46
c28.3604 -28.3604 18.9102 -75.6299 37.8203 -94.54c47.2695 0 47.2695 32.9805 47.2695 56.7305c0 39.1699 -28.3594 56.7197 -28.3594 94.5391h103.989z" />
<glyph glyph-name="sun" unicode="&#xf185;"
d="M494.2 226.1c11.2002 -7.59961 17.7998 -20.0996 17.8994 -33.6992c0 -13.4004 -6.69922 -26 -17.7998 -33.5l-59.7998 -40.5l13.7002 -71c2.5 -13.2002 -1.60059 -26.8008 -11.1006 -36.3008s-22.8994 -13.7998 -36.2998 -11.0996l-70.8994 13.7002l-40.4004 -59.9004
c-7.5 -11.0996 -20.0996 -17.7998 -33.5 -17.7998s-26 6.7002 -33.5 17.9004l-40.4004 59.8994l-70.7998 -13.7002c-13.3994 -2.59961 -26.7998 1.60059 -36.2998 11.1006s-13.7002 23.0996 -11.0996 36.2998l13.6992 71l-59.7998 40.5
c-11.0996 7.5 -17.7998 20 -17.7998 33.5s6.59961 26 17.7998 33.5996l59.7998 40.5l-13.6992 71c-2.60059 13.2002 1.59961 26.7002 11.0996 36.3008c9.5 9.59961 23 13.6992 36.2998 11.1992l70.7998 -13.6992l40.4004 59.8994c15.0996 22.2998 51.9004 22.2998 67 0
l40.4004 -59.8994l70.8994 13.6992c13 2.60059 26.6006 -1.59961 36.2002 -11.0996c9.5 -9.59961 13.7002 -23.2002 11.0996 -36.4004l-13.6992 -71zM381.3 140.5l76.7998 52.0996l-76.7998 52l17.6006 91.1006l-91 -17.6006l-51.9004 76.9004l-51.7998 -76.7998
l-91 17.5996l17.5996 -91.2002l-76.7998 -52l76.7998 -52l-17.5996 -91.1992l90.8994 17.5996l51.9004 -77l51.9004 76.9004l91 -17.6006zM256 296c57.2998 0 104 -46.7002 104 -104s-46.7002 -104 -104 -104s-104 46.7002 -104 104s46.7002 104 104 104zM256 136
c30.9004 0 56 25.0996 56 56s-25.0996 56 -56 56s-56 -25.0996 -56 -56s25.0996 -56 56 -56z" />
<glyph glyph-name="moon" unicode="&#xf186;"
d="M279.135 -64c-141.424 0 -256 114.64 -256 256c0 141.425 114.641 256 256 256c16.0342 -0.00292969 31.5078 -1.46875 46.7354 -4.27734c44.0205 -8.13086 53.7666 -66.8691 15.0215 -88.9189c-41.374 -23.5439 -67.4336 -67.4121 -67.4336 -115.836
c0 -83.5234 75.9238 -146.475 158.272 -130.792c43.6904 8.32129 74.5186 -42.5693 46.248 -77.4004c-47.8613 -58.9717 -120.088 -94.7754 -198.844 -94.7754zM279.135 400c-114.875 0 -208 -93.125 -208 -208s93.125 -208 208 -208
c65.2314 0 123.439 30.0361 161.575 77.0244c-111.611 -21.2568 -215.252 64.0957 -215.252 177.943c0 67.5127 36.9326 126.392 91.6934 157.555c-12.3271 2.27637 -25.0312 3.47754 -38.0166 3.47754z" />
<glyph glyph-name="caret-square-left" unicode="&#xf191;" horiz-adv-x="448"
d="M272 290.9v-197.801c0 -10.6992 -13 -16.0996 -20.5 -8.5l-98.2998 98.9004c-4.7002 4.7002 -4.7002 12.2002 0 16.9004l98.2998 98.8994c7.5 7.7002 20.5 2.2998 20.5 -8.39941zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="dot-circle" unicode="&#xf192;"
d="M256 392c-110.549 0 -200 -89.4678 -200 -200c0 -110.549 89.4678 -200 200 -200c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200zM256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248z
M256 272c44.1826 0 80 -35.8174 80 -80s-35.8174 -80 -80 -80s-80 35.8174 -80 80s35.8174 80 80 80z" />
<glyph glyph-name="building" unicode="&#xf1ad;" horiz-adv-x="448"
d="M128 300v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12zM268 288c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40
c0 -6.59961 -5.40039 -12 -12 -12h-40zM140 192c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM268 192c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40
c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM192 108c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM268 96c-6.59961 0 -12 5.40039 -12 12v40
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM448 -28v-36h-448v36c0 6.59961 5.40039 12 12 12h19.5v440c0 13.2998 10.7002 24 24 24h337c13.2998 0 24 -10.7002 24 -24v-440h19.5
c6.59961 0 12 -5.40039 12 -12zM79.5 -15h112.5v67c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-67h112.5v414l-288.5 1z" />
<glyph glyph-name="file-pdf" unicode="&#xf1c1;" horiz-adv-x="384"
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM298.2 127.7c10.5 -10.5 8 -38.7002 -17.5 -38.7002c-14.7998 0 -36.9004 6.7998 -55.7998 17c-21.6006 -3.59961 -46 -12.7002 -68.4004 -20.0996c-50.0996 -86.4004 -79.4004 -47 -76.0996 -31.2002
c4 20 31 35.8994 51 46.2002c10.5 18.3994 25.3994 50.5 35.3994 74.3994c-7.39941 28.6006 -11.3994 51 -7 67.1006c4.7998 17.6992 38.4004 20.2998 42.6006 -5.90039c4.69922 -15.4004 -1.5 -39.9004 -5.40039 -56c8.09961 -21.2998 19.5996 -35.7998 36.7998 -46.2998
c17.4004 2.2002 52.2002 5.5 64.4004 -6.5zM100.1 49.9004c0 -0.700195 11.4004 4.69922 30.4004 35c-5.90039 -5.5 -25.2998 -21.3008 -30.4004 -35zM181.7 240.5c-2.5 0 -2.60059 -26.9004 1.7998 -40.7998c4.90039 8.7002 5.59961 40.7998 -1.7998 40.7998zM157.3 103.9
c15.9004 6.09961 34 14.8994 54.7998 19.1992c-11.1992 8.30078 -21.7998 20.4004 -30.0996 35.5c-6.7002 -17.6992 -15 -37.7998 -24.7002 -54.6992zM288.9 108.9c3.59961 2.39941 -2.2002 10.3994 -37.3008 7.7998c32.3008 -13.7998 37.3008 -7.7998 37.3008 -7.7998z" />
<glyph glyph-name="file-word" unicode="&#xf1c2;" horiz-adv-x="384"
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM268.1 192v0.200195h15.8008c7.7998 0 13.5 -7.2998 11.5996 -14.9004c-4.2998 -17 -13.7002 -54.0996 -34.5 -136c-1.2998 -5.39941 -6.09961 -9.09961 -11.5996 -9.09961h-24.7002
c-5.5 0 -10.2998 3.7998 -11.6006 9.09961c-5.2998 20.9004 -17.7998 71 -17.8994 71.4004l-2.90039 17.2998c-0.5 -5.2998 -1.5 -11.0996 -3 -17.2998l-17.8994 -71.4004c-1.30078 -5.39941 -6.10059 -9.09961 -11.6006 -9.09961h-25.2002
c-5.59961 0 -10.3994 3.7002 -11.6992 9.09961c-6.5 26.5 -25.2002 103.4 -33.2002 136c-1.7998 7.5 3.89941 14.7998 11.7002 14.7998h16.7998c5.7998 0 10.7002 -4.09961 11.7998 -9.69922c5 -25.7002 18.4004 -93.8008 19.0996 -99
c0.300781 -1.7002 0.400391 -3.10059 0.5 -4.2002c0.800781 7.5 0.400391 4.7002 24.8008 103.7c1.39941 5.2998 6.19922 9.09961 11.6992 9.09961h13.3008c5.59961 0 10.3994 -3.7998 11.6992 -9.2002c23.9004 -99.7002 22.8008 -94.3994 23.6006 -99.5
c0.299805 -1.7002 0.5 -3.09961 0.700195 -4.2998c0.599609 8.09961 0.399414 5.7998 21 103.5c1.09961 5.5 6 9.5 11.6992 9.5z" />
<glyph glyph-name="file-excel" unicode="&#xf1c3;" horiz-adv-x="384"
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM260 224c9.2002 0 15 -10 10.2998 -18c-16 -27.5 -45.5996 -76.9004 -46.2998 -78l46.4004 -78c4.59961 -8 -1.10059 -18 -10.4004 -18h-28.7998c-4.40039 0 -8.5 2.40039 -10.6006 6.2998
c-22.6992 41.7998 -13.6992 27.5 -28.5996 57.7002c-5.59961 -12.7002 -6.90039 -17.7002 -28.5996 -57.7002c-2.10059 -3.89941 -6.10059 -6.2998 -10.5 -6.2998h-28.9004c-9.2998 0 -15.0996 10 -10.4004 18l46.3008 78l-46.3008 78c-4.59961 8 1.10059 18 10.4004 18
h28.9004c4.39941 0 8.5 -2.40039 10.5996 -6.2998c21.7002 -40.4004 14.7002 -28.6006 28.5996 -57.7002c6.40039 15.2998 10.6006 24.5996 28.6006 57.7002c2.09961 3.89941 6.09961 6.2998 10.5 6.2998h28.7998z" />
<glyph glyph-name="file-powerpoint" unicode="&#xf1c4;" horiz-adv-x="384"
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM120 44v168c0 6.59961 5.40039 12 12 12h69.2002c36.7002 0 62.7998 -27 62.7998 -66.2998c0 -74.2998 -68.7002 -66.5 -95.5 -66.5v-47.2002c0 -6.59961 -5.40039 -12 -12 -12h-24.5c-6.59961 0 -12 5.40039 -12 12z
M168.5 131.4h23c7.90039 0 13.9004 2.39941 18.0996 7.19922c8.5 9.80078 8.40039 28.5 0.100586 37.8008c-4.10059 4.59961 -9.90039 7 -17.4004 7h-23.8994v-52h0.0996094z" />
<glyph glyph-name="file-image" unicode="&#xf1c5;" horiz-adv-x="384"
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM80 32v64l39.5 39.5c4.7002 4.7002 12.2998 4.7002 17 0l39.5 -39.5l87.5 87.5c4.7002 4.7002 12.2998 4.7002 17 0l23.5 -23.5v-128h-224zM128 272c26.5 0 48 -21.5 48 -48s-21.5 -48 -48 -48s-48 21.5 -48 48
s21.5 48 48 48z" />
<glyph glyph-name="file-archive" unicode="&#xf1c6;" horiz-adv-x="384"
d="M128.3 288h32v-32h-32v32zM192.3 384v-32h-32v32h32zM128.3 352h32v-32h-32v32zM192.3 320v-32h-32v32h32zM369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1
c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-48.2998v-16h-32v16h-79.7002v-416h288zM194.2 182.3l17.2998 -87.7002c6.40039 -32.3994 -18.4004 -62.5996 -51.5 -62.5996
c-33.2002 0 -58 30.4004 -51.4004 62.9004l19.7002 97.0996v32h32v-32h22.1006c5.7998 0 10.6992 -4.09961 11.7998 -9.7002zM160.3 57.9004c17.9004 0 32.4004 12.0996 32.4004 27c0 14.8994 -14.5 27 -32.4004 27c-17.8994 0 -32.3994 -12.1006 -32.3994 -27
c0 -14.9004 14.5 -27 32.3994 -27zM192.3 256v-32h-32v32h32z" />
<glyph glyph-name="file-audio" unicode="&#xf1c7;" horiz-adv-x="384"
d="M369.941 350.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM332.118 320
l-76.1182 76.1182v-76.1182h76.1182zM48 -16h288v288h-104c-13.2549 0 -24 10.7451 -24 24v104h-160v-416zM192 60.0244c0 -10.6914 -12.9258 -16.0459 -20.4854 -8.48535l-35.5146 35.9746h-28c-6.62695 0 -12 5.37305 -12 12v56c0 6.62695 5.37305 12 12 12h28
l35.5146 36.9473c7.56055 7.56055 20.4854 2.20605 20.4854 -8.48535v-135.951zM233.201 107.154c9.05078 9.29688 9.05957 24.1328 0.000976562 33.4385c-22.1494 22.752 12.2344 56.2461 34.3945 33.4814c27.1982 -27.9404 27.2119 -72.4443 0.000976562 -100.401
c-21.793 -22.3857 -56.9463 10.3154 -34.3965 33.4814z" />
<glyph glyph-name="file-video" unicode="&#xf1c8;" horiz-adv-x="384"
d="M369.941 350.059c8.68848 -8.68848 14.0586 -20.6943 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c13.2461 0 25.252 -5.37012 33.9404 -14.0586zM332.118 320
l-76.1182 76.1182v-76.1182h76.1182zM48 -16h288v288h-104c-13.2549 0 -24 10.7451 -24 24v104h-160v-416zM276.687 195.303c10.0049 10.0049 27.3135 2.99707 27.3135 -11.3135v-111.976c0 -14.2939 -17.2959 -21.332 -27.3135 -11.3135l-52.6865 52.6738v-37.374
c0 -11.0459 -8.9541 -20 -20 -20h-104c-11.0459 0 -20 8.9541 -20 20v104c0 11.0459 8.9541 20 20 20h104c11.0459 0 20 -8.9541 20 -20v-37.374z" />
<glyph glyph-name="file-code" unicode="&#xf1c9;" horiz-adv-x="384"
d="M149.9 98.9004c3.5 -3.30078 3.69922 -8.90039 0.399414 -12.4004l-17.3994 -18.5996c-1.60059 -1.80078 -4 -2.80078 -6.40039 -2.80078c-2.2002 0 -4.40039 0.900391 -6 2.40039l-57.7002 54.0996c-3.7002 3.40039 -3.7002 9.30078 0 12.8008l57.7002 54.0996
c3.40039 3.2998 9 3.2002 12.4004 -0.400391l17.3994 -18.5996l0.200195 -0.200195c3.2002 -3.59961 2.7998 -9.2002 -0.799805 -12.3994l-32.7998 -28.9004l32.7998 -28.9004zM369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288
c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416h288zM209.6 234l24.4004 -7
c4.7002 -1.2998 7.40039 -6.2002 6 -10.9004l-54.7002 -188.199c-1.2998 -4.60059 -6.2002 -7.40039 -10.8994 -6l-24.4004 7.09961c-4.7002 1.2998 -7.40039 6.2002 -6 10.9004l54.7002 188.1c1.39941 4.7002 6.2002 7.40039 10.8994 6zM234.1 157.1
c-3.5 3.30078 -3.69922 8.90039 -0.399414 12.4004l17.3994 18.5996c3.30078 3.60059 8.90039 3.7002 12.4004 0.400391l57.7002 -54.0996c3.7002 -3.40039 3.7002 -9.30078 0 -12.8008l-57.7002 -54.0996c-3.5 -3.2998 -9.09961 -3.09961 -12.4004 0.400391
l-17.3994 18.5996l-0.200195 0.200195c-3.2002 3.59961 -2.7998 9.2002 0.799805 12.3994l32.7998 28.9004l-32.7998 28.9004z" />
<glyph glyph-name="life-ring" unicode="&#xf1cd;"
d="M256 -56c-136.967 0 -248 111.033 -248 248s111.033 248 248 248s248 -111.033 248 -248s-111.033 -248 -248 -248zM152.602 20.7197c63.2178 -38.3184 143.579 -38.3184 206.797 0l-53.4111 53.4111c-31.8467 -13.5215 -68.168 -13.5059 -99.9746 0zM336 192
c0 44.1123 -35.8877 80 -80 80s-80 -35.8877 -80 -80s35.8877 -80 80 -80s80 35.8877 80 80zM427.28 88.6016c38.3184 63.2178 38.3184 143.579 0 206.797l-53.4111 -53.4111c13.5215 -31.8467 13.5049 -68.168 0 -99.9746zM359.397 363.28
c-63.2168 38.3184 -143.578 38.3184 -206.796 0l53.4111 -53.4111c31.8457 13.5215 68.167 13.5049 99.9736 0zM84.7197 295.398c-38.3184 -63.2178 -38.3184 -143.579 0 -206.797l53.4111 53.4111c-13.5215 31.8467 -13.5059 68.168 0 99.9746z" />
<glyph glyph-name="paper-plane" unicode="&#xf1d8;"
d="M440 441.5c34.5996 19.9004 77.5996 -8.7998 71.5 -48.9004l-59.4004 -387.199c-2.2998 -14.5 -11.0996 -27.3008 -23.8994 -34.5c-7.2998 -4.10059 -15.4004 -6.2002 -23.6006 -6.2002c-6.19922 0 -12.3994 1.2002 -18.2998 3.59961l-111.899 46.2002l-43.8008 -59.0996
c-27.3994 -36.9004 -86.5996 -17.8008 -86.5996 28.5996v84.4004l-114.3 47.2998c-36.7998 15.0996 -40.1006 66 -5.7002 85.8994zM192 -16l36.5996 49.5l-36.5996 15.0996v-64.5996zM404.6 12.7002l59.4004 387.3l-416 -240l107.8 -44.5996l211.5 184.3
c14.2002 12.2998 34.4004 -5.7002 23.7002 -21.2002l-140.2 -202.3z" />
<glyph glyph-name="futbol" unicode="&#xf1e3;" horiz-adv-x="496"
d="M483.8 268.6c42.2998 -130.199 -29 -270.1 -159.2 -312.399c-25.5 -8.2998 -51.2998 -12.2002 -76.6992 -12.2002c-104.5 0 -201.7 66.5996 -235.7 171.4c-42.2998 130.199 29 270.1 159.2 312.399c25.5 8.2998 51.2998 12.2002 76.6992 12.2002
c104.5 0 201.7 -66.5996 235.7 -171.4zM409.3 74.9004c6.10059 8.39941 12.1006 16.8994 16.7998 26.1992c14.3008 28.1006 21.5 58.5 21.7002 89.2002l-38.8994 36.4004l-71.1006 -22.1006l-24.3994 -75.1992l43.6992 -60.9004zM409.3 310.3
c-24.5 33.4004 -58.7002 58.4004 -97.8994 71.4004l-47.4004 -26.2002v-73.7998l64.2002 -46.5l70.7002 22zM184.9 381.6c-39.9004 -13.2998 -73.5 -38.5 -97.8008 -71.8994l10.1006 -52.5l70.5996 -22l64.2002 46.5v73.7998zM139 68.5l43.5 61.7002l-24.2998 74.2998
l-71.1006 22.2002l-39 -36.4004c0.5 -55.7002 23.4004 -95.2002 37.8008 -115.3zM187.2 1.5c64.0996 -20.4004 115.5 -1.7998 121.7 0l22.3994 48.0996l-44.2998 61.7002h-78.5996l-43.6006 -61.7002z" />
<glyph glyph-name="newspaper" unicode="&#xf1ea;" horiz-adv-x="576"
d="M552 384c13.2549 0 24 -10.7451 24 -24v-336c0 -13.2549 -10.7451 -24 -24 -24h-496c-30.9277 0 -56 25.0723 -56 56v272c0 13.2549 10.7451 24 24 24h42.752c6.60547 18.623 24.3896 32 45.248 32h440zM48 56c0 -4.41113 3.58887 -8 8 -8s8 3.58887 8 8v248h-16v-248z
M528 48v288h-416v-280c0 -2.7168 -0.204102 -5.38574 -0.578125 -8h416.578zM172 168c-6.62695 0 -12 5.37305 -12 12v96c0 6.62695 5.37305 12 12 12h136c6.62695 0 12 -5.37305 12 -12v-96c0 -6.62695 -5.37305 -12 -12 -12h-136zM200 248v-40h80v40h-80zM160 108v24
c0 6.62695 5.37305 12 12 12h136c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-136c-6.62695 0 -12 5.37305 -12 12zM352 108v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-104
c-6.62695 0 -12 5.37305 -12 12zM352 252v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-104c-6.62695 0 -12 5.37305 -12 12zM352 180v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24
c0 -6.62695 -5.37305 -12 -12 -12h-104c-6.62695 0 -12 5.37305 -12 12z" />
<glyph glyph-name="bell-slash" unicode="&#xf1f6;" horiz-adv-x="640"
d="M633.99 -23.0195c6.91016 -5.52051 8.01953 -15.5908 2.5 -22.4902l-10 -12.4902c-5.53027 -6.88965 -15.5898 -8.00977 -22.4902 -2.49023l-598 467.51c-6.90039 5.52051 -8.01953 15.5908 -2.49023 22.4902l10 12.4902
c5.52051 6.90039 15.5898 8.00977 22.4902 2.49023zM163.53 80h182.84l61.3994 -48h-279.659c-19.1201 0 -31.9902 15.5996 -32.1006 32c-0.0498047 7.5498 2.61035 15.2598 8.61035 21.71c18.3701 19.7402 51.5703 49.6904 54.8398 140.42l45.4697 -35.5498
c-6.91992 -54.7803 -24.6895 -88.5498 -41.3994 -110.58zM320 352c-23.3496 0 -45 -7.17969 -62.9404 -19.4004l-38.1699 29.8408c19.6807 15.7793 43.1104 27.3096 69.1299 32.7197v20.8398c0 17.6699 14.3203 32 31.9805 32s31.9805 -14.3301 31.9805 -32v-20.8398
c73.46 -15.2598 127.939 -77.46 127.939 -155.16c0 -41.3604 6.03027 -70.7197 14.3398 -92.8496l-59.5293 46.54c-1.63086 13.96 -2.77051 28.8896 -2.79004 45.7295c0 0.200195 0.0595703 0.379883 0.0595703 0.580078c0 61.8604 -50.1396 112 -112 112zM320 -64
c-35.3203 0 -63.9697 28.6504 -63.9697 64h127.939c0 -35.3496 -28.6494 -64 -63.9697 -64z" />
<glyph glyph-name="copyright" unicode="&#xf1f9;"
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 -8c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200c-110.549 0 -200 -89.4688 -200 -200c0 -110.549 89.4678 -200 200 -200z
M363.351 93.0645c-9.61328 -9.71289 -45.5293 -41.3965 -104.064 -41.3965c-82.4297 0 -140.484 61.4248 -140.484 141.567c0 79.1514 60.2754 139.4 139.763 139.4c55.5303 0 88.7373 -26.6201 97.5928 -34.7783c2.37793 -2.1875 3.86914 -5.3252 3.86914 -8.80762
c0 -2.39746 -0.717773 -4.64258 -1.93359 -6.51465l-18.1543 -28.1133c-3.8418 -5.9502 -11.9668 -7.28223 -17.499 -2.9209c-8.5957 6.77637 -31.8145 22.5381 -61.708 22.5381c-48.3037 0 -77.916 -35.3301 -77.916 -80.082c0 -41.5889 26.8877 -83.6924 78.2764 -83.6924
c32.6572 0 56.8428 19.0391 65.7266 27.2256c5.26953 4.85645 13.5957 4.03906 17.8193 -1.73828l19.8652 -27.1699c1.45996 -1.98145 2.32422 -4.42969 2.32422 -7.07715c0 -3.28809 -1.32422 -6.2793 -3.47656 -8.44043z" />
<glyph glyph-name="closed-captioning" unicode="&#xf20a;"
d="M464 384c26.5 0 48 -21.5 48 -48v-288c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v288c0 26.5 21.5 48 48 48h416zM458 48c3.2998 0 6 2.7002 6 6v276c0 3.2998 -2.7002 6 -6 6h-404c-3.2998 0 -6 -2.7002 -6 -6v-276c0 -3.2998 2.7002 -6 6 -6h404z
M246.9 133.7c1.69922 -2.40039 1.5 -5.60059 -0.5 -7.7002c-53.6006 -56.7998 -172.801 -32.0996 -172.801 67.9004c0 97.2998 121.7 119.5 172.5 70.0996c2.10059 -2 2.5 -3.2002 1 -5.7002l-17.5 -30.5c-1.89941 -3.09961 -6.19922 -4 -9.09961 -1.7002
c-40.7998 32 -94.5996 14.9004 -94.5996 -31.1992c0 -48 51 -70.5 92.1992 -32.6006c2.80078 2.5 7.10059 2.10059 9.2002 -0.899414zM437.3 133.7c1.7002 -2.40039 1.5 -5.60059 -0.5 -7.7002c-53.5996 -56.9004 -172.8 -32.0996 -172.8 67.9004
c0 97.2998 121.7 119.5 172.5 70.0996c2.09961 -2 2.5 -3.2002 1 -5.7002l-17.5 -30.5c-1.90039 -3.09961 -6.2002 -4 -9.09961 -1.7002c-40.8008 32 -94.6006 14.9004 -94.6006 -31.1992c0 -48 51 -70.5 92.2002 -32.6006c2.7998 2.5 7.09961 2.10059 9.2002 -0.899414z
" />
<glyph glyph-name="object-group" unicode="&#xf247;"
d="M500 320h-12v-256h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-320v-12c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v256h-12
c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-12h320v12c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12zM448 384v-32h32v32h-32zM32 384v-32h32v32h-32zM64 0v32
h-32v-32h32zM480 0v32h-32v-32h32zM440 64v256h-12c-6.62695 0 -12 5.37305 -12 12v12h-320v-12c0 -6.62695 -5.37305 -12 -12 -12h-12v-256h12c6.62695 0 12 -5.37305 12 -12v-12h320v12c0 6.62695 5.37305 12 12 12h12zM404 256c6.62695 0 12 -5.37207 12 -12v-168
c0 -6.62793 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37207 -12 12v52h-84c-6.62695 0 -12 5.37207 -12 12v168c0 6.62793 5.37305 12 12 12h200c6.62695 0 12 -5.37207 12 -12v-52h84zM136 280v-112h144v112h-144zM376 104v112h-56v-76
c0 -6.62793 -5.37305 -12 -12 -12h-76v-24h144z" />
<glyph glyph-name="object-ungroup" unicode="&#xf248;" horiz-adv-x="576"
d="M564 224h-12v-160h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-224v-12c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v24h-88v-12
c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v160h-12c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-12h224v12c0 6.62695 5.37305 12 12 12h72
c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-12v-24h88v12c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12zM352 384v-32h32v32h-32zM352 128v-32h32v32h-32zM64 96v32h-32v-32h32zM64 352v32
h-32v-32h32zM96 136h224v12c0 6.62695 5.37305 12 12 12h12v160h-12c-6.62695 0 -12 5.37305 -12 12v12h-224v-12c0 -6.62695 -5.37305 -12 -12 -12h-12v-160h12c6.62695 0 12 -5.37305 12 -12v-12zM224 0v32h-32v-32h32zM504 64v160h-12c-6.62695 0 -12 5.37305 -12 12v12
h-88v-88h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-88v-24h12c6.62695 0 12 -5.37305 12 -12v-12h224v12c0 6.62695 5.37305 12 12 12h12zM544 0v32h-32v-32h32zM544 256v32h-32v-32h32z" />
<glyph glyph-name="sticky-note" unicode="&#xf249;" horiz-adv-x="448"
d="M448 99.8936c0 -13.2451 -5.37012 -25.252 -14.0586 -33.9404l-83.8828 -83.8818c-8.68848 -8.68848 -20.6943 -14.0596 -33.9404 -14.0596h-268.118c-26.5098 0 -48 21.4902 -48 48v351.988c0 26.5098 21.4902 48 48 48h352c26.5098 0 48 -21.4902 48 -48v-268.106z
M320 19.8936l76.1182 76.1182h-76.1182v-76.1182zM400 368h-352v-351.988h224v104c0 13.2549 10.7451 24 24 24h104v223.988z" />
<glyph glyph-name="clone" unicode="&#xf24d;"
d="M464 448c26.5098 0 48 -21.4902 48 -48v-320c0 -26.5098 -21.4902 -48 -48 -48h-48v-48c0 -26.5098 -21.4902 -48 -48 -48h-320c-26.5098 0 -48 21.4902 -48 48v320c0 26.5098 21.4902 48 48 48h48v48c0 26.5098 21.4902 48 48 48h320zM362 -16c3.31152 0 6 2.68848 6 6
v42h-224c-26.5098 0 -48 21.4902 -48 48v224h-42c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h308zM458 80c3.31152 0 6 2.68848 6 6v308c0 3.31152 -2.68848 6 -6 6h-308c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h308z" />
<glyph glyph-name="hourglass" unicode="&#xf254;" horiz-adv-x="384"
d="M368 400c0 -80.0996 -31.8984 -165.619 -97.1797 -208c64.9912 -42.1934 97.1797 -127.436 97.1797 -208h4c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-360c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h4
c0 80.0996 31.8994 165.619 97.1797 208c-64.9912 42.1934 -97.1797 127.436 -97.1797 208h-4c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h360c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-4zM64 400
c0 -101.621 57.3066 -184 128 -184s128 82.3799 128 184h-256zM320 -16c0 101.62 -57.3076 184 -128 184s-128 -82.3799 -128 -184h256z" />
<glyph glyph-name="hand-rock" unicode="&#xf255;"
d="M408.864 368.948c48.8213 20.751 103.136 -15.0723 103.136 -67.9111v-114.443c0 -15.3955 -3.08887 -30.3906 -9.18262 -44.5674l-42.835 -99.6562c-4.99707 -11.625 -3.98242 -18.8574 -3.98242 -42.3701c0 -17.6729 -14.3271 -32 -32 -32h-252
c-17.6729 0 -32 14.3271 -32 32c0 27.3301 1.1416 29.2012 -3.11035 32.9033l-97.71 85.0811c-24.8994 21.6797 -39.1797 52.8926 -39.1797 85.6338v56.9531c0 47.4277 44.8457 82.0215 91.0459 71.1807c1.96094 55.751 63.5107 87.8262 110.671 60.8057
c29.1895 31.0713 78.8604 31.4473 108.334 -0.0214844c32.7051 18.6846 76.4121 10.3096 98.8135 -23.5879zM464 186.594v114.445c0 34.29 -52 33.8232 -52 0.676758c0 -8.83594 -7.16309 -16 -16 -16h-7c-8.83691 0 -16 7.16406 -16 16v26.751
c0 34.457 -52 33.707 -52 0.676758v-27.4287c0 -8.83594 -7.16309 -16 -16 -16h-7c-8.83691 0 -16 7.16406 -16 16v40.4658c0 34.3525 -52 33.8115 -52 0.677734v-41.1436c0 -8.83594 -7.16406 -16 -16 -16h-7c-8.83594 0 -16 7.16406 -16 16v26.751
c0 34.4023 -52 33.7744 -52 0.676758v-116.571c0 -8.83105 -7.17773 -15.9961 -16.0078 -15.9961c-4.0166 0 -7.68848 1.48242 -10.499 3.92969l-7 6.09473c-3.37012 2.93457 -5.49316 7.25293 -5.49316 12.0674v41.2275c0 34.2148 -52 33.8857 -52 0.677734v-56.9531
c0 -18.8555 8.27441 -36.874 22.7002 -49.4365l97.71 -85.0801c12.4502 -10.8398 19.5898 -26.4463 19.5898 -42.8164v-10.2861h220v7.07617c0 13.21 2.65332 26.0791 7.88281 38.25l42.835 99.6553c3.37891 7.82715 5.28223 16.501 5.28223 25.5625v0.0498047z" />
<glyph glyph-name="hand-paper" unicode="&#xf256;" horiz-adv-x="448"
d="M372.57 335.359c39.9062 5.63281 75.4297 -25.7393 75.4297 -66.3594v-131.564c-0.00292969 -15.7393 -1.80566 -30.9482 -5.19531 -45.666l-30.1836 -130.958c-3.34668 -14.5234 -16.2783 -24.8125 -31.1816 -24.8125h-222.897
c-10.7539 0 -20.2588 5.28613 -26.0615 13.4316l-119.97 168.415c-21.2441 29.8203 -14.8047 71.3574 14.5498 93.1533c18.7754 13.9395 42.1309 16.2979 62.083 8.87109v126.13c0 44.0547 41.125 75.5439 82.4053 64.9834c23.8926 48.1963 92.3535 50.2471 117.982 0.74707
c42.5186 11.1445 83.0391 -21.9346 83.0391 -65.5469v-10.8242zM399.997 137.437l-0.00195312 131.563c0 24.9492 -36.5703 25.5508 -36.5703 -0.691406v-76.3086c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v154.184
c0 25.501 -36.5703 26.3633 -36.5703 0.691406v-154.875c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v188.309c0 25.501 -36.5703 26.3545 -36.5703 0.691406v-189c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16
v153.309c0 25.501 -36.5713 26.3359 -36.5713 0.691406v-206.494c0 -15.5703 -20.0352 -21.9092 -29.0303 -9.2832l-27.1279 38.0791c-14.3711 20.1709 -43.833 -2.33496 -29.3945 -22.6045l115.196 -161.697h201.92l27.3252 118.551
c2.63086 11.417 3.96484 23.1553 3.96484 34.8857z" />
<glyph glyph-name="hand-scissors" unicode="&#xf257;"
d="M256 -32c-44.9561 0 -77.3428 43.2627 -64.0244 85.8535c-21.6484 13.71 -34.0156 38.7617 -30.3408 65.0068h-87.6348c-40.8037 0 -74 32.8105 -74 73.1406c0 40.3291 33.1963 73.1396 74 73.1396l94 -9.14062l-78.8496 18.6787
c-38.3076 14.7422 -57.04 57.4707 -41.9424 95.1123c15.0303 37.4736 57.7549 55.7803 95.6416 41.2012l144.929 -55.7568c24.9551 30.5566 57.8086 43.9932 92.2178 24.7324l97.999 -54.8525c20.9746 -11.7393 34.0049 -33.8457 34.0049 -57.6904v-205.702
c0 -30.7422 -21.4404 -57.5576 -51.7979 -64.5537l-118.999 -27.4268c-4.97168 -1.14648 -10.0889 -1.72949 -15.2031 -1.72949zM256 16.0127l70 -0.000976562c1.52441 0 2.99707 0.174805 4.42285 0.501953l119.001 27.4277
c8.58203 1.97754 14.5762 9.29102 14.5762 17.7812v205.701c0 6.4873 -3.62109 12.542 -9.44922 15.8047l-98 54.8545c-8.13965 4.55566 -18.668 2.61914 -24.4873 -4.50781l-21.7646 -26.6475c-2.93457 -3.59375 -7.40332 -5.87305 -12.4004 -5.87305
c-2.02246 0 -3.95703 0.375977 -5.73828 1.06152l-166.549 64.0908c-32.6543 12.5664 -50.7744 -34.5771 -19.2227 -46.7168l155.357 -59.7852c6 -2.30859 10.2539 -8.12402 10.2539 -14.9326v-11.6328c0 -8.83691 -7.16309 -16 -16 -16h-182
c-34.375 0 -34.4297 -50.2803 0 -50.2803h182c8.83691 0 16 -7.16309 16 -16v-6.85645c0 -8.83691 -7.16309 -16 -16 -16h-28c-25.1221 0 -25.1592 -36.5674 0 -36.5674h28c8.83691 0 16 -7.16211 16 -16v-6.85547c0 -8.83691 -7.16309 -16 -16 -16
c-25.1201 0 -25.1602 -36.5674 0 -36.5674z" />
<glyph glyph-name="hand-lizard" unicode="&#xf258;" horiz-adv-x="576"
d="M556.686 157.458c12.6357 -19.4863 19.3145 -42.0615 19.3145 -65.2871v-124.171h-224v71.582l-99.751 38.7871c-2.7832 1.08203 -5.70996 1.63086 -8.69727 1.63086h-131.552c-30.8789 0 -56 25.1211 -56 56c0 48.5234 39.4766 88 88 88h113.709l18.333 48h-196.042
c-44.1123 0 -80 35.8877 -80 80v8c0 30.8779 25.1211 56 56 56h293.917c24.5 0 47.084 -12.2725 60.4111 -32.8291zM528 16v76.1709c0 0.0166016 -0.0439453 0.106445 -0.0439453 0.12207c0 14.3945 -4.24219 27.8057 -11.5439 39.0498l-146.358 225.715
c-4.44336 6.85254 -11.9707 10.9424 -20.1367 10.9424h-293.917c-4.41113 0 -8 -3.58887 -8 -8v-8c0 -17.6445 14.3555 -32 32 -32h213.471c25.2021 0 42.626 -25.293 33.6299 -48.8457l-24.5518 -64.2812c-7.05371 -18.4658 -25.0732 -30.873 -44.8398 -30.873h-113.709
c-22.0557 0 -40 -17.9443 -40 -40c0 -4.41113 3.58887 -8 8 -8h131.552c0.0175781 0 0.0712891 -0.0273438 0.0888672 -0.0273438c9.16992 0 17.9404 -1.72461 26.0039 -4.86621l99.752 -38.7881c18.5898 -7.22852 30.6035 -24.7881 30.6035 -44.7363v-23.582h128z" />
<glyph glyph-name="hand-spock" unicode="&#xf259;"
d="M501.03 331.824c6.92773 -11.1826 10.9697 -24.4053 10.9697 -38.5146c0 -5.92676 -0.706055 -11.6885 -2.03809 -17.208l-57.623 -241.963c-13.2236 -56.1904 -63.707 -98.1387 -123.908 -98.1387h-0.352539h-107.455
c-0.0761719 0 -0.193359 0.00195312 -0.270508 0.00195312c-40.9248 0 -78.1475 15.9814 -105.761 42.0391l-91.3652 85.9766c-14.3076 13.4434 -23.2246 32.5547 -23.2246 53.7168c0 19.5254 7.61035 37.2861 20.0254 50.4766
c5.31836 5.66406 29.875 29.3926 68.1152 21.8477l-24.3594 82.1973c-1.97363 6.64844 -2.97656 13.6836 -2.97656 20.9688c0 38.6953 29.8926 70.4639 67.8262 73.4531c-0.246094 2.45117 -0.34082 4.85547 -0.34082 7.37207c0 34.4199 23.585 63.376 55.4619 71.5752
c43.248 10.9785 80.5645 -17.7012 89.6602 -53.0723l13.6836 -53.207l4.64648 22.6602c6.99023 33.5186 36.6826 58.8037 72.2373 58.916c8.73438 0 56.625 -3.26953 70.7383 -54.0801c15.0664 0.710938 46.9199 -3.50977 66.3105 -35.0176zM463.271 287.219
c7.86914 32.9844 -42.1211 45.2695 -50.0859 11.9219l-24.8008 -104.146c-4.38867 -18.4141 -31.7783 -11.8926 -28.0557 6.2168l28.5479 139.166c7.39844 36.0703 -43.3076 45.0703 -50.1182 11.9629l-31.791 -154.971
c-3.54883 -17.3086 -28.2832 -18.0469 -32.7109 -0.804688l-47.3262 184.035c-8.43359 32.8105 -58.3691 20.2676 -49.8652 -12.8359l42.4414 -165.039c4.81641 -18.7207 -23.3711 -26.9121 -28.9648 -8.00781l-31.3438 105.779
c-9.6875 32.6465 -59.1191 18.2578 -49.3867 -14.625l36.0137 -121.539c6.59375 -22.2441 10.1777 -45.7803 10.1777 -70.1523c0 -6.54297 -8.05664 -10.9355 -13.4824 -5.82617l-51.123 48.1074c-24.7852 23.4082 -60.0527 -14.1875 -35.2793 -37.4902l91.3691 -85.9805
c19.0469 -17.9736 44.75 -28.998 72.9795 -28.998h0.157227h107.455c0.0732422 0 0.138672 0.0429688 0.212891 0.0429688c37.5791 0 69.1016 26.1416 77.3564 61.2168z" />
<glyph glyph-name="hand-pointer" unicode="&#xf25a;" horiz-adv-x="448"
d="M358.182 268.639c43.1934 16.6348 89.8184 -15.7949 89.8184 -62.6387v-84c-0.000976562 -5.24023 -0.600586 -10.3037 -1.72754 -15.2041l-27.4297 -118.999c-6.98242 -30.2969 -33.7549 -51.7969 -64.5566 -51.7969h-178.286
c-21.2588 0 -41.3682 10.4102 -53.791 27.8457l-109.699 154.001c-21.2432 29.8193 -14.8047 71.3574 14.5498 93.1523c18.8115 13.9658 42.1748 16.2822 62.083 8.87207v161.129c0 36.9443 29.7363 67 66.2861 67s66.2861 -30.0557 66.2861 -67v-73.6338
c20.4131 2.85742 41.4678 -3.94238 56.5947 -19.6289c27.1934 12.8467 60.3799 5.66992 79.8721 -19.0986zM80.9854 168.303c-14.4004 20.2119 -43.8008 -2.38281 -29.3945 -22.6055l109.712 -154c3.43457 -4.81934 8.92871 -7.69727 14.6973 -7.69727h178.285
c8.49219 0 15.8037 5.99414 17.7822 14.5762l27.4297 119.001c0.333008 1.44629 0.501953 2.93457 0.501953 4.42285v84c0 25.1602 -36.5713 25.1211 -36.5713 0c0 -8.83594 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16406 -16 16v21
c0 25.1602 -36.5713 25.1201 -36.5713 0v-21c0 -8.83594 -7.16309 -16 -16 -16h-6.85938c-8.83691 0 -16 7.16406 -16 16v35c0 25.1602 -36.5703 25.1201 -36.5703 0v-35c0 -8.83594 -7.16309 -16 -16 -16h-6.85742c-8.83691 0 -16 7.16406 -16 16v175
c0 25.1602 -36.5713 25.1201 -36.5713 0v-241.493c0 -15.5703 -20.0352 -21.9092 -29.0303 -9.2832zM176.143 48v96c0 8.83691 6.26855 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16zM251.571 48v96
c0 8.83691 6.26758 16 14 16h6c7.73145 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26855 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16zM327 48v96c0 8.83691 6.26758 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6
c-7.73242 0 -14 7.16309 -14 16z" />
<glyph glyph-name="hand-peace" unicode="&#xf25b;" horiz-adv-x="448"
d="M362.146 256.024c42.5908 13.3184 85.8535 -19.0684 85.8535 -64.0244l-0.0117188 -70.001c-0.000976562 -5.24023 -0.600586 -10.3027 -1.72949 -15.2031l-27.4268 -118.999c-6.99707 -30.3564 -33.8105 -51.7969 -64.5547 -51.7969h-205.702
c-23.8447 0 -45.9502 13.0303 -57.6904 34.0059l-54.8525 97.999c-19.2607 34.4092 -5.82422 67.2617 24.7324 92.2178l-55.7568 144.928c-14.5791 37.8867 3.72754 80.6113 41.2012 95.6416c37.6406 15.0977 80.3691 -3.63477 95.1123 -41.9424l18.6787 -78.8496
l-9.14062 94c0 40.8037 32.8096 74 73.1396 74s73.1406 -33.1963 73.1406 -74v-87.6348c26.2451 3.6748 51.2959 -8.69238 65.0068 -30.3408zM399.987 122l-0.000976562 70c0 25.1602 -36.5674 25.1201 -36.5674 0c0 -8.83691 -7.16309 -16 -16 -16h-6.85547
c-8.83789 0 -16 7.16309 -16 16v28c0 25.1592 -36.5674 25.1221 -36.5674 0v-28c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v182c0 34.4297 -50.2803 34.375 -50.2803 0v-182c0 -8.83691 -7.16309 -16 -16 -16h-11.6328
c-6.80859 0 -12.624 4.25391 -14.9326 10.2539l-59.7842 155.357c-12.1396 31.5518 -59.2842 13.4326 -46.7168 -19.2227l64.0898 -166.549c0.685547 -1.78125 1.07812 -3.71875 1.07812 -5.74121c0 -4.99707 -2.2959 -9.46289 -5.88965 -12.3975l-26.6475 -21.7646
c-7.12695 -5.81934 -9.06445 -16.3467 -4.50781 -24.4873l54.8535 -98c3.26367 -5.82812 9.31934 -9.44922 15.8057 -9.44922h205.701c8.49121 0 15.8037 5.99414 17.7812 14.5762l27.4277 119.001c0.333008 1.44629 0.501953 2.93457 0.501953 4.42285z" />
<glyph glyph-name="registered" unicode="&#xf25d;"
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 -8c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200c-110.549 0 -200 -89.4688 -200 -200c0 -110.549 89.4678 -200 200 -200z
M366.442 73.791c4.40332 -7.99219 -1.37012 -17.791 -10.5107 -17.791h-42.8096c-0.00488281 0 -0.000976562 -0.0126953 -0.00585938 -0.0126953c-4.58594 0 -8.57422 2.58301 -10.5869 6.37305l-47.5156 89.3027h-31.958v-83.6631c0 -6.61719 -5.38281 -12 -12 -12
h-38.5674c-6.61719 0 -12 5.38281 -12 12v248.304c0 6.61719 5.38281 12 12 12h78.667c71.251 0 101.498 -32.749 101.498 -85.252c0 -31.6123 -15.2148 -59.2969 -39.4824 -73.1758c3.02148 -4.61719 0.225586 0.199219 53.2715 -96.085zM256.933 208.094
c20.9131 0 32.4307 11.5186 32.4316 32.4316c0 19.5752 -6.5127 31.709 -38.9297 31.709h-27.377v-64.1406h33.875z" />
<glyph glyph-name="calendar-plus" unicode="&#xf271;" horiz-adv-x="448"
d="M336 156v-24c0 -6.59961 -5.40039 -12 -12 -12h-76v-76c0 -6.59961 -5.40039 -12 -12 -12h-24c-6.59961 0 -12 5.40039 -12 12v76h-76c-6.59961 0 -12 5.40039 -12 12v24c0 6.59961 5.40039 12 12 12h76v76c0 6.59961 5.40039 12 12 12h24c6.59961 0 12 -5.40039 12 -12
v-76h76c6.59961 0 12 -5.40039 12 -12zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40
c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="calendar-minus" unicode="&#xf272;" horiz-adv-x="448"
d="M124 120c-6.59961 0 -12 5.40039 -12 12v24c0 6.59961 5.40039 12 12 12h200c6.59961 0 12 -5.40039 12 -12v-24c0 -6.59961 -5.40039 -12 -12 -12h-200zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="calendar-times" unicode="&#xf273;" horiz-adv-x="448"
d="M311.7 73.2998l-17 -17c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-53.7002 53.7998l-53.7002 -53.6992c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-17 17c-4.7002 4.69922 -4.7002 12.2998 0 17l53.7002 53.6992l-53.7002 53.7002c-4.7002 4.7002 -4.7002 12.2998 0 17
l17 17c4.7002 4.7002 12.2998 4.7002 17 0l53.7002 -53.7002l53.7002 53.7002c4.7002 4.7002 12.2998 4.7002 17 0l17 -17c4.7002 -4.7002 4.7002 -12.2998 0 -17l-53.7998 -53.7998l53.6992 -53.7002c4.80078 -4.7002 4.80078 -12.2998 0.100586 -17zM448 336v-352
c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10
v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="calendar-check" unicode="&#xf274;" horiz-adv-x="448"
d="M400 384c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h48v52c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-52h128v52c0 6.62695 5.37305 12 12 12h40
c6.62695 0 12 -5.37305 12 -12v-52h48zM394 -16c3.31152 0 6 2.68848 6 6v298h-352v-298c0 -3.31152 2.68848 -6 6 -6h340zM341.151 184.65l-142.31 -141.169c-4.70508 -4.66699 -12.3027 -4.6377 -16.9707 0.0673828l-75.0908 75.6992
c-4.66699 4.70508 -4.6377 12.3027 0.0673828 16.9707l22.7197 22.5361c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0693359l44.1035 -44.4609l111.072 110.182c4.70508 4.66699 12.3027 4.63672 16.9707 -0.0683594l22.5361 -22.7178
c4.66699 -4.70508 4.63672 -12.3027 -0.0683594 -16.9697z" />
<glyph glyph-name="map" unicode="&#xf279;" horiz-adv-x="576"
d="M560.02 416c8.4502 0 15.9805 -6.83008 15.9805 -16.0195v-346.32c0 -13.4707 -8.32422 -24.9951 -20.1201 -29.71l-151.83 -52.8105c-6.23242 -2.02832 -12.9023 -3.12305 -19.8076 -3.12305c-7.07324 0 -13.8799 1.15039 -20.2422 3.27344l-172 60.71l-170.05 -62.8398
c-1.99023 -0.790039 -4 -1.16016 -5.95996 -1.16016c-8.45996 0 -15.9902 6.83008 -15.9902 16.0195v346.32c0.00292969 13.4697 8.32617 24.9932 20.1201 29.71l151.83 52.8105c6.43945 2.08984 13.1201 3.13965 19.8096 3.13965
c7.06641 -0.00292969 13.8789 -1.16602 20.2402 -3.28027l172 -60.7197h0.00976562l170.05 62.8398c1.98047 0.790039 4 1.16016 5.95996 1.16016zM224 357.58v-285.97l128 -45.1904v285.97zM48 29.9502l127.36 47.0801l0.639648 0.229492v286.2l-128 -44.5303v-288.979z
M528 65.0801v288.97l-127.36 -47.0693l-0.639648 -0.240234v-286.19z" />
<glyph glyph-name="comment-alt" unicode="&#xf27a;"
d="M448 448c35.2998 0 64 -28.7002 64 -64v-288c0 -35.2998 -28.7002 -64 -64 -64h-144l-124.9 -93.5996c-2.19922 -1.7002 -4.69922 -2.40039 -7.09961 -2.40039c-6.2002 0 -12 4.90039 -12 12v84h-96c-35.2998 0 -64 28.7002 -64 64v288c0 35.2998 28.7002 64 64 64h384z
M464 96v288c0 8.7998 -7.2002 16 -16 16h-384c-8.7998 0 -16 -7.2002 -16 -16v-288c0 -8.7998 7.2002 -16 16 -16h144v-60l67.2002 50.4004l12.7998 9.59961h160c8.7998 0 16 7.2002 16 16z" />
<glyph glyph-name="pause-circle" unicode="&#xf28b;"
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM352 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-48
c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h48c8.7998 0 16 -7.2002 16 -16zM240 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-48c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h48c8.7998 0 16 -7.2002 16 -16z" />
<glyph glyph-name="stop-circle" unicode="&#xf28d;"
d="M504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200zM352 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-160
c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h160c8.7998 0 16 -7.2002 16 -16z" />
<glyph glyph-name="handshake" unicode="&#xf2b5;" horiz-adv-x="640"
d="M519.2 320.1h120.8v-255.699h-64c-17.5 0 -31.7998 14.1992 -31.9004 31.6992h-57.8994c-1.7998 -8.19922 -5.2998 -16.0996 -10.9004 -23l-26.2002 -32.2998c-15.7998 -19.3994 -41.8994 -25.5 -64 -16.7998c-13.5 -16.5996 -30.5996 -24 -48.7998 -24
c-15.0996 0 -28.5996 5.09961 -41.0996 15.9004c-31.7998 -21.9004 -74.7002 -21.3008 -105.601 3.7998l-84.5996 76.3994h-9.09961c-0.100586 -17.5 -14.3008 -31.6992 -31.9004 -31.6992h-64v255.699h118l47.5996 47.6006c10.5 10.3994 24.8008 16.2998 39.6006 16.2998
h226.8c15.4326 0 29.4326 -6.22168 39.5996 -16.2998zM48 96.4004c8.7998 0 16 7.09961 16 16c0 8.7998 -7.2002 16 -16 16s-16 -7.2002 -16 -16c0 -8.80078 7.2002 -16 16 -16zM438 103.3c2.7002 3.40039 2.2002 8.5 -1.2002 11.2998l-108.2 87.8008l-8.19922 -7.5
c-40.3008 -36.8008 -86.7002 -11.8008 -101.5 4.39941c-26.7002 29 -25 74.4004 4.39941 101.3l38.7002 35.5h-56.7002c-2 -0.799805 -3.7002 -1.5 -5.7002 -2.2998l-61.6992 -61.5996h-41.9004v-128.101h27.7002l97.2998 -88
c16.0996 -13.0996 41.4004 -10.5 55.2998 6.60059l15.6006 19.2002l36.7998 -31.5c3 -2.40039 12 -4.90039 18 2.39941l30 36.5l23.8994 -19.3994c3.5 -2.80078 8.5 -2.2002 11.3008 1.19922zM544 144.1v128h-44.7002l-61.7002 61.6006
c-1.39941 1.5 -3.39941 2.2998 -5.5 2.2998l-83.6992 -0.200195c-10 0 -19.6006 -3.7002 -27 -10.5l-65.6006 -60.0996c-9.7002 -8.7998 -10.5 -24 -1.2002 -33.9004c8.90039 -9.39941 25.1006 -8.7002 34.6006 0l55.2002 50.6006c6.5 5.89941 16.5996 5.5 22.5996 -1
l10.9004 -11.7002c6 -6.5 5.5 -16.6006 -1 -22.6006l-12.5 -11.3994l102.699 -83.4004c2.80078 -2.2998 5.40039 -4.89941 7.7002 -7.7002h69.2002zM592 96.4004c8.7998 0 16 7.09961 16 16c0 8.7998 -7.2002 16 -16 16s-16 -7.2002 -16 -16c0 -8.80078 7.2002 -16 16 -16z
" />
<glyph glyph-name="envelope-open" unicode="&#xf2b6;"
d="M494.586 283.484c10.6523 -8.80762 17.4141 -22.1064 17.4141 -36.9932v-262.491c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v262.515c0 14.9355 6.80469 28.2705 17.5146 37.0771c4.08008 3.35449 110.688 89.0996 135.15 108.549
c22.6992 18.1426 60.1299 55.8594 103.335 55.8594c43.4365 0 81.2314 -38.1914 103.335 -55.8594c23.5283 -18.707 130.554 -104.773 135.251 -108.656zM464 -10v253.632c0 0.00195312 0.00390625 0.000976562 0.00390625 0.00292969
c0 1.88184 -0.869141 3.56152 -2.22754 4.66016c-15.8633 12.8232 -108.793 87.5752 -132.366 106.316c-17.5527 14.0195 -49.7168 45.3887 -73.4102 45.3887c-23.6016 0 -55.2451 -30.8799 -73.4102 -45.3887c-23.5713 -18.7393 -116.494 -93.4795 -132.364 -106.293
c-1.40918 -1.13965 -2.22559 -2.85254 -2.22559 -4.66504v-253.653c0 -3.31152 2.68848 -6 6 -6h404c3.31152 0 6 2.68848 6 6zM432.009 177.704c4.24902 -5.15918 3.46484 -12.7949 -1.74512 -16.9814c-28.9746 -23.2822 -59.2734 -47.5967 -70.9287 -56.8623
c-22.6992 -18.1436 -60.1299 -55.8604 -103.335 -55.8604c-43.4521 0 -81.2871 38.2373 -103.335 55.8604c-11.2793 8.9668 -41.7441 33.4131 -70.9268 56.8643c-5.20996 4.1875 -5.99316 11.8223 -1.74512 16.9814l15.2578 18.5283
c4.17773 5.07227 11.6572 5.84277 16.7793 1.72559c28.6182 -23.001 58.5654 -47.0352 70.5596 -56.5713c17.5527 -14.0195 49.7168 -45.3887 73.4102 -45.3887c23.6016 0 55.2461 30.8799 73.4102 45.3887c11.9941 9.53516 41.9434 33.5703 70.5625 56.5684
c5.12207 4.11621 12.6016 3.3457 16.7783 -1.72656z" />
<glyph glyph-name="address-book" unicode="&#xf2b9;" horiz-adv-x="448"
d="M436 288h-20v-64h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-20v-64h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-20v-48c0 -26.5 -21.5 -48 -48 -48h-320c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48
h320c26.5 0 48 -21.5 48 -48v-48h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12zM368 -16v416h-320v-416h320zM208 192c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64zM118.4 64
c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002c0 -10.6006 -10 -19.2002 -22.4004 -19.2002
h-179.199z" />
<glyph glyph-name="address-card" unicode="&#xf2bb;" horiz-adv-x="576"
d="M528 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-480c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h480zM528 16v352h-480v-352h480zM208 192c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64z
M118.4 64c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002
c0 -10.6006 -10 -19.2002 -22.4004 -19.2002h-179.199zM360 128c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 192c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112
c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 256c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112z" />
<glyph glyph-name="user-circle" unicode="&#xf2bd;" horiz-adv-x="496"
d="M248 344c53 0 96 -43 96 -96s-43 -96 -96 -96s-96 43 -96 96s43 96 96 96zM248 200c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8
c49.7002 0 95.0996 18.2998 130.1 48.4004c-14.8994 23 -40.3994 38.5 -69.5996 39.5c-20.7998 -6.5 -40.5996 -9.60059 -60.5 -9.60059s-39.7002 3.2002 -60.5 9.60059c-29.2002 -0.900391 -54.7002 -16.5 -69.5996 -39.5c35 -30.1006 80.3994 -48.4004 130.1 -48.4004z
M410.7 76.0996c23.3994 32.7002 37.2998 72.7002 37.2998 115.9c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -43.2002 13.9004 -83.2002 37.2998 -115.9c24.5 31.4004 62.2002 51.9004 105.101 51.9004c10.1992 0 26.0996 -9.59961 57.5996 -9.59961
c31.5996 0 47.4004 9.59961 57.5996 9.59961c43 0 80.7002 -20.5 105.101 -51.9004z" />
<glyph glyph-name="id-badge" unicode="&#xf2c1;" horiz-adv-x="384"
d="M336 448c26.5 0 48 -21.5 48 -48v-416c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48h288zM336 -16v416h-288v-416h288zM144 336c-8.7998 0 -16 7.2002 -16 16s7.2002 16 16 16h96c8.7998 0 16 -7.2002 16 -16s-7.2002 -16 -16 -16
h-96zM192 160c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64zM102.4 32c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8
c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002c0 -10.6006 -10 -19.2002 -22.4004 -19.2002h-179.199z" />
<glyph glyph-name="id-card" unicode="&#xf2c2;" horiz-adv-x="576"
d="M528 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-480c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h480zM528 16v288h-480v-288h32.7998c-1 4.5 -0.799805 -3.59961 -0.799805 22.4004c0 31.7998 30.0996 57.5996 67.2002 57.5996
c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996c0 -26 0.0996094 -17.9004 -0.799805 -22.4004h224.8zM360 96c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16
c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 160c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 224c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112
c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM192 128c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64z" />
<glyph glyph-name="window-maximize" unicode="&#xf2d0;"
d="M464 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h416zM464 22v234h-416v-234c0 -3.2998 2.7002 -6 6 -6h404c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="window-minimize" unicode="&#xf2d1;"
d="M480 -32h-448c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32h448c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32z" />
<glyph glyph-name="window-restore" unicode="&#xf2d2;"
d="M464 448c26.5 0 48 -21.5 48 -48v-320c0 -26.5 -21.5 -48 -48 -48h-48v-48c0 -26.5 -21.5 -48 -48 -48h-320c-26.5 0 -48 21.5 -48 48v320c0 26.5 21.5 48 48 48h48v48c0 26.5 21.5 48 48 48h320zM368 -16v208h-320v-208h320zM464 80v320h-320v-48h224
c26.5 0 48 -21.5 48 -48v-224h48z" />
<glyph glyph-name="snowflake" unicode="&#xf2dc;" horiz-adv-x="448"
d="M440.1 92.7998c7.60059 -4.39941 10.1006 -14.2002 5.5 -21.7002l-7.89941 -13.8994c-4.40039 -7.7002 -14 -10.2998 -21.5 -5.90039l-39.2002 23l9.09961 -34.7002c2.30078 -8.5 -2.69922 -17.2998 -11.0996 -19.5996l-15.2002 -4.09961
c-8.39941 -2.30078 -17.0996 2.7998 -19.2998 11.2998l-21.2998 81l-71.9004 42.2002v-84.5l58.2998 -59.3008c6.10059 -6.19922 6.10059 -16.3994 0 -22.5996l-11.0996 -11.2998c-6.09961 -6.2002 -16.0996 -6.2002 -22.2002 0l-24.8994 25.3994v-46.0996
c0 -8.7998 -7 -16 -15.7002 -16h-15.7002c-8.7002 0 -15.7002 7.2002 -15.7002 16v45.9004l-24.8994 -25.4004c-6.10059 -6.2002 -16.1006 -6.2002 -22.2002 0l-11.1006 11.2998c-6.09961 6.2002 -6.09961 16.4004 0 22.6006l58.3008 59.2998v84.5l-71.9004 -42.2002
l-21.2998 -81c-2.2998 -8.5 -10.9004 -13.5996 -19.2998 -11.2998l-15.2002 4.09961c-8.40039 2.2998 -13.2998 11.1006 -11.1006 19.6006l9.10059 34.6992l-39.2002 -23c-7.5 -4.39941 -17.2002 -1.7998 -21.5 5.90039l-7.90039 13.9004
c-4.2998 7.69922 -1.69922 17.5 5.80078 21.8994l39.1992 23l-34.0996 9.2998c-8.40039 2.30078 -13.2998 11.1006 -11.0996 19.6006l4.09961 15.5c2.2998 8.5 10.9004 13.5996 19.2998 11.2998l79.7002 -21.7002l71.9004 42.2002l-71.9004 42.2002l-79.7002 -21.7002
c-8.39941 -2.2998 -17.0996 2.7998 -19.2998 11.2998l-4.09961 15.5c-2.30078 8.5 2.69922 17.2998 11.0996 19.6006l34.0996 9.09961l-39.1992 23c-7.60059 4.5 -10.1006 14.2002 -5.80078 21.9004l7.90039 13.8994c4.40039 7.7002 14 10.2998 21.5 5.90039l39.2002 -23
l-9.10059 34.7002c-2.2998 8.5 2.7002 17.2998 11.1006 19.5996l15.2002 4.09961c8.39941 2.30078 17.0996 -2.7998 19.2998 -11.2998l21.2998 -81l71.9004 -42.2002v84.5l-58.3008 59.3008c-6.09961 6.19922 -6.09961 16.3994 0 22.5996l11.5 11.2998
c6.10059 6.2002 16.1006 6.2002 22.2002 0l24.9004 -25.3994v46.0996c0 8.7998 7 16 15.7002 16h15.6992c8.7002 0 15.7002 -7.2002 15.7002 -16v-45.9004l24.9004 25.4004c6.09961 6.2002 16.0996 6.2002 22.2002 0l11.0996 -11.2998
c6.09961 -6.2002 6.09961 -16.4004 0 -22.6006l-58.2998 -59.2998v-84.5l71.8994 42.2002l21.3008 81c2.2998 8.5 10.8994 13.5996 19.2998 11.2998l15.2002 -4.09961c8.39941 -2.2998 13.2998 -11.1006 11.0996 -19.6006l-9.09961 -34.6992l39.1992 23
c7.5 4.39941 17.2002 1.7998 21.5 -5.90039l7.90039 -13.9004c4.2998 -7.69922 1.7002 -17.5 -5.7998 -21.8994l-39.2002 -23l34.0996 -9.2998c8.40039 -2.30078 13.3008 -11.1006 11.1006 -19.6006l-4.10059 -15.5c-2.2998 -8.5 -10.8994 -13.5996 -19.2998 -11.2998
l-79.7002 21.7002l-71.8994 -42.2002l71.7998 -42.2002l79.7002 21.7002c8.39941 2.2998 17.0996 -2.7998 19.2998 -11.2998l4.09961 -15.5c2.30078 -8.5 -2.69922 -17.2998 -11.0996 -19.6006l-34.0996 -9.2998z" />
<glyph glyph-name="trash-alt" unicode="&#xf2ed;" horiz-adv-x="448"
d="M268 32c-6.62305 0 -12 5.37695 -12 12v216c0 6.62305 5.37695 12 12 12h24c6.62305 0 12 -5.37695 12 -12v-216c0 -6.62305 -5.37695 -12 -12 -12h-24zM432 368c8.83105 0 16 -7.16895 16 -16v-16c0 -8.83105 -7.16895 -16 -16 -16h-16v-336
c0 -26.4922 -21.5078 -48 -48 -48h-288c-26.4922 0 -48 21.5078 -48 48v336h-16c-8.83105 0 -16 7.16895 -16 16v16c0 8.83105 7.16895 16 16 16h82.4102l34.0195 56.7002c8.39258 13.9844 23.6777 23.2998 41.1602 23.2998h100.82
c0.0078125 0 -0.015625 0.0517578 -0.0078125 0.0517578c17.4824 0 32.7949 -9.36719 41.1875 -23.3516l34 -56.7002h82.4102zM171.84 397.09l-17.4502 -29.0898h139.221l-17.46 29.0898c-1.0498 1.74707 -2.95898 2.91016 -5.14355 2.91016h-0.00683594h-94
c-0.00585938 0 -0.00683594 0.00683594 -0.0126953 0.00683594c-2.18457 0 -4.09766 -1.16992 -5.14746 -2.91699zM368 -16v336h-288v-336h288zM156 32c-6.62305 0 -12 5.37695 -12 12v216c0 6.62305 5.37695 12 12 12h24c6.62305 0 12 -5.37695 12 -12v-216
c0 -6.62305 -5.37695 -12 -12 -12h-24z" />
<glyph glyph-name="images" unicode="&#xf302;" horiz-adv-x="576"
d="M480 32v-16c0 -26.5098 -21.4902 -48 -48 -48h-384c-26.5098 0 -48 21.4902 -48 48v256c0 26.5098 21.4902 48 48 48h16v-48h-10c-3.31152 0 -6 -2.68848 -6 -6v-244c0 -3.31152 2.68848 -6 6 -6h372c3.31152 0 6 2.68848 6 6v10h48zM522 368h-372
c-3.31152 0 -6 -2.68848 -6 -6v-244c0 -3.31152 2.68848 -6 6 -6h372c3.31152 0 6 2.68848 6 6v244c0 3.31152 -2.68848 6 -6 6zM528 416c26.5098 0 48 -21.4902 48 -48v-256c0 -26.5098 -21.4902 -48 -48 -48h-384c-26.5098 0 -48 21.4902 -48 48v256
c0 26.5098 21.4902 48 48 48h384zM264 304c0 -22.0908 -17.9092 -40 -40 -40s-40 17.9092 -40 40s17.9092 40 40 40s40 -17.9092 40 -40zM192 208l39.5146 39.5146c4.68652 4.68652 12.2842 4.68652 16.9717 0l39.5137 -39.5146l103.515 103.515
c4.68652 4.68652 12.2842 4.68652 16.9717 0l71.5137 -71.5146v-80h-288v48z" />
<glyph glyph-name="clipboard" unicode="&#xf328;" horiz-adv-x="384"
d="M336 384c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h80c0 35.2998 28.7002 64 64 64s64 -28.7002 64 -64h80zM192 408c-13.2998 0 -24 -10.7002 -24 -24s10.7002 -24 24 -24s24 10.7002 24 24
s-10.7002 24 -24 24zM336 -10v340c0 3.2998 -2.7002 6 -6 6h-42v-36c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12v36h-42c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h276c3.2998 0 6 2.7002 6 6z" />
<glyph glyph-name="arrow-alt-circle-down" unicode="&#xf358;"
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM224 308c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-116
h67c10.7002 0 16.0996 -12.9004 8.5 -20.5l-99 -99c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-99 99c-7.5 7.59961 -2.2002 20.5 8.5 20.5h67v116z" />
<glyph glyph-name="arrow-alt-circle-left" unicode="&#xf359;"
d="M8 192c0 137 111 248 248 248s248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248zM456 192c0 110.5 -89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200s200 89.5 200 200zM384 212v-40c0 -6.59961 -5.40039 -12 -12 -12h-116v-67
c0 -10.7002 -12.9004 -16 -20.5 -8.5l-99 99c-4.7002 4.7002 -4.7002 12.2998 0 17l99 99c7.59961 7.59961 20.5 2.2002 20.5 -8.5v-67h116c6.59961 0 12 -5.40039 12 -12z" />
<glyph glyph-name="arrow-alt-circle-right" unicode="&#xf35a;"
d="M504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200zM128 172v40c0 6.59961 5.40039 12 12 12h116v67
c0 10.7002 12.9004 16 20.5 8.5l99 -99c4.7002 -4.7002 4.7002 -12.2998 0 -17l-99 -99c-7.59961 -7.59961 -20.5 -2.2002 -20.5 8.5v67h-116c-6.59961 0 -12 5.40039 -12 12z" />
<glyph glyph-name="arrow-alt-circle-up" unicode="&#xf35b;"
d="M256 -56c-137 0 -248 111 -248 248s111 248 248 248s248 -111 248 -248s-111 -248 -248 -248zM256 392c-110.5 0 -200 -89.5 -200 -200s89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200zM276 64h-40c-6.59961 0 -12 5.40039 -12 12v116h-67
c-10.7002 0 -16 12.9004 -8.5 20.5l99 99c4.7002 4.7002 12.2998 4.7002 17 0l99 -99c7.59961 -7.59961 2.2002 -20.5 -8.5 -20.5h-67v-116c0 -6.59961 -5.40039 -12 -12 -12z" />
<glyph glyph-name="gem" unicode="&#xf3a5;" horiz-adv-x="576"
d="M464 448c4.09961 0 7.7998 -2 10.0996 -5.40039l99.9004 -147.199c2.90039 -4.40039 2.59961 -10.1006 -0.700195 -14.2002l-276 -340.8c-4.7998 -5.90039 -13.7998 -5.90039 -18.5996 0l-276 340.8c-3.2998 4 -3.60059 9.7998 -0.700195 14.2002l100 147.199
c2.2002 3.40039 6 5.40039 10 5.40039h352zM444.7 400h-56.7998l51.6992 -96h68.4004zM242.6 400l-51.5996 -96h194l-51.7002 96h-90.7002zM131.3 400l-63.2998 -96h68.4004l51.6992 96h-56.7998zM88.2998 256l119.7 -160l-68.2998 160h-51.4004zM191.2 256l96.7998 -243.3
l96.7998 243.3h-193.6zM368 96l119.6 160h-51.3994z" />
<glyph glyph-name="money-bill-alt" unicode="&#xf3d1;" horiz-adv-x="640"
d="M320 304c53.0195 0 96 -50.1396 96 -112c0 -61.8701 -43 -112 -96 -112c-53.0195 0 -96 50.1504 -96 112c0 61.8604 42.9805 112 96 112zM360 136v16c0 4.41992 -3.58008 8 -8 8h-16v88c0 4.41992 -3.58008 8 -8 8h-13.5801
c-4.91113 0 -9.50586 -1.49316 -13.3096 -4.03027l-15.3301 -10.2197c-2.15332 -1.43262 -3.55957 -3.88379 -3.55957 -6.66113c0 -1.6377 0.493164 -3.16113 1.33887 -4.42871l8.88086 -13.3105c1.43164 -2.15234 3.88379 -3.55957 6.66113 -3.55957
c1.6377 0 3.16016 0.494141 4.42871 1.33984l0.469727 0.310547v-55.4404h-16c-4.41992 0 -8 -3.58008 -8 -8v-16c0 -4.41992 3.58008 -8 8 -8h64c4.41992 0 8 3.58008 8 8zM608 384c17.6699 0 32 -14.3301 32 -32v-320c0 -17.6699 -14.3301 -32 -32 -32h-576
c-17.6699 0 -32 14.3301 -32 32v320c0 17.6699 14.3301 32 32 32h576zM592 112v160c-35.3496 0 -64 28.6504 -64 64h-416c0 -35.3496 -28.6504 -64 -64 -64v-160c35.3496 0 64 -28.6504 64 -64h416c0 35.3496 28.6504 64 64 64z" />
<glyph glyph-name="window-close" unicode="&#xf410;"
d="M464 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h416zM464 22v340c0 3.2998 -2.7002 6 -6 6h-404c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h404c3.2998 0 6 2.7002 6 6z
M356.5 253.4l-61.4004 -61.4004l61.4004 -61.4004c4.59961 -4.59961 4.59961 -12.0996 0 -16.7998l-22.2998 -22.2998c-4.60059 -4.59961 -12.1006 -4.59961 -16.7998 0l-61.4004 61.4004l-61.4004 -61.4004c-4.59961 -4.59961 -12.0996 -4.59961 -16.7998 0
l-22.2998 22.2998c-4.59961 4.60059 -4.59961 12.1006 0 16.7998l61.4004 61.4004l-61.4004 61.4004c-4.59961 4.59961 -4.59961 12.0996 0 16.7998l22.2998 22.2998c4.60059 4.59961 12.1006 4.59961 16.7998 0l61.4004 -61.4004l61.4004 61.4004
c4.59961 4.59961 12.0996 4.59961 16.7998 0l22.2998 -22.2998c4.7002 -4.60059 4.7002 -12.1006 0 -16.7998z" />
<glyph glyph-name="comment-dots" unicode="&#xf4ad;"
d="M144 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM256 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM368 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32
s-32 14.2998 -32 32s14.2998 32 32 32zM256 416c141.4 0 256 -93.0996 256 -208s-114.6 -208 -256 -208c-32.7998 0 -64 5.2002 -92.9004 14.2998c-29.0996 -20.5996 -77.5996 -46.2998 -139.1 -46.2998c-9.59961 0 -18.2998 5.7002 -22.0996 14.5
c-3.80078 8.7998 -2 19 4.59961 26c0.5 0.400391 31.5 33.7998 46.4004 73.2002c-33 35.0996 -52.9004 78.7002 -52.9004 126.3c0 114.9 114.6 208 256 208zM256 48c114.7 0 208 71.7998 208 160s-93.2998 160 -208 160s-208 -71.7998 -208 -160
c0 -42.2002 21.7002 -74.0996 39.7998 -93.4004l20.6006 -21.7998l-10.6006 -28.0996c-5.5 -14.5 -12.5996 -28.1006 -19.8994 -40.2002c23.5996 7.59961 43.1992 18.9004 57.5 29l19.5 13.7998l22.6992 -7.2002c25.3008 -8 51.7002 -12.0996 78.4004 -12.0996z" />
<glyph glyph-name="smile-wink" unicode="&#xf4da;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM365.8 138.4c10.2002 -8.5 11.6006 -23.6006 3.10059 -33.8008
c-30 -36 -74.1006 -56.5996 -120.9 -56.5996s-90.9004 20.5996 -120.9 56.5996c-8.39941 10.2002 -7.09961 25.3008 3.10059 33.8008c10.0996 8.39941 25.2998 7.09961 33.7998 -3.10059c20.7998 -25.0996 51.5 -39.3994 84 -39.3994s63.2002 14.3994 84 39.3994
c8.5 10.2002 23.5996 11.6006 33.7998 3.10059zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 268c25.7002 0 55.9004 -16.9004 59.7002 -42.0996c1.7998 -11.1006 -11.2998 -18.2002 -19.7998 -10.8008l-9.5 8.5
c-14.8008 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-8.30078 -7.39941 -21.5 -0.399414 -19.8008 10.8008c4 25.1992 34.2002 42.0996 59.9004 42.0996z" />
<glyph glyph-name="angry" unicode="&#xf556;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM248 136c33.5996 0 65.2002 -14.7998 86.7998 -40.5996
c8.40039 -10.2002 7.10059 -25.3008 -3.09961 -33.8008c-10.6006 -8.89941 -25.7002 -6.69922 -33.7998 3c-24.8008 29.7002 -75 29.7002 -99.8008 0c-8.5 -10.1992 -23.5996 -11.5 -33.7998 -3s-11.5996 23.6006 -3.09961 33.8008
c21.5996 25.7998 53.2002 40.5996 86.7998 40.5996zM200 208c0 -17.7002 -14.2998 -32.0996 -32 -32.0996s-32 14.2998 -32 32c0 6.19922 2.2002 11.6992 5.2998 16.5996l-28.2002 8.5c-12.6992 3.7998 -19.8994 17.2002 -16.0996 29.9004
c3.7998 12.6992 17.0996 20 29.9004 16.0996l80 -24c12.6992 -3.7998 19.8994 -17.2002 16.0996 -29.9004c-3.09961 -10.3994 -12.7002 -17.0996 -23 -17.0996zM399 262.9c3.7998 -12.7002 -3.40039 -26.1006 -16.0996 -29.8008l-28.2002 -8.5
c3.09961 -4.89941 5.2998 -10.3994 5.2998 -16.5996c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32c-10.2998 0 -19.9004 6.7002 -23 17.0996c-3.7998 12.7002 3.40039 26.1006 16.0996 29.9004l80 24c12.8008 3.7998 26.1006 -3.40039 29.9004 -16.0996z" />
<glyph glyph-name="dizzy" unicode="&#xf567;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM214.2 209.9
c-7.90039 -7.90039 -20.5 -7.90039 -28.4004 -0.200195l-17.7998 17.7998l-17.7998 -17.7998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0c-7.80078 7.7998 -7.80078 20.5 0 28.2998l17.8994 17.9004l-17.8994 17.8994c-7.80078 7.7998 -7.80078 20.5 0 28.2998
c7.7998 7.80078 20.5 7.80078 28.2998 0l17.7998 -17.7998l17.9004 17.9004c7.7998 7.7998 20.5 7.7998 28.2998 0s7.7998 -20.5 0 -28.2998l-17.9004 -17.9004l17.9004 -17.7998c7.7998 -7.7998 7.7998 -20.5 0 -28.2998zM374.2 302.1
c7.7002 -7.7998 7.7002 -20.3994 0 -28.1992l-17.9004 -17.9004l17.7998 -18c7.80078 -7.7998 7.80078 -20.5 0 -28.2998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0l-17.7998 17.7998l-17.7998 -17.7998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0
c-7.80078 7.7998 -7.80078 20.5 0 28.2998l17.8994 17.9004l-17.8994 17.8994c-7.80078 7.7998 -7.80078 20.5 0 28.2998c7.7998 7.80078 20.5 7.80078 28.2998 0l17.7998 -17.7998l17.9004 17.7998c7.7998 7.80078 20.5 7.80078 28.2998 0zM248 176
c35.2998 0 64 -28.7002 64 -64s-28.7002 -64 -64 -64s-64 28.7002 -64 64s28.7002 64 64 64z" />
<glyph glyph-name="flushed" unicode="&#xf579;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM344 304c44.2002 0 80 -35.7998 80 -80s-35.7998 -80 -80 -80
s-80 35.7998 -80 80s35.7998 80 80 80zM344 176c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM344 248c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM232 224c0 -44.2002 -35.7998 -80 -80 -80
s-80 35.7998 -80 80s35.7998 80 80 80s80 -35.7998 80 -80zM152 176c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM152 248c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM312 104
c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-128c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h128z" />
<glyph glyph-name="frown-open" unicode="&#xf57a;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM200 240c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32
s14.2998 32 32 32s32 -14.2998 32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM248 160c35.5996 0 88.7998 -21.2998 95.7998 -61.2002c2 -11.7998 -9.09961 -21.5996 -20.5 -18.0996
c-31.2002 9.59961 -59.3994 15.2998 -75.2998 15.2998s-44.0996 -5.7002 -75.2998 -15.2998c-11.5 -3.40039 -22.5 6.2998 -20.5 18.0996c7 39.9004 60.2002 61.2002 95.7998 61.2002z" />
<glyph glyph-name="grimace" unicode="&#xf57f;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM344 192c26.5 0 48 -21.5 48 -48v-32c0 -26.5 -21.5 -48 -48 -48h-192c-26.5 0 -48 21.5 -48 48v32c0 26.5 21.5 48 48 48
h192zM176 96v24h-40v-8c0 -8.7998 7.2002 -16 16 -16h24zM176 136v24h-24c-8.7998 0 -16 -7.2002 -16 -16v-8h40zM240 96v24h-48v-24h48zM240 136v24h-48v-24h48zM304 96v24h-48v-24h48zM304 136v24h-48v-24h48zM360 112v8h-40v-24h24c8.7998 0 16 7.2002 16 16zM360 136v8
c0 8.7998 -7.2002 16 -16 16h-24v-24h40z" />
<glyph glyph-name="grin" unicode="&#xf580;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 9.90039 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32z" />
<glyph glyph-name="grin-alt" unicode="&#xf581;" horiz-adv-x="496"
d="M200.3 200c-7.5 -11.4004 -24.5996 -12 -32.7002 0c-12.3994 18.7002 -15.1992 37.2998 -15.6992 56c0.599609 18.7002 3.2998 37.2998 15.6992 56c7.60059 11.4004 24.7002 12 32.7002 0c12.4004 -18.7002 15.2002 -37.2998 15.7002 -56
c-0.599609 -18.7002 -3.2998 -37.2998 -15.7002 -56zM328.3 200c-7.5 -11.4004 -24.5996 -12 -32.7002 0c-12.3994 18.7002 -15.1992 37.2998 -15.6992 56c0.599609 18.7002 3.2998 37.2998 15.6992 56c7.60059 11.4004 24.7002 12 32.7002 0
c12.4004 -18.7002 15.2002 -37.2998 15.7002 -56c-0.599609 -18.7002 -3.2998 -37.2998 -15.7002 -56zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200
s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006
s79.7002 4.7998 105.6 13.1006z" />
<glyph glyph-name="grin-beam" unicode="&#xf582;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM117.7 216.3c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996
l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002zM277.7 216.3c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998
c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002z" />
<glyph glyph-name="grin-beam-sweat" unicode="&#xf583;" horiz-adv-x="496"
d="M440 288c-29.5 0 -53.2998 26.2998 -53.2998 58.7002c0 25 31.7002 75.5 46.2002 97.2998c3.5 5.2998 10.5996 5.2998 14.1992 0c14.5 -21.7998 46.2002 -72.2998 46.2002 -97.2998c0 -32.4004 -23.7998 -58.7002 -53.2998 -58.7002zM248 48
c-51.9004 0 -115.3 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-8 -47.0996 -71.3994 -80 -123.3 -80zM378.3 216.3
c-3.09961 -0.899414 -7.2002 0.100586 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998zM483.6 269.2c8 -24.2998 12.4004 -50.2002 12.4004 -77.2002c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248
c45.7002 0 88.4004 -12.5996 125.2 -34.2002c-10.9004 -21.5996 -15.5 -36.2002 -17.2002 -45.7002c-31.2002 20.1006 -68.2002 31.9004 -108 31.9004c-110.3 0 -200 -89.7002 -200 -200s89.7002 -200 200 -200s200 89.7002 200 200
c0 22.5 -3.90039 44.0996 -10.7998 64.2998c0.399414 0 21.7998 -2.7998 46.3994 12.9004zM168 258.6c-12.2998 0 -23.7998 -7.7998 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996z" />
<glyph glyph-name="grin-hearts" unicode="&#xf584;" horiz-adv-x="496"
d="M353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM200.8 192.3
l-70.2002 18.1006c-20.3994 5.2998 -31.8994 27 -24.1992 47.1992c6.69922 17.7002 26.6992 26.7002 44.8994 22l7.10059 -1.89941l2 7.09961c5.09961 18.1006 22.8994 30.9004 41.5 27.9004c21.3994 -3.40039 34.3994 -24.2002 28.7998 -44.5l-19.4004 -69.9004
c-1.2998 -4.5 -6 -7.2002 -10.5 -6zM389.6 257.6c7.7002 -20.1992 -3.7998 -41.7998 -24.1992 -47.0996l-70.2002 -18.2002c-4.60059 -1.2002 -9.2998 1.5 -10.5 6l-19.4004 69.9004c-5.59961 20.2998 7.40039 41.0996 28.7998 44.5c18.7002 3 36.5 -9.7998 41.5 -27.9004
l2 -7.09961l7.10059 1.89941c18.2002 4.7002 38.2002 -4.39941 44.8994 -22zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200
s89.7002 -200 200 -200z" />
<glyph glyph-name="grin-squint" unicode="&#xf585;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 9.90039 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM118.9 184.2c-3.80078 4.39941 -3.90039 11 -0.100586 15.5l33.6006 40.2998
l-33.6006 40.2998c-3.7002 4.5 -3.7002 11 0.100586 15.5c3.89941 4.40039 10.1992 5.5 15.2998 2.5l80 -48c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998s-2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7002 -1.7002 -15.2998 2.5zM361.8 181.7
l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5.10059 2.90039 11.5 1.90039 15.2998 -2.5c3.80078 -4.5 3.90039 -11 0.100586 -15.5l-33.6006 -40.2998l33.6006 -40.2998c3.7002 -4.5 3.7002 -11 -0.100586 -15.5
c-3.59961 -4.2002 -9.89941 -5.7002 -15.2998 -2.5z" />
<glyph glyph-name="grin-squint-tears" unicode="&#xf586;"
d="M117.1 63.9004c6.30078 0.899414 11.7002 -4.5 10.9004 -10.9004c-3.7002 -25.7998 -13.7002 -84 -30.5996 -100.9c-22 -21.8994 -57.9004 -21.5 -80.3008 0.900391c-22.3994 22.4004 -22.7998 58.4004 -0.899414 80.2998
c16.8994 16.9004 75.0996 26.9004 100.899 30.6006zM75.9004 105.6c-19.6006 -3.89941 -35.1006 -8.09961 -47.3008 -12.1992c-39.2998 90.5996 -22.0996 199.899 52 274c48.5 48.3994 111.9 72.5996 175.4 72.5996c38.9004 0 77.7998 -9.2002 113.2 -27.4004
c-4 -12.1992 -8.2002 -28 -12 -48.2998c-30.4004 17.9004 -65 27.7002 -101.2 27.7002c-53.4004 0 -103.6 -20.7998 -141.4 -58.5996c-61.5996 -61.5 -74.2998 -153.4 -38.6992 -227.801zM428.2 293.2c20.2998 3.89941 36.2002 8 48.5 12
c47.8994 -93.2002 32.8994 -210.5 -45.2002 -288.601c-48.5 -48.3994 -111.9 -72.5996 -175.4 -72.5996c-33.6992 0 -67.2998 7 -98.6992 20.5996c4.19922 12.2002 8.2998 27.7002 12.1992 47.2002c26.6006 -12.7998 55.9004 -19.7998 86.4004 -19.7998
c53.4004 0 103.6 20.7998 141.4 58.5996c65.6992 65.7002 75.7998 166 30.7998 242.601zM394.9 320.1c-6.30078 -0.899414 -11.7002 4.5 -10.9004 10.9004c3.7002 25.7998 13.7002 84 30.5996 100.9c22 21.8994 57.9004 21.5 80.3008 -0.900391
c22.3994 -22.4004 22.7998 -58.4004 0.899414 -80.2998c-16.8994 -16.9004 -75.0996 -26.9004 -100.899 -30.6006zM207.9 211.8c3 -3 4.19922 -7.2998 3.19922 -11.5l-22.5996 -90.5c-1.40039 -5.39941 -6.2002 -9.09961 -11.7002 -9.09961h-0.899414
c-5.80078 0.5 -10.5 5.09961 -11 10.8994l-4.80078 52.3008l-52.2998 4.7998c-5.7998 0.5 -10.3994 5.2002 -10.8994 11c-0.400391 5.89941 3.39941 11.2002 9.09961 12.5996l90.5 22.7002c4.2002 1 8.40039 -0.200195 11.4004 -3.2002zM247.6 236.9
c-0.0996094 0 -6.39941 -1.80078 -11.3994 3.19922c-3 3 -4.2002 7.30078 -3.2002 11.4004l22.5996 90.5c1.40039 5.7002 7 9.2002 12.6006 9.09961c5.7998 -0.5 10.5 -5.09961 11 -10.8994l4.7998 -52.2998l52.2998 -4.80078c5.7998 -0.5 10.4004 -5.19922 10.9004 -11
c0.399414 -5.89941 -3.40039 -11.1992 -9.10059 -12.5996zM299.6 148.4c29.1006 29.0996 53 59.5996 65.3008 83.7998c4.89941 9.2998 17.5996 9.89941 23.3994 1.7002c27.7002 -38.9004 6.10059 -106.9 -30.5996 -143.7s-104.8 -58.2998 -143.7 -30.6006
c-8.2998 5.90039 -7.5 18.6006 1.7002 23.4004c24.2002 12.5 54.7998 36.2998 83.8994 65.4004z" />
<glyph glyph-name="grin-stars" unicode="&#xf587;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM125.7 200.9l6.09961 34.8994l-25.3994 24.6006
c-4.60059 4.59961 -1.90039 12.2998 4.2998 13.1992l34.8994 5l15.5 31.6006c2.90039 5.7998 11 5.7998 13.9004 0l15.5 -31.6006l34.9004 -5c6.19922 -1 8.7998 -8.69922 4.2998 -13.1992l-25.4004 -24.6006l6 -34.8994c1 -6.2002 -5.39941 -11 -11 -7.90039
l-31.2998 16.2998l-31.2998 -16.2998c-5.60059 -3.09961 -12 1.7002 -11 7.90039zM385.4 273.6c6.19922 -1 8.89941 -8.59961 4.39941 -13.1992l-25.3994 -24.6006l6 -34.8994c1 -6.2002 -5.40039 -11 -11 -7.90039l-31.3008 16.2998l-31.2998 -16.2998
c-5.59961 -3.09961 -12 1.7002 -11 7.90039l6 34.8994l-25.3994 24.6006c-4.60059 4.59961 -1.90039 12.2998 4.2998 13.1992l34.8994 5l15.5 31.6006c2.90039 5.7998 11 5.7998 13.9004 0l15.5 -31.6006z" />
<glyph glyph-name="grin-tears" unicode="&#xf588;" horiz-adv-x="640"
d="M117.1 191.9c6.30078 0.899414 11.7002 -4.5 10.9004 -10.9004c-3.7002 -25.7998 -13.7002 -84 -30.5996 -100.9c-22 -21.8994 -57.9004 -21.5 -80.3008 0.900391c-22.3994 22.4004 -22.7998 58.4004 -0.899414 80.2998c16.8994 16.9004 75.0996 26.9004 100.899 30.6006
zM623.8 161.3c21.9004 -21.8994 21.5 -57.8994 -0.799805 -80.2002c-22.4004 -22.3994 -58.4004 -22.7998 -80.2998 -0.899414c-16.9004 16.8994 -26.9004 75.0996 -30.6006 100.899c-0.899414 6.30078 4.5 11.7002 10.8008 10.8008
c25.7998 -3.7002 84 -13.7002 100.899 -30.6006zM497.2 99.5996c12.3994 -37.2998 25.0996 -43.7998 28.2998 -46.5c-44.5996 -65.7998 -120 -109.1 -205.5 -109.1s-160.9 43.2998 -205.5 109.1c3.09961 2.60059 15.7998 9.10059 28.2998 46.5
c33.4004 -63.8994 100.3 -107.6 177.2 -107.6s143.8 43.7002 177.2 107.6zM122.7 223.5c-2.40039 0.299805 -5 2.5 -49.5 -6.90039c12.3994 125.4 118.1 223.4 246.8 223.4s234.4 -98 246.8 -223.5c-44.2998 9.40039 -47.3994 7.2002 -49.5 7
c-15.2002 95.2998 -97.7998 168.5 -197.3 168.5s-182.1 -73.2002 -197.3 -168.5zM320 48c-51.9004 0 -115.3 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996
c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-8 -47.0996 -71.3994 -80 -123.3 -80zM450.3 216.3c-3.09961 -0.899414 -7.2002 0.100586 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17
c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998zM240 258.6
c-12.2998 0 -23.7998 -7.7998 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996z" />
<glyph glyph-name="grin-tongue" unicode="&#xf589;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0
l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200
s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996
s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998zM168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32
s14.2998 32 32 32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
<glyph glyph-name="grin-tongue-squint" unicode="&#xf58a;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0
l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200
s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996
s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998zM377.1 295.8c3.80078 -4.39941 3.90039 -11 0.100586 -15.5l-33.6006 -40.2998
l33.6006 -40.2998c3.7002 -4.5 3.7002 -11 -0.100586 -15.5c-3.59961 -4.2002 -9.89941 -5.7002 -15.2998 -2.5l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5 3 11.5 1.90039 15.2998 -2.5zM214.2 250.3
c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998s-2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7002 -1.7002 -15.2998 2.5c-3.80078 4.5 -3.90039 11 -0.100586 15.5l33.6006 40.2998l-33.6006 40.2998c-3.7002 4.5 -3.7002 11 0.100586 15.5
c3.89941 4.5 10.2998 5.5 15.2998 2.5z" />
<glyph glyph-name="grin-tongue-wink" unicode="&#xf58b;" horiz-adv-x="496"
d="M152 268c25.7002 0 55.9004 -16.9004 59.7998 -42.0996c0.799805 -5 -1.7002 -10 -6.09961 -12.4004c-5.7002 -3.09961 -11.2002 -0.599609 -13.7002 1.59961l-9.5 8.5c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5
c-3.7998 -3.39941 -9.2998 -4 -13.7002 -1.59961c-4.39941 2.40039 -6.89941 7.40039 -6.09961 12.4004c3.89941 25.1992 34.0996 42.0996 59.7998 42.0996zM328 320c44.2002 0 80 -35.7998 80 -80s-35.7998 -80 -80 -80s-80 35.7998 -80 80s35.7998 80 80 80zM328 192
c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM328 264c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248z
M312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998
c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3
c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998
c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998z" />
<glyph glyph-name="grin-wink" unicode="&#xf58c;" horiz-adv-x="496"
d="M328 268c25.6904 0 55.8799 -16.9199 59.8701 -42.1201c1.72949 -11.0898 -11.3506 -18.2695 -19.8301 -10.8398l-9.5498 8.47949c-14.8105 13.1904 -46.1602 13.1904 -60.9707 0l-9.5498 -8.47949c-8.33008 -7.40039 -21.5801 -0.379883 -19.8301 10.8398
c3.98047 25.2002 34.1699 42.1201 59.8604 42.1201zM168 208c-17.6699 0 -32 14.3301 -32 32s14.3301 32 32 32s32 -14.3301 32 -32s-14.3301 -32 -32 -32zM353.55 143.36c10.04 3.13965 19.3906 -5.4502 17.71 -15.3408
c-7.92969 -47.1494 -71.3193 -80.0195 -123.26 -80.0195s-115.33 32.8701 -123.26 80.0195c-1.69043 9.9707 7.76953 18.4707 17.71 15.3408c25.9297 -8.31055 64.3994 -13.0605 105.55 -13.0605s79.6201 4.75977 105.55 13.0605zM248 440c136.97 0 248 -111.03 248 -248
s-111.03 -248 -248 -248s-248 111.03 -248 248s111.03 248 248 248zM248 -8c110.28 0 200 89.7197 200 200s-89.7197 200 -200 200s-200 -89.7197 -200 -200s89.7197 -200 200 -200z" />
<glyph glyph-name="kiss" unicode="&#xf596;" horiz-adv-x="496"
d="M168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM304 140c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5
c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM248 440c137 0 248 -111 248 -248
s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z
" />
<glyph glyph-name="kiss-beam" unicode="&#xf597;" horiz-adv-x="496"
d="M168 296c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.299805 -3.7998 -2 -7.19922 -5.59961 -8.2998c-3.10059 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996c-12.3008 0 -23.8008 -7.89941 -31.5 -21.5996l-9.5 -17
c-1.80078 -3.2002 -5.80078 -4.7002 -9.30078 -3.7002c-3.59961 1.10059 -5.89941 4.60059 -5.59961 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8
c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM304 140c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5
c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM328 296
c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.299805 -3.7998 -2 -7.19922 -5.59961 -8.2998c-3.10059 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996c-12.3008 0 -23.8008 -7.89941 -31.5 -21.5996l-9.5 -17
c-1.80078 -3.2002 -5.80078 -4.7002 -9.30078 -3.7002c-3.59961 1.10059 -5.89941 4.60059 -5.59961 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004z" />
<glyph glyph-name="kiss-wink-heart" unicode="&#xf598;" horiz-adv-x="504"
d="M304 139.5c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002
c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM374.5 223c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-2.5 -2.2998 -7.90039 -4.7002 -13.7002 -1.59961c-4.39941 2.39941 -6.89941 7.39941 -6.09961 12.3994
c3.89941 25.2002 34.2002 42.1006 59.7998 42.1006s55.7998 -16.9004 59.7998 -42.1006c0.799805 -5 -1.7002 -10 -6.09961 -12.3994c-4.40039 -2.40039 -9.90039 -1.7002 -13.7002 1.59961zM136 239.5c0 17.7002 14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32
s-32 14.2998 -32 32zM501.1 45.5c9.2002 -23.9004 -4.39941 -49.4004 -28.5 -55.7002l-83 -21.5c-5.39941 -1.39941 -10.8994 1.7998 -12.3994 7.10059l-22.9004 82.5996c-6.59961 24 8.7998 48.5996 34 52.5996c22 3.5 43.1006 -11.5996 49 -33l2.2998 -8.39941
l8.40039 2.2002c21.5996 5.59961 45.0996 -5.10059 53.0996 -25.9004zM334 11.7002c17.7002 -64 10.9004 -39.5 13.4004 -46.7998c-30.5 -13.4004 -64 -20.9004 -99.4004 -20.9004c-137 0 -248 111 -248 248s111 248 248 248s248 -111 247.9 -248
c0 -31.7998 -6.2002 -62.0996 -17.1006 -90c-6 1.5 -12.2002 2.7998 -18.5996 2.90039c-5.60059 9.69922 -13.6006 17.5 -22.6006 23.8994c6.7002 19.9004 10.4004 41.1006 10.4004 63.2002c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200
c30.7998 0 59.9004 7.2002 86 19.7002z" />
<glyph glyph-name="laugh" unicode="&#xf599;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 224c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM168 224
c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
<glyph glyph-name="laugh-beam" unicode="&#xf59a;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 296c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.700195 -8.5 -10.7998 -11.8994 -14.8994 -4.5
l-9.5 17c-7.7002 13.7002 -19.2002 21.6006 -31.5 21.6006c-12.3008 0 -23.8008 -7.90039 -31.5 -21.6006l-9.5 -17c-4.10059 -7.39941 -15.6006 -4.09961 -14.9004 4.5c3.2998 42.1006 32.2002 71.4004 56 71.4004zM127 220.1c-4.2002 -7.39941 -15.7002 -4 -15.0996 4.5
c3.2998 42.1006 32.1992 71.4004 56 71.4004c23.7998 0 52.6992 -29.2998 56 -71.4004c0.699219 -8.5 -10.8008 -11.8994 -14.9004 -4.5l-9.5 17c-7.7002 13.7002 -19.2002 21.6006 -31.5 21.6006s-23.7998 -7.90039 -31.5 -21.6006zM362.4 160c8.19922 0 14.5 -7 13.5 -15
c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
<glyph glyph-name="laugh-squint" unicode="&#xf59b;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM343.6 252l33.6006 -40.2998c8.59961 -10.4004 -3.90039 -24.7998 -15.4004 -18l-80 48
c-7.7998 4.7002 -7.7998 15.8994 0 20.5996l80 48c11.6006 6.7998 24 -7.7002 15.4004 -18zM134.2 193.7c-11.6006 -6.7998 -24.1006 7.59961 -15.4004 18l33.6006 40.2998l-33.6006 40.2998c-8.59961 10.2998 3.7998 24.9004 15.4004 18l80 -48
c7.7998 -4.7002 7.7998 -15.8994 0 -20.5996zM362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
<glyph glyph-name="laugh-wink" unicode="&#xf59c;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 284c25.7002 0 55.9004 -16.9004 59.7002 -42.0996c1.7998 -11.1006 -11.2998 -18.2002 -19.7998 -10.8008
l-9.5 8.5c-14.8008 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-8.30078 -7.39941 -21.5 -0.399414 -19.8008 10.8008c4 25.1992 34.2002 42.0996 59.9004 42.0996zM168 224c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32z
M362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
<glyph glyph-name="meh-blank" unicode="&#xf5a4;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32
s-32 14.2998 -32 32s14.2998 32 32 32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
<glyph glyph-name="meh-rolling-eyes" unicode="&#xf5a5;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM336 296c39.7998 0 72 -32.2002 72 -72s-32.2002 -72 -72 -72
s-72 32.2002 -72 72s32.2002 72 72 72zM336 184c22.0996 0 40 17.9004 40 40c0 13.5996 -7.2998 25.0996 -17.7002 32.2998c1 -2.59961 1.7002 -5.39941 1.7002 -8.2998c0 -13.2998 -10.7002 -24 -24 -24s-24 10.7002 -24 24c0 3 0.700195 5.7002 1.7002 8.2998
c-10.4004 -7.2002 -17.7002 -18.7002 -17.7002 -32.2998c0 -22.0996 17.9004 -40 40 -40zM232 224c0 -39.7998 -32.2002 -72 -72 -72s-72 32.2002 -72 72s32.2002 72 72 72s72 -32.2002 72 -72zM120 224c0 -22.0996 17.9004 -40 40 -40s40 17.9004 40 40
c0 13.5996 -7.2998 25.0996 -17.7002 32.2998c1 -2.59961 1.7002 -5.39941 1.7002 -8.2998c0 -13.2998 -10.7002 -24 -24 -24s-24 10.7002 -24 24c0 3 0.700195 5.7002 1.7002 8.2998c-10.4004 -7.2002 -17.7002 -18.7002 -17.7002 -32.2998zM312 96
c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-128c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h128z" />
<glyph glyph-name="sad-cry" unicode="&#xf5b3;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM392 53.5996c34.5996 35.9004 56 84.7002 56 138.4c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -53.7002 21.4004 -102.4 56 -138.4v114.4
c0 13.2002 10.7998 24 24 24s24 -10.7998 24 -24v-151.4c28.5 -15.5996 61.2002 -24.5996 96 -24.5996s67.5 9 96 24.5996v151.4c0 13.2002 10.7998 24 24 24s24 -10.7998 24 -24v-114.4zM205.8 213.5c-5.7998 -3.2002 -11.2002 -0.700195 -13.7002 1.59961l-9.5 8.5
c-14.7998 13.2002 -46.1992 13.2002 -61 0l-9.5 -8.5c-3.7998 -3.39941 -9.2998 -4 -13.6992 -1.59961c-4.40039 2.40039 -6.90039 7.40039 -6.10059 12.4004c3.90039 25.1992 34.2002 42.0996 59.7998 42.0996c25.6006 0 55.8008 -16.9004 59.8008 -42.0996
c0.799805 -5 -1.7002 -10 -6.10059 -12.4004zM344 268c25.7002 0 55.9004 -16.9004 59.7998 -42.0996c0.799805 -5 -1.7002 -10 -6.09961 -12.4004c-5.7002 -3.09961 -11.2002 -0.599609 -13.7002 1.59961l-9.5 8.5c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5
c-3.7998 -3.39941 -9.2002 -4 -13.7002 -1.59961c-4.39941 2.40039 -6.89941 7.40039 -6.09961 12.4004c3.89941 25.1992 34.0996 42.0996 59.7998 42.0996zM248 176c30.9004 0 56 -28.7002 56 -64s-25.0996 -64 -56 -64s-56 28.7002 -56 64s25.0996 64 56 64z" />
<glyph glyph-name="sad-tear" unicode="&#xf5b4;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM256 144c38.0996 0 74 -16.7998 98.5 -46.0996
c8.5 -10.2002 7.09961 -25.3008 -3.09961 -33.8008c-10.6006 -8.7998 -25.7002 -6.69922 -33.8008 3.10059c-15.2998 18.2998 -37.7998 28.7998 -61.5996 28.7998c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM162.4 173.2c2.7998 3.7002 8.39941 3.7002 11.1992 0c11.4004 -15.2998 36.4004 -50.6006 36.4004 -68.1006
c0 -22.6992 -18.7998 -41.0996 -42 -41.0996s-42 18.4004 -42 41.0996c0 17.5 25 52.8008 36.4004 68.1006z" />
<glyph glyph-name="smile-beam" unicode="&#xf5b8;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM332 135.4c8.5 10.1992 23.5996 11.5 33.7998 3.09961
c10.2002 -8.5 11.6006 -23.5996 3.10059 -33.7998c-30 -36 -74.1006 -56.6006 -120.9 -56.6006s-90.9004 20.6006 -120.9 56.6006c-8.39941 10.2002 -7.09961 25.2998 3.10059 33.7998c10.2002 8.40039 25.2998 7.09961 33.7998 -3.09961
c20.7998 -25.1006 51.5 -39.4004 84 -39.4004s63.2002 14.4004 84 39.4004zM136.5 237l-9.5 -17c-1.90039 -3.2002 -5.90039 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996zM328 296c23.7998 0 52.7002 -29.2998 56 -71.4004
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002
c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004z" />
<glyph glyph-name="surprise" unicode="&#xf5c2;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM248 168c35.2998 0 64 -28.7002 64 -64s-28.7002 -64 -64 -64
s-64 28.7002 -64 64s28.7002 64 64 64zM200 240c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
<glyph glyph-name="tired" unicode="&#xf5c8;" horiz-adv-x="496"
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM377.1 295.8c3.80078 -4.39941 3.90039 -11 0.100586 -15.5
l-33.6006 -40.2998l33.6006 -40.2998c3.7998 -4.5 3.7002 -11 -0.100586 -15.5c-3.5 -4.10059 -9.89941 -5.7002 -15.2998 -2.5l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5 2.90039 11.5 1.90039 15.2998 -2.5z
M220 240c0 -4.2002 -2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7998 -1.60059 -15.2998 2.5c-3.80078 4.5 -3.90039 11 -0.100586 15.5l33.6006 40.2998l-33.6006 40.2998c-3.7998 4.5 -3.7002 11 0.100586 15.5
c3.7998 4.40039 10.2998 5.5 15.2998 2.5l80 -48c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998zM248 176c45.4004 0 100.9 -38.2998 107.8 -93.2998c1.5 -11.9004 -7 -21.6006 -15.5 -17.9004c-22.7002 9.7002 -56.2998 15.2002 -92.2998 15.2002
s-69.5996 -5.5 -92.2998 -15.2002c-8.60059 -3.7002 -17 6.10059 -15.5 17.9004c6.89941 55 62.3994 93.2998 107.8 93.2998z" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 141 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 896 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,148 @@
( function( api, $, _ ) {
wp.customize.bind( 'preview-ready', function() {
});// 'preview-ready'
if ( serverPreviewParams && ! serverPreviewParams.preview_ready_event_exists ) {
try { api.czr_preview = new api.CZR_preview(); } catch( _er_ ) {
console.log( "new api.CZR_preview() => error => ", _er_ );
}
}
else {
api.bind( 'preview-ready', function(){
api.preview.bind( 'active', function() {
try { api.czr_preview = new api.CZR_preview(); } catch( _er_ ) {
console.log( "new api.CZR_preview() => error => ", _er_ );
}
});
});
}
var czrPreviewConstructor = {
setting_cbs : {},
subsetting_cbs : {},//nested sub settings
input_cbs : {},
initialize: function() {
var self = this;
this.pre_setting_cbs = _.extend( self.pre_setting_cbs, self.getPreSettingCbs() );
this.setting_cbs = _.extend( self.setting_cbs, self.getSettingCbs() );
this.subsetting_cbs = _.extend( self.subsetting_cbs, self.getSubSettingCbs() );
this.input_cbs = _.extend( self.input_cbs, self.getInputCbs() );
this.syncData();
this.addCbs();
$( 'body' ).removeClass( 'wp-customizer-unloading' );
},
getPreSettingCbs : function() { return {}; },
getSettingCbs : function() { return {}; },
getSubSettingCbs : function() { return {}; },
getInputCbs : function() { return {}; },
syncData : function() {
api.preview.send( 'czr-query-data-ready', api.settings.czr_wpQueryInfos );
api.preview.send(
'czr-partial-refresh-data',
typeof( undefined ) === typeof( _customizePartialRefreshExports ) ? {} : _customizePartialRefreshExports.partials
);
},
addCbs : function() {
var self = this;
api.preview.bind( 'pre_setting', function( args ) {
args = args || {};
var _setId = args.set_id;
if ( ! api.has( self._build_setId( _setId ) ) )
return;
var _opt_name = self._get_option_name( args.set_id );
if ( ! _.has( self.pre_setting_cbs, _opt_name ) || ! _.isFunction( self.pre_setting_cbs[ _opt_name ] ) )
return;
self.pre_setting_cbs[ _opt_name ]( args );
});
_.each( self.setting_cbs, function( _cb, _setId ) {
if ( ! api.has( self._build_setId( _setId ) ) )
return;
if ( _.isFunction( self.setting_cbs[ _setId ] ) ) {
api( self._build_setId(_setId) ).bind( self.setting_cbs[ _setId ] );
}
} );
api.preview.bind( 'sub_setting', function( args ) {
var _opt_name = self._get_option_name( args.set_id );
if ( ! _.has(self.subsetting_cbs, _opt_name) )
return;
if ( ! _.has( self.subsetting_cbs[ _opt_name ], args.changed_prop ) )
return;
self.subsetting_cbs[ _opt_name ][ args.changed_prop ]( args );
});
api.preview.bind( 'czr_input', function( args ) {
var _defaults = {
set_id : '',
module_id : '',
item_id : '',
input_id : '',
value : null
};
args = _.extend ( _defaults, args );
var _opt_name = self._get_option_name( args.set_id );
if ( ! _.has( self.input_cbs, _opt_name ) )
return;
if ( ! _.has( self.input_cbs[ _opt_name ], args.input_id ) )
return;
self.input_cbs[ _opt_name ][ args.input_id ]( args );
});
api.selectiveRefresh.bind( 'partial-content-rendered', function( params ) {
if ( ! _.has( params, 'partial' ) || ! _.has( params.partial, 'id' ) )
return;
var _shortOptName = params.partial.id;
api.preview.send( 'czr-partial-refresh-done', { set_id : self._build_setId( params.partial.id ) } );
});
},
_build_setId : function ( name ) {
var self = this;
if ( _.isEmpty( window.themeServerPreviewParams ) )
return name;
if ( ! _.isArray( themeServerPreviewParams.wpBuiltinSettings ) || _.contains( themeServerPreviewParams.wpBuiltinSettings, name ) )
return name;
var themeOptionsPrefix = themeServerPreviewParams.themeOptionsPrefix;
if ( _.isEmpty( themeOptionsPrefix ) )
return name;
return -1 == name.indexOf( themeOptionsPrefix ) ? [ themeOptionsPrefix + '[' , name , ']' ].join('') : name;
},
_get_option_name : function( name ) {
if ( _.isEmpty( window.themeServerPreviewParams ) )
return name;
var themeOptionsPrefix = themeServerPreviewParams.themeOptionsPrefix;
if ( _.isEmpty( themeOptionsPrefix ) )
return name;
var self = this;
return name.replace(/\[|\]/g, '').replace( themeOptionsPrefix, '');
},
_is_external : function( _href ) {
if ( 'string' !== typeof(_href) )
return false;
var _thisHref = _href.trim(),
_main_domain = (location.host).split('.').slice(-2).join('.'),
_reg = new RegExp( _main_domain );
if ( _thisHref !== '' && _thisHref != '#' && _isValidURL( _thisHref ) )
return !_reg.test( _thisHref );
return false;
},
_isValidURL : function(_url){
var _pattern = /(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
return _pattern.test( _url );
}
};//czrPreviewConstructor
api.CZR_preview = api.Class.extend( czrPreviewConstructor );
} )( wp.customize, jQuery, _ );
@@ -0,0 +1 @@
!function(r,t,s){if(wp.customize.bind("preview-ready",function(){}),serverPreviewParams&&!serverPreviewParams.preview_ready_event_exists)try{r.czr_preview=new r.CZR_preview}catch(e){console.log("new api.CZR_preview() => error => ",e)}else r.bind("preview-ready",function(){r.preview.bind("active",function(){try{r.czr_preview=new r.CZR_preview}catch(e){console.log("new api.CZR_preview() => error => ",e)}})});var e={setting_cbs:{},subsetting_cbs:{},input_cbs:{},initialize:function(){var e=this;this.pre_setting_cbs=s.extend(e.pre_setting_cbs,e.getPreSettingCbs()),this.setting_cbs=s.extend(e.setting_cbs,e.getSettingCbs()),this.subsetting_cbs=s.extend(e.subsetting_cbs,e.getSubSettingCbs()),this.input_cbs=s.extend(e.input_cbs,e.getInputCbs()),this.syncData(),this.addCbs(),t("body").removeClass("wp-customizer-unloading")},getPreSettingCbs:function(){return{}},getSettingCbs:function(){return{}},getSubSettingCbs:function(){return{}},getInputCbs:function(){return{}},syncData:function(){r.preview.send("czr-query-data-ready",r.settings.czr_wpQueryInfos),r.preview.send("czr-partial-refresh-data","undefined"==typeof _customizePartialRefreshExports?{}:_customizePartialRefreshExports.partials)},addCbs:function(){var n=this;r.preview.bind("pre_setting",function(e){var t=(e=e||{}).set_id;if(r.has(n._build_setId(t))){var i=n._get_option_name(e.set_id);s.has(n.pre_setting_cbs,i)&&s.isFunction(n.pre_setting_cbs[i])&&n.pre_setting_cbs[i](e)}}),s.each(n.setting_cbs,function(e,t){r.has(n._build_setId(t))&&s.isFunction(n.setting_cbs[t])&&r(n._build_setId(t)).bind(n.setting_cbs[t])}),r.preview.bind("sub_setting",function(e){var t=n._get_option_name(e.set_id);s.has(n.subsetting_cbs,t)&&s.has(n.subsetting_cbs[t],e.changed_prop)&&n.subsetting_cbs[t][e.changed_prop](e)}),r.preview.bind("czr_input",function(e){e=s.extend({set_id:"",module_id:"",item_id:"",input_id:"",value:null},e);var t=n._get_option_name(e.set_id);s.has(n.input_cbs,t)&&s.has(n.input_cbs[t],e.input_id)&&n.input_cbs[t][e.input_id](e)}),r.selectiveRefresh.bind("partial-content-rendered",function(e){if(s.has(e,"partial")&&s.has(e.partial,"id")){e.partial.id;r.preview.send("czr-partial-refresh-done",{set_id:n._build_setId(e.partial.id)})}})},_build_setId:function(e){if(s.isEmpty(window.themeServerPreviewParams))return e;if(!s.isArray(themeServerPreviewParams.wpBuiltinSettings)||s.contains(themeServerPreviewParams.wpBuiltinSettings,e))return e;var t=themeServerPreviewParams.themeOptionsPrefix;return s.isEmpty(t)?e:-1==e.indexOf(t)?[t+"[",e,"]"].join(""):e},_get_option_name:function(e){if(s.isEmpty(window.themeServerPreviewParams))return e;var t=themeServerPreviewParams.themeOptionsPrefix;if(s.isEmpty(t))return e;return e.replace(/\[|\]/g,"").replace(t,"")},_is_external:function(e){if("string"!=typeof e)return!1;var t=e.trim(),i=location.host.split(".").slice(-2).join("."),n=new RegExp(i);return!(""===t||"#"==t||!_isValidURL(t))&&!n.test(t)},_isValidURL:function(e){return/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/.test(e)}};r.CZR_preview=r.Class.extend(e)}(wp.customize,jQuery,_);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,556 @@
<?php
namespace Nimble;
if ( did_action('nimble_skope_loaded') ) {
if ( ( defined( 'CZR_DEV' ) && CZR_DEV ) || ( defined( 'NIMBLE_DEV' ) && NIMBLE_DEV ) ) {
error_log( __FILE__ . ' => The skope has already been loaded' );
}
return;
}
// Set the namsepace as a global so we can use it when fired from another theme/plugin using the fmk
global $czr_skope_namespace;
$czr_skope_namespace = __NAMESPACE__ . '\\';
do_action( 'nimble_skope_loaded' );
//Creates a new instance
function Flat_Skop_Base( $params = array() ) {
return Flat_Skop_Base::skp_get_instance( $params );
}
/////////////////////////////////////////////////////////////////
// <DEFINITIONS>
// THE SKOPE MODEL
function skp_get_default_skope_model() {
return array(
'title' => '',
'long_title' => '',
'ctx_title' => '',
'id' => '',
'skope' => '',
//'level' => '',
'obj_id' => '',
'skope_id' => '',
'values' => ''
);
}
// those contexts have no group
function skp_get_no_group_skope_list() {
return array( 'home', 'search', '404', 'date' );
}
/////////////////////////////////////////////////////////////////
// </DEFINITIONS>
/////////////////////////////////////////////////////////////////
// HELPERS
function skp_trim_text( $text, $text_length, $more ) {
if ( !$text )
return '';
$text = trim( strip_tags( $text ) );
if ( !$text_length )
return $text;
$end_substr = $_text_length = strlen( $text );
if ( $_text_length > $text_length ){
$end_substr = strpos( $text, ' ' , $text_length);
$end_substr = ( $end_substr !== FALSE ) ? $end_substr : $text_length;
$text = substr( $text , 0 , $end_substr );
}
return ( ( $end_substr < $text_length ) && $more ) ? $text : $text . ' ' .$more ;
}
/////////////////////////////////////////////////////////////////
// SKOPE HELPERS
/**
* Return the current skope
* Front / Back agnostic.
* @param $_requesting_wot is a string with the following possible values : 'meta_type' (like post) , 'type' (like page), 'id' (like page id)
* @param $_return_string string param stating if the return value should be a string or an array
* @param $requested_parts is an array of parts looking like
* Array
* (
* [meta_type] => post
* [type] => page
* [obj_id] => 9
* )
* USE CASE when $requested_parts is passed : when a post gets deleted, we need to clean any skope posts associated. That's when we invoke skp_get_skope( null, true, $requested_parts )
* @return a string of all concatenated ctx parts (default) 0R an array of the ctx parts
*/
function skp_get_skope( $_requesting_wot = null, $_return_string = true, $requested_parts = array() ) {
//skope builder from the wp $query
//=> returns :
// the meta_type : post, tax, user
// the type : post_type, taxonomy name, author
// the id : post id, term id, user id
// if $parts are provided, use them.
// Note that the value of skp_get_query_skope() is cached when get the first time for better performance
$parts = ( is_array( $requested_parts ) && !empty( $requested_parts ) ) ? $requested_parts : skp_get_query_skope();
// error_log( '<SKOPE PARTS>' );
// error_log( print_r( $parts, true ) );
// error_log( '</SKOPE PARTS>' );
$_return = array();
$meta_type = $type = $obj_id = false;
if ( is_array( $parts ) && !empty( $parts ) ) {
$meta_type = isset( $parts['meta_type'] ) ? $parts['meta_type'] : false;
$type = isset( $parts['type'] ) ? $parts['type'] : false;
$obj_id = isset( $parts['obj_id'] ) ? $parts['obj_id'] : false;
}
switch ( $_requesting_wot ) {
case 'meta_type':
if ( false !== $meta_type ) {
$_return = array( "meta_type" => "{$meta_type}" );
}
break;
case 'type':
if ( false !== $type ) {
$_return = array( "type" => "{$type}" );
}
break;
case 'id':
if ( false !== $obj_id ) {
$_return = array( "id" => "{$obj_id}" );
}
break;
default:
//LOCAL
//here we don't check if there's a type this is the case where there must be one when a meta type (post, tax, user) is defined.
//typically the skope will look like post_page_25
if ( false !== $meta_type && false !== $obj_id ) {
$_return = array( "meta_type" => "{$meta_type}" , "type" => "{$type}", "id" => "{$obj_id}" );
}
//GROUP
else if ( false !== $meta_type && !$obj_id ) {
$_return = array( "meta_type" => "{$meta_type}", "type" => "{$type}" );
}
//LOCAL WITH NO GROUP : home ( when home displays "Your latests posts" ) , 404, search, date, post type archive
else if ( false !== $obj_id ) {
$_return = array( "id" => "{$obj_id}" );
}
else {
// don't print the skope error log if not in dev mode
// fixes : https://github.com/presscustomizr/czr-skope/issues/1
if ( defined( 'NIMBLE_DEV' ) && NIMBLE_DEV ) {
// the favicon request break skope building, so skip this case
// see https://github.com/presscustomizr/nimble-builder/issues/658
if ( '/favicon.ico' !== $_SERVER['REQUEST_URI'] ) {
error_log( __FUNCTION__ . ' error when building the local skope, no object_id provided.');
error_log( print_r( $parts, true) );
}
}
}
break;
}
//return the parts array if not a string requested
if ( !$_return_string ) {
return $_return;
}
//don't go further if not an array or empty
if ( !is_array( $_return ) || ( is_array( $_return ) && empty( $_return ) ) ) {
return '';
}
//if a specific part of the ctx is requested, don't concatenate
//return the part if exists
if ( !is_null( $_requesting_wot ) ) {
return isset( $_return[ $_requesting_wot ] ) ? $_return[ $_requesting_wot ] : '';
}
//generate the ctx string from the array of ctx_parts
$_concat = "";
foreach ( $_return as $_key => $_part ) {
if ( empty( $_concat) ) {
$_concat .= $_part;
} else {
$_concat .= '_'. $_part;
}
}
return $_concat;
}
/**
* skope builder from the wp $query
* !!has to be fired after 'template_redirect'
* Used on front ( not customizing preview ? => @todo make sure of this )
* @return array of ctx parts
*/
function skp_get_query_skope() {
//don't call get_queried_object if the $query is not defined yet
global $wp_the_query;
if ( !isset( $wp_the_query ) || empty( $wp_the_query ) ) {
return array();
}
// is it cached already ?
if ( !empty( Flat_Skop_Base()->query_skope ) ) {
return Flat_Skop_Base()->query_skope;
}
$queried_object = get_queried_object();
// error_log( '<GET QUERIED OBJECT>' . gettype( $queried_object ) );
// error_log( print_r( $wp_the_query , true ) );
// error_log( '</GET QUERIED OBJECT>' );
$meta_type = $type = $obj_id = false;
// The queried object is NULL on
// - home when displaying the latest posts
// - date archives
// - 404 page
// - search page
if ( !is_null( $queried_object ) && is_object( $queried_object ) ) {
//post, custom post types, page
if ( isset($queried_object->post_type) ) {
$meta_type = 'post';
$type = $queried_object->post_type;
$obj_id = $queried_object->ID;
}
//taxinomies : tags, categories, custom tax type
if ( isset($queried_object->taxonomy) && isset($queried_object->term_id) ) {
$meta_type = 'tax';
$type = $queried_object->taxonomy;
$obj_id = $queried_object->term_id;
}
}
//author archive page
if ( is_author() ) {
$meta_type = 'user';
$type = 'author';
$obj_id = $wp_the_query->get( 'author' );
}
//SKOPES WITH NO GROUPS
//post type archive object
if ( is_post_type_archive() ) {
$obj_id = 'post_type_archive' . '_'. $wp_the_query->get( 'post_type' );
}
if ( is_404() ) {
$obj_id = '404';
}
if ( is_search() ) {
$obj_id = 'search';
}
if ( is_date() ) {
$obj_id = 'date';
}
if ( skp_is_real_home() ) {
$obj_id = 'home';
// December 2018
// when the home page is a page, the skope now includes the page id, instead of being generic as it was since then : skp__post_page_home
// This has been introduced to facilitate the compatibility of Nimble Builder with multilanguage plugins like polylang
// => Allows user to create a different home page for each languages
//
// To summarize,
// Before dec 2018 :
// - home page is blog page => skope_id = skp___home
// - home page is page => skope_id = skp__post_page_home
//
// After Dec 2018
// - hope page is blog page => skope_id is unchanged = skp__home
// - home page is a page => skope_id is changed to = skp__post_page_{$static_home_page_id}
//
// This means that if Nimble sections, or any other contextualizations had been made on home when 'page' === get_option( 'show_on_front' ),
// for which the corresponding skope_id was skp__post_page_home,
// those settings have to be copied in the skp__post_page_{$static_home_page_id} skope settings
// If we are on the real home page, but displaying a static page then set the static page id as obj_id
if ( !is_home() && 'page' === get_option( 'show_on_front' ) ) {
$home_page_id = get_option( 'page_on_front' );
if ( 0 < $home_page_id ) {
$obj_id = $home_page_id;
}
}
}
// cache now
if ( did_action( 'wp' ) ) {
Flat_Skop_Base()->query_skope = apply_filters( 'skp_get_query_skope' , array( 'meta_type' => $meta_type , 'type' => $type , 'obj_id' => $obj_id ), $queried_object );
}
return Flat_Skop_Base()->query_skope;
}
//@return the skope prefix used both when customizing and on front
function skp_get_skope_id( $level = 'local' ) {
// CACHE THE SKOPE WHEN 'wp' DONE
// the skope id is used when filtering the options, called hundreds of times.
// We get higher performances with a cached value instead of using the skp_get_skope_id() function on each call.
$new_skope_ids = array( 'local' => '_skope_not_set_', 'group' => '_skope_not_set_' );
if ( did_action( 'wp' ) ) {
if ( empty( Flat_Skop_Base()->current_skope_ids ) ) {
$new_skope_ids['local'] = skp_build_skope_id( array( 'skope_string' => skp_get_skope(), 'skope_level' => 'local' ) );
$new_skope_ids['group'] = skp_build_skope_id( array( 'skope_level' => 'group' ) );
Flat_Skop_Base()->current_skope_ids = $new_skope_ids;
$skope_id_to_return = $new_skope_ids[ $level ];
// error_log('<SKOPE ID cached in skp_get_skope_id>');
// error_log( print_r( $new_skope_ids, true ) );
// error_log('</SKOPE ID cached in skp_get_skope_id>');
} else {
$new_skope_ids = Flat_Skop_Base()->current_skope_ids;
$skope_id_to_return = $new_skope_ids[ $level ];
}
} else {
$skope_id_to_return = array_key_exists( $level, $new_skope_ids ) ? $new_skope_ids[ $level ] : '_skope_not_set_';
}
// if ( !(bool)did_action( 'wp' ) ) {
// sek_error_log('ACTION WP NOT FIRED', did_action('wp'));
// }
// Jan 2021, while working on https://github.com/presscustomizr/nimble-builder-pro/issues/81
// when customizing and firing this function during ajax calls, the check for did_action('wp') will return 0.
// => which will lead to skope_id set to '_skope_not_set_'
// in order to prevent this, let's get the skope_id value from the customizer posted value when available.
if ( skp_is_customizing() && '_skope_not_set_' === $skope_id_to_return && 'local' === $level && !empty($_POST['local_skope_id']) ) {
$skope_id_to_return = sanitize_text_field($_POST['local_skope_id']);
}
// Feb 2021 => added for https://github.com/presscustomizr/nimble-builder/issues/478
if ( skp_is_customizing() && '_skope_not_set_' === $skope_id_to_return && 'group' === $level && !empty($_POST['group_skope_id']) ) {
$skope_id_to_return = sanitize_text_field($_POST['group_skope_id']);
}
$skope_id_to_return = apply_filters( 'skp_get_skope_id', $skope_id_to_return, $level );
// At this point, the skope_id should be set
if ( '_skope_not_set_' === $skope_id_to_return ) {
//error_log( __FUNCTION__ . ' error => skope_id not set for level ' . $level );
}
// error_log('$skope_id_to_return => ' . $level . ' ' . $skope_id_to_return );
// error_log( print_r( Flat_Skop_Base()->current_skope_ids , true ) );
return $skope_id_to_return;
}
//@param args = array(
// 'skope_string' => skp_get_skope(),
// 'skope_type' => $skp_type,
// 'skope_level' => 'local'
//)
//@return string
function skp_build_skope_id( $args = array() ) {
$skope_id = '_skope_not_set_';
// normalizes
$args = is_array( $args ) ? $args : array();
$args = wp_parse_args(
$args,
array( 'skope_string' => '', 'skope_type' => '', 'skope_level' => '' )
);
// set params if not provided
$args['skope_level'] = empty( $args['skope_level'] ) ? 'local' : $args['skope_level'];
$args['skope_string'] = ( 'local' == $args['skope_level'] && empty( $args['skope_string'] ) ) ? skp_get_skope() : $args['skope_string'];
$args['skope_type'] = ( 'group' == $args['skope_level'] && empty( $args['skope_type'] ) ) ? skp_get_skope( 'type' ) : $args['skope_type'];
// generate skope_id for two cases : local or group
switch( $args[ 'skope_level'] ) {
case 'local' :
$skope_id = strtolower( NIMBLE_SKOPE_ID_PREFIX . $args[ 'skope_string' ] );
break;
case 'group' :
if ( !empty( $args[ 'skope_type' ] ) ) {
$skope_id = strtolower( NIMBLE_SKOPE_ID_PREFIX . 'all_' . $args[ 'skope_type' ] );
}
break;
}
return $skope_id;
}
/**
* Used when localizing the customizer js params
* Can be a post ( post, pages, CPT) , tax(tag, cats, custom taxs), author, date, search page, 404.
* @param $args : array(
* 'level' => string,
* 'meta_type' => string
* 'long' => bool
* 'is_prefixed' => bool //<= indicated if we should add the "Options for" prefix
* )
* @return string title of the current ctx if exists. If not => false.
*/
function skp_get_skope_title( $args = array() ) {
$defaults = array(
'level' => '',
'meta_type' => null,
'long' => false,
'is_prefixed' => true
);
$args = wp_parse_args( $args, $defaults );
$level = $args['level'];
$meta_type = $args['meta_type'];
$long = $args['long'];
$is_prefixed = $args['is_prefixed'];
$_dyn_type = ( skp_is_customize_preview_frame() && isset( $_POST['dyn_type']) ) ? sanitize_text_field($_POST['dyn_type']) : '';
$type = skp_get_skope('type');
$skope = skp_get_skope();
$title = '';
if( 'local' == $level ) {
$type = skp_get_skope( 'type' );
$title = $is_prefixed ? __( 'Options for', 'text_doma') . ' ' : $title;
if ( skp_skope_has_a_group( $meta_type ) ) {
$_id = skp_get_skope('id');
switch ($meta_type) {
case 'post':
$type_obj = get_post_type_object( $type );
$title .= sprintf( '%1$s "%3$s" (id : %2$s)', strtolower( $type_obj->labels->singular_name ), $_id, get_the_title( $_id ) );
break;
case 'tax':
$type_obj = get_taxonomy( $type );
$term = get_term( $_id, $type );
$title .= sprintf( '%1$s "%3$s" (id : %2$s)', strtolower( $type_obj->labels->singular_name ), $_id, $term->name );
break;
case 'user':
$author = get_userdata( $_id );
$title .= sprintf( '%1$s "%3$s" (id : %2$s)', __('user', 'text_doma'), $_id, $author->user_login );
break;
}
} else if ( ( 'trans' == $_dyn_type || skp_skope_has_no_group( $skope ) ) ) {
if ( is_post_type_archive() ) {
global $wp_the_query;
$title .= sprintf( __( '%1$s archive page', 'text_doma'), $wp_the_query->get( 'post_type' ) );
} else {
$title .= strtolower( $skope );
}
} else {
$title .= __( 'Undefined', 'text_doma');
}
}
if ( 'group' == $level || 'special_group' == $level ) {
$title = $is_prefixed ? __( 'Options for all', 'text_doma') . ' ' : __( 'All' , 'text_doma' ) . ' ';
switch( $meta_type ) {
case 'post' :
$type_obj = get_post_type_object( $type );
$title .= strtolower( $type_obj->labels->name );
break;
case 'tax' :
$type_obj = get_taxonomy( $type );
$title .= strtolower( $type_obj->labels->name );
break;
case 'user' :
$title .= __('users', 'text_doma');
break;
}
}
if ( 'global' == $level ) {
$title = __( 'Sitewide options', 'text_doma');
}
$title = ucfirst( $title );
return skp_trim_text( $title, $long ? 45 : 28, '...');
}
//@return bool
//=> tells if the current skope is part of the ones without group
function skp_skope_has_no_group( $meta_type ) {
return in_array(
$meta_type,
skp_get_no_group_skope_list()
) || is_post_type_archive();
}
//@return bool
//Tells if the current skope has a group level
function skp_skope_has_a_group( $meta_type ) {
return in_array(
$meta_type,
array('post', 'tax', 'user')
);
}
//@return bool
function skp_is_real_home() {
// Warning : when show_on_front is a page, but no page_on_front has been picked yet, is_home() is true
// beware of https://github.com/presscustomizr/nimble-builder/issues/349
return ( is_home() && ( 'posts' == get_option( 'show_on_front' ) || '__nothing__' == get_option( 'show_on_front' ) ) )
|| ( is_home() && 0 == get_option( 'page_on_front' ) && 'page' == get_option( 'show_on_front' ) )//<= this is the case when the user want to display a page on home but did not pick a page yet
|| is_front_page();
}
/**
* Returns a boolean
*/
function skp_is_customizing() {
//checks if is customizing : two contexts, admin and front (preview frame)
global $pagenow;
$_is_ajaxing_from_customizer = isset( $_POST['customized'] ) || isset( $_POST['wp_customize'] );
$is_customizing = false;
// the check on $pagenow does NOT work on multisite install @see https://github.com/presscustomizr/nimble-builder/issues/240
// That's why we also check with other global vars
// @see wp-includes/theme.php, _wp_customize_include()
$is_customize_php_page = ( is_admin() && 'customize.php' == basename( $_SERVER['PHP_SELF'] ) );
$is_customize_admin_page_one = (
$is_customize_php_page
||
( isset( $_REQUEST['wp_customize'] ) && 'on' == sanitize_text_field($_REQUEST['wp_customize']) )
||
( !empty( $_GET['customize_changeset_uuid'] ) || !empty( $_POST['customize_changeset_uuid'] ) )
);
$is_customize_admin_page_two = is_admin() && isset( $pagenow ) && 'customize.php' == $pagenow;
if ( $is_customize_admin_page_one || $is_customize_admin_page_two ) {
$is_customizing = true;
//hu_is_customize_preview_frame() ?
// Note : is_customize_preview() is not able to differentiate when previewing in the customizer and when previewing a changeset draft.
// @todo => change this
} else if ( is_customize_preview() || ( !is_admin() && isset($_REQUEST['customize_messenger_channel']) ) ) {
$is_customizing = true;
// hu_doing_customizer_ajax()
} else if ( $_is_ajaxing_from_customizer && ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
$is_customizing = true;
}
return $is_customizing;
}
/**
* Is the customizer preview panel being displayed ?
* @return boolean
*/
function skp_is_customize_preview_frame() {
return is_customize_preview() || ( !is_admin() && isset($_REQUEST['customize_messenger_channel']) );
}
/**
* @return boolean
*/
function skp_is_previewing_live_changeset() {
return !isset( $_POST['customize_messenger_channel']) && is_customize_preview();
}
?>
@@ -0,0 +1,30 @@
<?php
////////////////////////////////////////////////////////////////
// FLAT SKOPE BASE
if ( !class_exists( 'Flat_Skop_Base' ) ) :
class Flat_Skop_Base {
static $instance;
public $query_skope = array();//<= will cache the query skope ( otherwise called multiple times ) on the first invokation of skp_get_query_skope() IF 'wp' done
public $current_skope_ids = array();// will cache the skope ids on the first invokation of skp_get_skope_id, if 'wp' done
public static function skp_get_instance( $params ) {
if ( !isset( self::$instance ) && !( self::$instance instanceof Flat_Skop_Base ) )
self::$instance = new Flat_Skope_Clean_Final( $params );
return self::$instance;
}
function __construct( $params = array() ) {
$defaults = array(
'base_url_path' => ''//NIMBLE_BASE_URL . '/inc/czr-skope/'
);
$params = wp_parse_args( $params, $defaults );
if ( !defined( 'NIMBLE_SKOPE_BASE_URL' ) ) { define( 'NIMBLE_SKOPE_BASE_URL' , $params['base_url_path'] ); }
if ( !defined( 'NIMBLE_SKOPE_ID_PREFIX' ) ) { define( 'NIMBLE_SKOPE_ID_PREFIX' , "skp__" ); }
$this->skp_register_and_load_control_assets();
$this->skp_export_skope_data_and_schedule_sending_to_panel();
$this->skp_schedule_cleaning_on_object_delete();
}//__construct
}
endif;
?>
@@ -0,0 +1,45 @@
<?php
/////////////////////////////////////////////////////////////////
// PRINT CUSTOMIZER JAVASCRIPT + LOCALIZED DATA
if ( !class_exists( 'Flat_Skop_Register_And_Load_Control_Assets' ) ) :
class Flat_Skop_Register_And_Load_Control_Assets extends Flat_Skop_Base {
// Fired in Flat_Skop_Base::__construct()
public function skp_register_and_load_control_assets() {
add_action( 'customize_controls_enqueue_scripts', array( $this, 'skp_enqueue_controls_js_css' ), 20 );
}
public function skp_enqueue_controls_js_css() {
$_use_unminified = defined('CZR_DEV')
&& true === CZR_DEV
// && false === strpos( dirname( dirname( dirname (__FILE__) ) ) , 'inc/wfc' )
&& file_exists( sprintf( '%s/assets/czr/js/czr-skope-base.js' , dirname( __FILE__ ) ) );
$_prod_script_path = sprintf(
'%1$s/assets/czr/js/%2$s' ,
NIMBLE_SKOPE_BASE_URL,
$_use_unminified ? 'czr-skope-base.js' : 'czr-skope-base.min.js'
);
wp_enqueue_script(
'czr-skope-base',
//dev / debug mode mode?
$_prod_script_path,
array('customize-controls' , 'jquery', 'underscore'),
( defined('WP_DEBUG') && true === WP_DEBUG ) ? time() : wp_get_theme()->version,
$in_footer = true
);
wp_localize_script(
'czr-skope-base',
'FlatSkopeLocalizedData',
array(
'noGroupSkopeList' => skp_get_no_group_skope_list(),
'defaultSkopeModel' => skp_get_default_skope_model(),
'i18n' => array()
)
);
}
}//class
endif;
?>
@@ -0,0 +1,192 @@
<?php
/* ------------------------------------------------------------------------- *
* CUSTOMIZE PREVIEW : export skope data and send skope to the panel
/* ------------------------------------------------------------------------- */
if ( !class_exists( 'Flat_Export_Skope_Data_And_Send_To_Panel' ) ) :
class Flat_Export_Skope_Data_And_Send_To_Panel extends Flat_Skop_Register_And_Load_Control_Assets {
// Fired in Flat_Skop_Base::__construct()
public function skp_export_skope_data_and_schedule_sending_to_panel() {
add_action( 'wp_head', array( $this, 'skp_print_server_skope_data') , 30 );
}
//hook : 'wp_footer'
public function skp_print_server_skope_data() {
if ( !skp_is_customize_preview_frame() )
return;
global $wp_query, $wp_customize;
$_meta_type = skp_get_skope( 'meta_type', true );
// $_czr_scopes = array( );
$_czr_skopes = $this->_skp_get_json_export_ready_skopes();
$_czr_query_data = $this->_skp_get_json_export_ready_query_data();
ob_start();
?>
var _doSend = function() {
// December 2020 : it may happen that the 'sync' event was already sent and that we missed it
// Typically when the site is slow.
// So we need to check if the "sync" event has fired already ( see customize-base.js, ::bind method )
// For more security, let's introduce a marker and attempt to re-sent after a moment if needed
window.czr_skopes_sent = false;
var _send = function() {
wp.customize.preview.send( 'czr-new-skopes-synced', {
czr_new_skopes : _wpCustomizeSettings.czr_new_skopes || [],
czr_stylesheet : _wpCustomizeSettings.czr_stylesheet || '',
isChangesetDirty : _wpCustomizeSettings.isChangesetDirty || false,
skopeGlobalDBOpt : _wpCustomizeSettings.skopeGlobalDBOpt || [],
} );
window.czr_skopes_sent = true;
};
jQuery( function() {
if ( wp.customize.preview.topics && wp.customize.preview.topics.sync && wp.customize.preview.topics.sync.fired() ) {
_send();
} else {
wp.customize.preview.bind( 'sync', function( events ) {
_send();
});
}
setTimeout( function() {
if ( !window.czr_skopes_sent ) {
_send();
}
}, 2500 );
});
};
// recursively try to load jquery every 200ms during 6s ( max 30 times )
var _doWhenCustomizeSettingsReady = function( attempts ) {
attempts = attempts || 0;
if ( typeof undefined !== typeof window._wpCustomizeSettings ) {
_wpCustomizeSettings.czr_new_skopes = <?php echo wp_json_encode( $_czr_skopes ); ?>;
_wpCustomizeSettings.czr_stylesheet = '<?php echo get_stylesheet(); ?>';
_wpCustomizeSettings.czr_query_params = <?php echo wp_json_encode($_czr_query_data); ?>;
_doSend();
} else if ( attempts < 30 ) {
setTimeout( function() {
attempts++;
_doWhenCustomizeSettingsReady( attempts );
}, 20 );
} else {
if ( window.console && window.console.log ) {
console.log('Nimble Builder problem : _wpCustomizeSettings is not defined');
}
}
};
_doWhenCustomizeSettingsReady();
<?php
$script = ob_get_clean();
wp_register_script( 'nb_print_skope_data_js', '');
wp_enqueue_script( 'nb_print_skope_data_js' );
wp_add_inline_script( 'nb_print_skope_data_js', $script );
}
// introduced in october 2019 for https://github.com/presscustomizr/nimble-builder/issues/401
private function _skp_get_json_export_ready_query_data() {
global $wp_query;
global $authordata;
add_filter('get_the_archive_title_prefix', '__return_false');
$archive_title = get_the_archive_title();
remove_filter('get_the_archive_title_prefix', '__return_false');
return [
'is_singular' => $wp_query->is_singular,
'is_archive' => $wp_query->is_archive,
'is_search' => $wp_query->is_search,
'is_attachment' => $wp_query->is_attachment,
'is_front_page' => is_front_page(),
'the_archive_title' => $archive_title,
'the_archive_description' => get_the_archive_description(),
'the_previous_post_link' => is_singular() ? get_previous_post_link( $format = '%link' ) : '',
'the_next_post_link' => is_singular() ? get_next_post_link( $format = '%link' ) : '',
'the_search_query' => get_search_query(),
'the_search_results_nb' => (int) $wp_query->found_posts,
'the_author_id' => isset( $authordata->ID ) ? $authordata->ID : 0,
'post_id' => get_the_ID(),
'query_vars' => $wp_query->query_vars
];
}
/* ------------------------------------------------------------------------- *
* CUSTOMIZE PREVIEW : BUILD SKOPES JSON
/* ------------------------------------------------------------------------- */
//generates the array of available scopes for a given context
//ex for a single post tagged #tag1 and #tag2 and categroized #cat1 :
//global
//all posts
//local
//posts tagged #tag1
//posts tagged #tag2
//posts categorized #cat1
//@return array()
//
//skp_get_skope_title() takes the following default args
//array(
// 'level' => '',
// 'meta_type' => null,
// 'long' => false,
// 'is_prefixed' => true
//)
private function _skp_get_json_export_ready_skopes() {
$skopes = array();
$_meta_type = skp_get_skope( 'meta_type', true );
//default properties of the scope object
$defaults = skp_get_default_skope_model();
//global and local and always sent
$skopes[] = wp_parse_args(
array(
'title' => skp_get_skope_title( array( 'level' => 'global' ) ),
'long_title' => skp_get_skope_title( array( 'level' => 'global', 'meta_type' => null, 'long' => true ) ),
'ctx_title' => skp_get_skope_title( array( 'level' => 'global', 'meta_type' => null, 'long' => true, 'is_prefixed' => false ) ),
'skope' => 'global',
'level' => '_all_'
),
$defaults
);
//SPECIAL GROUPS
//@todo
//GROUP
//Do we have a group ? => if yes, then there must be a meta type
if ( skp_get_skope('meta_type') ) {
$skopes[] = wp_parse_args(
array(
'title' => skp_get_skope_title( array( 'level' => 'group', 'meta_type' => $_meta_type ) ),
'long_title' => skp_get_skope_title( array( 'level' => 'group', 'meta_type' => $_meta_type, 'long' => true ) ),
'ctx_title' => skp_get_skope_title( array( 'level' => 'group', 'meta_type' => $_meta_type, 'long' => true, 'is_prefixed' => false ) ),
'skope' => 'group',
'level' => 'all_' . skp_get_skope('type'),
'skope_id' => skp_get_skope_id( 'group' )
),
$defaults
);
}
//LOCAL
$skopes[] = wp_parse_args(
array(
'title' => skp_get_skope_title( array( 'level' => 'local', 'meta_type' => $_meta_type ) ),
'long_title' => skp_get_skope_title( array( 'level' => 'local', 'meta_type' => $_meta_type, 'long' => true ) ),
'ctx_title' => skp_get_skope_title( array( 'level' => 'local', 'meta_type' => $_meta_type, 'long' => true, 'is_prefixed' => false ) ),
'skope' => 'local',
'level' => skp_get_skope(),
'obj_id' => skp_get_skope('id'),
'skope_id' => skp_get_skope_id( 'local' )
),
$defaults
);
return apply_filters( 'skp_json_export_ready_skopes', $skopes );
}
}//class
endif;
?>
@@ -0,0 +1,105 @@
<?php
if ( !class_exists( 'Flat_Skope_Clean_Final' ) ) :
final class Flat_Skope_Clean_Final extends Flat_Export_Skope_Data_And_Send_To_Panel {
// Fired in Flat_Skop_Base::__construct()
public function skp_schedule_cleaning_on_object_delete() {
add_action( 'delete_post', array( $this, 'skp_clean_skopified_posts' ) );
add_action( 'delete_term_taxonomy', array( $this, 'skp_clean_skopified_taxonomies' ) );
add_action( 'delete_user', array( $this, 'skp_clean_skopified_users' ) );
}
// Clean any associated skope post for all public post types : post, page, public cpt
// 'delete_post' Fires immediately before a post is deleted from the database.
// @see wp-includes/post.php
// don't have to return anything
public function skp_clean_skopified_posts( $postid ) {
$deletion_candidate = get_post( $postid );
if ( !$deletion_candidate || !is_object( $deletion_candidate ) )
return;
// Stop here if the post type is not considered "viewable".
// For built-in post types such as posts and pages, the 'public' value will be evaluated.
// For all others, the 'publicly_queryable' value will be used.
// For example, the 'revision' post type, which is purely internal and not skopable, won't pass this test.
if ( !is_post_type_viewable( $deletion_candidate->post_type ) )
return;
// Force the skope parts normally retrieved with skp_get_query_skope()
$skope_string = skp_get_skope( null, true, array(
'meta_type' => 'post',
'type' => $deletion_candidate->post_type,
'obj_id' => $postid
) );
// build a skope_id with the normalized function
$skope_id = skp_build_skope_id( array( 'skope_string' => $skope_string, 'skope_level' => 'local' ) );
// fetch the skope post id which, if exists, is set as a theme mod
$skope_post_id_candidate = get_theme_mod( $skope_id );
if ( $skope_post_id_candidate > 0 && get_post( $skope_post_id_candidate ) ) {
// permanently delete the skope post from db
wp_delete_post( $skope_post_id_candidate );
// remove the theme_mod
remove_theme_mod( $skope_id );
}
}
// 'delete_term_taxonomy' Fires immediately before a term taxonomy ID is deleted.
public function skp_clean_skopified_taxonomies( $term_id ) {
$deletion_candidate = get_term( $term_id );
if ( !$deletion_candidate || !is_object( $deletion_candidate ) )
return;
//error_log( print_r( $deletion_candidate, true ) );
// Force the skope parts normally retrieved with skp_get_query_skope()
$skope_string = skp_get_skope( null, true, array(
'meta_type' => 'tax',
'type' => $deletion_candidate->taxonomy,
'obj_id' => $term_id
) );
// build a skope_id with the normalized function
$skope_id = skp_build_skope_id( array( 'skope_string' => $skope_string, 'skope_level' => 'local' ) );
// fetch the skope post id which, if exists, is set as a theme mod
$skope_post_id_candidate = get_theme_mod( $skope_id );
if ( $skope_post_id_candidate > 0 && get_post( $skope_post_id_candidate ) ) {
// permanently delete the skope post from db
wp_delete_post( $skope_post_id_candidate );
// remove the theme_mod
remove_theme_mod( $skope_id );
//error_log( 'SUCCESSFULLY REMOVED SKOPE POST ID ' . $skope_post_id_candidate . ' AND THEME MOD ' . $skope_id );
}
}
// 'delete_user' Fires immediately before a user is deleted from the database.
public function skp_clean_skopified_users( $user_id ) {
// Force the skope parts normally retrieved with skp_get_query_skope()
$skope_string = skp_get_skope( null, true, array(
'meta_type' => 'user',
'type' => 'author',
'obj_id' => $user_id
) );
// build a skope_id with the normalized function
$skope_id = skp_build_skope_id( array( 'skope_string' => $skope_string, 'skope_level' => 'local' ) );
// fetch the skope post id which, if exists, is set as a theme mod
$skope_post_id_candidate = get_theme_mod( $skope_id );
if ( $skope_post_id_candidate > 0 && get_post( $skope_post_id_candidate ) ) {
// permanently delete the skope post from db
wp_delete_post( $skope_post_id_candidate );
// remove the theme_mod
remove_theme_mod( $skope_id );
//error_log( 'SUCCESSFULLY REMOVED SKOPE POST ID ' . $skope_post_id_candidate . ' AND THEME MOD ' . $skope_id );
}
}
}//class
endif;
?>
@@ -0,0 +1,272 @@
module.exports = {
"env": {
"browser": true
},
"extends": "eslint:recommended",
"rules": {
"accessor-pairs": "error",
"array-bracket-newline": "off",
"array-bracket-spacing": "off",
"array-callback-return": "off",
"array-element-newline": "off",
"arrow-body-style": "error",
"arrow-parens": "error",
"arrow-spacing": "error",
"block-scoped-var": "off",
"block-spacing": "off",
"brace-style": "off",
"callback-return": "error",
"camelcase": "off",
"capitalized-comments": "off",
"class-methods-use-this": "error",
"comma-dangle": "off",
"comma-spacing": "off",
"comma-style": [
"error",
"last"
],
"complexity": "off",
"computed-property-spacing": "off",
"consistent-return": "off",
"consistent-this": "off",
"curly": "off",
"default-case": "off",
"dot-location": "off",
"dot-notation": "off",
"eol-last": "off",
"eqeqeq": "off",
"for-direction": "off",
"func-call-spacing": "off",
"func-name-matching": "error",
"func-names": [
"error",
"never"
],
"func-style": "off",
"function-paren-newline": "off",
"generator-star-spacing": "error",
"getter-return": "error",
"global-require": "off",
"guard-for-in": "off",
"handle-callback-err": "error",
"id-blacklist": "error",
"id-length": "off",
"id-match": "error",
"implicit-arrow-linebreak": "error",
"indent": "off",
"indent-legacy": "off",
"init-declarations": "off",
"jsx-quotes": "error",
"key-spacing": "off",
"keyword-spacing": "off",
"line-comment-position": "off",
"linebreak-style": "off",
"lines-around-comment": "off",
"lines-around-directive": "off",
"lines-between-class-members": "error",
"max-depth": "off",
"max-len": "off",
"max-lines": "off",
"max-nested-callbacks": "error",
"max-params": "off",
"max-statements": "off",
"max-statements-per-line": "off",
"multiline-comment-style": "off",
"multiline-ternary": "off",
"new-parens": "off",
"newline-after-var": "off",
"newline-before-return": "off",
"newline-per-chained-call": "off",
"no-alert": "error",
"no-array-constructor": "error",
"no-await-in-loop": "error",
"no-bitwise": "off",
"no-buffer-constructor": "error",
"no-caller": "error",
"no-catch-shadow": "off",
"no-confusing-arrow": "error",
"no-continue": "off",
"no-div-regex": "error",
"no-duplicate-imports": "error",
"no-else-return": "off",
"no-empty-function": "off",
"no-eq-null": "off",
"no-eval": "error",
"no-extend-native": "off",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-extra-parens": "off",
"no-floating-decimal": "off",
"no-implicit-coercion": [
"error",
{
"boolean": false,
"number": false,
"string": false
}
],
"no-implicit-globals": "off",
"no-implied-eval": "error",
"no-inline-comments": "off",
"no-inner-declarations": [
"error",
"functions"
],
"no-invalid-this": "off",
"no-iterator": "error",
"no-label-var": "off",
"no-labels": "off",
"no-lone-blocks": "off",
"no-lonely-if": "off",
"no-loop-func": "error",
"no-magic-numbers": "off",
"no-mixed-operators": "off",
"no-mixed-requires": "error",
"no-multi-assign": "off",
"no-multi-spaces": "off",
"no-multi-str": "error",
"no-multiple-empty-lines": "off",
"no-native-reassign": "error",
"no-negated-condition": "off",
"no-negated-in-lhs": "error",
"no-nested-ternary": "off",
"no-new": "off",
"no-new-func": "error",
"no-new-object": "error",
"no-new-require": "error",
"no-new-wrappers": "error",
"no-octal-escape": "error",
"no-param-reassign": "off",
"no-path-concat": "error",
"no-plusplus": "off",
"no-process-env": "error",
"no-process-exit": "error",
"no-proto": "error",
"no-prototype-builtins": "off",
"no-restricted-globals": "error",
"no-restricted-imports": "error",
"no-restricted-modules": "error",
"no-restricted-properties": "error",
"no-restricted-syntax": "error",
"no-return-assign": "off",
"no-return-await": "error",
"no-script-url": "error",
"no-self-assign": [
"error",
{
"props": false
}
],
"no-self-compare": "off",
"no-sequences": "off",
"no-shadow": "off",
"no-shadow-restricted-names": "error",
"no-spaced-func": "off",
"no-sync": "error",
"no-tabs": "off",
"no-template-curly-in-string": "error",
"no-ternary": "off",
"no-throw-literal": "off",
"no-undef-init": "error",
"no-undefined": "error",
"no-underscore-dangle": "off",
"no-unmodified-loop-condition": "error",
"no-unneeded-ternary": [
"error",
{
"defaultAssignment": true
}
],
"no-unused-expressions": "off",
"no-use-before-define": "off",
"no-useless-call": "off",
"no-useless-computed-key": "error",
"no-useless-concat": "off",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-useless-return": "off",
"no-var": "off",
"no-void": "off",
"no-warning-comments": "off",
"no-whitespace-before-property": "error",
"no-with": "error",
"nonblock-statement-body-position": [
"error",
"any"
],
"object-curly-newline": "off",
"object-curly-spacing": "off",
"object-property-newline": "off",
"object-shorthand": "off",
"one-var": "off",
"one-var-declaration-per-line": "off",
"operator-assignment": "off",
"operator-linebreak": [
"error",
"after"
],
"padded-blocks": "off",
"padding-line-between-statements": "error",
"prefer-arrow-callback": "off",
"prefer-const": "error",
"prefer-destructuring": "off",
"prefer-numeric-literals": "error",
"prefer-promise-reject-errors": "error",
"prefer-reflect": "off",
"prefer-rest-params": "off",
"prefer-spread": "off",
"prefer-template": "off",
"quote-props": "off",
"quotes": "off",
"radix": [
"error",
"always"
],
"require-await": "error",
"require-jsdoc": "off",
"rest-spread-spacing": "error",
"semi": "off",
"semi-spacing": "off",
"semi-style": [
"error",
"last"
],
"sort-imports": "error",
"sort-keys": "off",
"sort-vars": "off",
"space-before-blocks": "off",
"space-before-function-paren": "off",
"space-in-parens": "off",
"space-infix-ops": "off",
"space-unary-ops": "off",
"spaced-comment": "off",
"strict": "off",
"switch-colon-spacing": "off",
"symbol-description": "error",
"template-curly-spacing": "error",
"template-tag-spacing": "error",
"unicode-bom": [
"error",
"never"
],
"valid-jsdoc": "off",
"valid-typeof": [
"error",
{
"requireStringLiterals": false
}
],
"vars-on-top": "off",
"wrap-iife": "off",
"wrap-regex": "off",
"yield-star-spacing": "error",
"yoda": "off"
},
"globals": {
"wp": true,
"jQuery": true,
"_":true,
'FlatSkopeLocalizedData' : true,
'serverControlParams' : true
}
};
@@ -0,0 +1,136 @@
var CZRFlatSkopeModuleMths = CZRFlatSkopeModuleMths || {};
( function ( api, $, _ ) {
$.extend( CZRFlatSkopeModuleMths, {
// fired in module::initialize
scheduleSkopeReactions : function() {
var module = this;
// @params looks like :
// {
// newSkopes : newSkopes,
// previousSkopes : previousSkopes
// }
api.bind( 'active-skopes-updated', function( params ) {
console.log( 'active-skopes-updated', params, module.SKOPE_LEVEL );
params = _.extend( { newSkopes : {}, previousSkopes : {} }, params );
if ( ! _.has( params.newSkopes, module.SKOPE_LEVEL ) ) {
api.errorLog( 'active-skopes-updated => ' + module.SKOPE_LEVEL + ' was not found in the skope list' );
return;
} else {
module.isReady.then( function() {
// Always update the local skope-id in the pre-item
if ( module.preItem && ! _.isEmpty( module.preItem.czr_Input ) && module.preItem.czr_Input.has('skope-id') ) {
module.preItem.czr_Input( 'skope-id' )( params.newSkopes[ module.SKOPE_LEVEL ] );
}
// Print the contextual items only
//module.refreshContextualItems();
// Display the parent control when relevant
module.control.active( '_skope_not_set_' != params.newSkopes[ module.SKOPE_LEVEL ] );
});
// Print a bottom notification in all controls wrapper
//module.printSkopeInfoInControls();
}
});
},
//This method react to the skope change
// => reinstantiates all items based on the current collection
// refreshContextualItems : function() {
// var module = this;
// //Remove item views and instances
// module.czr_Item.each( function( _itm ) {
// if ( ! _.isEmpty( _itm.container ) && 0 < _itm.container.length ) {
// $.when( _itm.container.remove() ).done( function() {
// //Remove item instances
// module.czr_Item.remove( _itm.id );
// });
// } else {
// //Remove item instances
// module.czr_Item.remove( _itm.id );
// }
// });
// // Reset the item collection
// // => the collection listeners will be setup after populate, on 'items-collection-populated'
// var _collection_ = $.extend( true, [], module.itemCollection() );
// // reset the collection
// module.itemCollection = new api.Value( [] );
// module.populateSavedItemCollection( _collection_ );
// },
// // invoked when module.ready() and api.czr_activeSkopes updated
// printSkopeInfoInControls : function() {
// var module = this,
// _css_class_ = 'skp-note-for-' + module.SKOPE_LEVEL;
// //This = _ctrl_
// var mayBePrintAndSetupCtrlBottomNote = function() {
// var _ctrl_ = this,
// _skope_title_ = FlatSkopeLocalizedData.i18n[ 'this page' ];
// if ( 0 < _ctrl_.container.find( '.' + _css_class_ ).length )
// return;
// var currentSkopeObj = _.findWhere( api.czr_currentSkopesCollection(), { skope : module.SKOPE_LEVEL } );
// if ( ! _.isEmpty( currentSkopeObj ) ) {
// _skope_title_ = currentSkopeObj.ctx_title;
// }
// _ctrl_.container.append(
// $('<div>', {
// class: [ _css_class_ , 'skp-ctrl-bottom-note', 'czr-notice' ].join(' '),
// html : [
// FlatSkopeLocalizedData.i18n[ 'Can be customized for' ],
// '<span class="skp-focus-link"><u>' + _skope_title_ + '</u><span>'
// ].join(' ')
// })
// );
// api.CZR_Helpers.setupDOMListeners(
// [//toggles remove view alert
// {
// trigger : 'click keydown',
// selector : ['.' + _css_class_, '.skp-focus-link'].join(' '),
// name : _css_class_,
// //data = {
// // dom_el,
// // dom_event,
// // event,
// // model
// // }
// actions : function( data ) {
// data.dom_event.preventDefault();
// module.control.focus();
// }
// }//actions to execute
// ],
// { model: {}, dom_el:_ctrl_.container },//model + dom scope
// null //instance where to look for the cb methods
// );//api.CZR_Helpers.setupDOMListeners
// };//mayBePrintAndSetupCtrlBottomNote
// _.each( api.czr_skopeBase.getSkopableSettings(), function( settingData ) {
// //console.log('settingDATA', settingData );
// api.control.when( settingData.apiCtrlId, function( _ctrl_ ) {
// _ctrl_.deferred.embedded.then( function() {
// $.when( _ctrl_.container.find('.' + _css_class_ ).remove() ).done( function() {
// if ( module.weHaveASkope() ) {
// mayBePrintAndSetupCtrlBottomNote.call( _ctrl_ );
// }
// });
// });
// } );
// });
// }//printSkopeInfoInControls
});//extend
})( wp.customize , jQuery, _ );
@@ -0,0 +1,132 @@
//@global serverControlParams
var CZRSkopeBaseMths = CZRSkopeBaseMths || {};
(function ( api, $, _ ) {
$.extend( CZRSkopeBaseMths, {
initialize: function() {
var self = this;
///////////////////// DEFINITIONS /////////////////////
//Store the state of the first skope collection state
api.czr_initialSkopeCollectionPopulated = $.Deferred();
//the czr_skopeCollection stores all skopes instantiated by the user
//this collection is not updated directly
//=> it's updated on skope() instance change
api.czr_skopeCollection = new api.Value([]);//all available skope, including the current skopes
//the current skopes collection get updated each time the 'czr-new-skopes-synced' event is triggered on the api by the preview
api.czr_currentSkopesCollection = new api.Value([]);
//the currently active skopes
api.czr_activeSkopes = new api.Value( { local : '', group : ''} );
///////////////////// SKOPE COLLECTIONS SYNCHRONISATION AND LISTENERS /////////////////////
//LISTEN TO SKOPE SYNC => UPDATE SKOPE COLLECTION ON START AND ON EACH REFRESH
//the sent data look like :
//{
// czr_new_skopes : _wpCustomizeSettings.czr_new_skopes || [],
// isChangesetDirty : boolean
// }
api.bind( 'ready' , function() {
api.previewer.bind( 'czr-new-skopes-synced', function( skope_server_data ) {
if ( serverControlParams.isDevMode ) {
api.infoLog( 'API SKOPE SYNCED', skope_server_data );
}
// set the currently active stylesheet
if ( ! _.has( skope_server_data, 'czr_stylesheet') ) {
api.errorLog( "On 'czr-new-skopes-synced' : missing stylesheet in the server data" );
return;
}
api.czr_skopeBase.stylesheet = api.czr_skopeBase.stylesheet || new api.Value( api.settings.theme.stylesheet );
api.czr_skopeBase.stylesheet( skope_server_data.czr_stylesheet );
//api.consoleLog('czr-skopes-ready DATA', skope_server_data );
var preview = this,
previousSkopeCollection = api.czr_currentSkopesCollection();
//initialize skopes with the server sent skope_server_data
//if skope has not been initialized yet and the server sent wrong skope_server_data, then reject the skope ready promise()
if ( ! _.has( skope_server_data, 'czr_new_skopes') ) {
api.errorLog( "On 'czr-new-skopes-synced' : missing skopes in the server data" );
return;
}
// If no "group" skope has been sent, check if we should have one
// array( 'home', 'search', '404', 'date' ) <= have no group
if ( _.isEmpty( _.findWhere( skope_server_data.czr_new_skopes, { skope : 'group' } ) ) ){
var _local_ = _.findWhere( skope_server_data.czr_new_skopes, { skope : 'local' } );
if ( ! _.isEmpty( _local_ ) && ! _.contains( FlatSkopeLocalizedData.noGroupSkopeList, _local_.level ) ) {
api.errorLog( 'No group level skope sent while there should be one' );
}
}
//1) Updated the collection with normalized skopes => prepareSkopeForAPI + api.czr_currentSkopesCollection( collection )
//2) When the api.czr_currentSkopesCollection() Value is set => instantiates the missing skope
//3) Set the skope layout view when the skope embedded promise is resolved
if ( serverControlParams.isDevMode ) {
api.czr_skopeBase.updateSkopeCollection( skope_server_data.czr_new_skopes , preview.channel() );
} else {
try {
api.czr_skopeBase.updateSkopeCollection( skope_server_data.czr_new_skopes , preview.channel() );
} catch ( er ) {
console.log('UPDATE SKOPE COLLECTION ERROR', er);
return;
}
}
//@return void()
// => refresh skope notice below the skope switcher title
// => refresh bottom skope infos in the preview
// var _refreshSkopeInfosNotices = function() {
// console.log('REFRESH SKOPE TITLE IF NEEDED ?');
// //WRITE THE CURRENT SKOPE TITLE
// //self._writeCurrentSkopeTitle();
// };
//Always wait for the initial collection to be populated
api.czr_initialSkopeCollectionPopulated.then( function() {
//console.log('INITIAL SKOPE COLLECTION POPULATED');
if ( ! _.has( skope_server_data, 'czr_new_skopes' ) || _.isEmpty( skope_server_data.czr_new_skopes ) ) {
api.errorLog( 'Missing skope data after refresh', skope_server_data );
}
// set the local and group skope id
api.czr_activeSkopes( {
'local' : self.getSkopeProperty( 'skope_id', 'local' ),
'group' : self.getSkopeProperty( 'skope_id', 'group' )
});
// if ( ! _.isEmpty( previousSkopeCollection ) ) { //Rewrite the title when the local skope has changed
// var _prevLoc = _.findWhere( previousSkopeCollection , { skope : 'local' } ).opt_name,
// _newLoc =_.findWhere( skope_server_data.czr_new_skopes, { skope : 'local' } ).opt_name;
// if ( _newLoc !== _prevLoc ) {
// //REFRESH SKOPE INFOS IN TITLE AND PREVIEW FRAME
// _refreshSkopeInfosNotices();
// }
// }
});
});//api.previewer.bind
});//api.bind( 'ready'
//CURRENT SKOPE COLLECTION LISTENER
//The skope collection is set on 'czr-new-skopes-synced' triggered by the preview
//setup the callbacks of the skope collection update
//on init and on preview change : the collection of skopes is populated with new skopes
//=> instanciate the relevant skope object + render them
api.czr_currentSkopesCollection.bind( function( to, from ) {
return self.currentSkopesCollectionReact( to, from );
}, { deferred : true });
///////////////////// VARIOUS /////////////////////
//DECLARE THE LIST OF CONTROL TYPES FOR WHICH THE VIEW IS REFRESHED ON CHANGE
//self.refreshedControls = [ 'czr_cropped_image'];// [ 'czr_cropped_image', 'czr_multi_module', 'czr_module' ];
api.trigger( 'czr_skopeBase_initialized' );
}//initialize
});//$.extend()
})( wp.customize , jQuery, _);
@@ -0,0 +1,49 @@
//@global serverControlParams
var CZRSkopeBaseMths = CZRSkopeBaseMths || {};
( function ( api, $, _ ) {
$.extend( CZRSkopeBaseMths, {
//////////////////////////////////////////////////////////
/// <SKOPE HELPERSS>
// @return string
getSkopeProperty : function( what, skope_level ) {
what = what || 'skope_id';
skope_level = skope_level || 'local';
var _skope_data = _.findWhere( api.czr_currentSkopesCollection(), { skope : skope_level });
if ( _.isEmpty( _skope_data ) ){
// display an error message if local skope not found. Should always be defined.
if ( 'local' == skope_level ) {
api.errorLog( "getSkopeProperty => local skope missing, returning not_set" );
}
return "_skope_not_set_";//for example when trying to get a group skope_id in a context where there can't be a group skope like home or search.
} else if ( !_.has( _skope_data, what ) ) {
api.errorLog( "getSkopeProperty => " + what + " property does not exist" );
return "_skope_not_set_";
} else {
return _skope_data[ what ];
}
},
//@return string
firstToUpperCase : function( str ) {
return ! _.isString( str ) ? '' : str.substr(0, 1).toUpperCase() + str.substr(1);
}
// //@return string
// buildSkopeLink : function( skope_id ) {
// if ( ! api.czr_skope.has( skope_id ) ) {
// api.errorLog( 'buildSkopeLink : the requested skope id is not registered : ' + skope_id );
// return '';
// }
// var _link_title = [ serverControlParams.i18n.skope['Switch to scope'], api.czr_skope( skope_id )().title ].join(' : ');
// return [
// '<span class="czr-skope-switch" title=" ' + _link_title + '" data-skope-id="' + skope_id + '">',
// api.czr_skope( skope_id )().title,
// '</span>'
// ].join( '' );
// },
});//$.extend
})( wp.customize , jQuery, _ );
@@ -0,0 +1,132 @@
//@global serverControlParams
var CZRSkopeBaseMths = CZRSkopeBaseMths || {};
(function ( api, $, _ ) {
$.extend( CZRSkopeBaseMths, {
//Fired on 'czr-new-skopes-synced' triggered by the preview, each time the preview is refreshed.
//On a Save Action, api.czr_savedDirties has been populated =>
// 1) check if the server sends the same saved values
// 2) update the skope db properties with the latests saved ones
//
//A skope candidate is structured this way :
//{
// id:""
// long_title:"Site wide options"
// obj_id:""
// skope:"global"
// title:"Site wide options"
//}
//@see api_overrides
updateSkopeCollection : function( sent_collection ) {
var self = this,
_api_ready_collection = [];
//normalize each sent skopes
_.each( sent_collection, function( _skope ) {
var skope_candidate = $.extend( true, {}, _skope );//deep clone to avoid any shared references
_api_ready_collection.push( self.prepareSkopeForAPI( skope_candidate ) );
});
//set the new collection of current skopes
//=> this will instantiate the not instantiated skopes
api.czr_currentSkopesCollection( _api_ready_collection );
// set the group skope id
//console.log( "SKOPE COLLECTION UPDATED", api.czr_currentSkopesCollection() );
},
//@param skope_candidate
////A skope candidate is structured this way :
//{
// id:""
// long_title:"Site wide options"
// obj_id:""
// skope:"global"
// title:"Site wide options"
//}
prepareSkopeForAPI : function( skope_candidate ) {
if ( ! _.isObject( skope_candidate ) ) {
throw new Error('prepareSkopeForAPI : a skope must be an object to be API ready');
}
var api_ready_skope = skope_candidate;
_.each( FlatSkopeLocalizedData.defaultSkopeModel , function( _value, _key ) {
var _candidate_val = skope_candidate[_key];
switch( _key ) {
case 'title' :
if ( ! _.isString( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : a skope title property must a string');
}
api_ready_skope[_key] = _candidate_val;
break;
case 'long_title' :
if ( ! _.isString( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : a skope title property must a string');
}
api_ready_skope[_key] = _candidate_val;
break;
case 'ctx_title' :
if ( ! _.isString( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : a skope context title property must a string');
}
api_ready_skope[_key] = _candidate_val;
break;
case 'skope' :
if ( ! _.isString( _candidate_val ) || _.isEmpty( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : a skope "skope" property must a string not empty');
}
api_ready_skope[_key] = _candidate_val;
break;
case 'obj_id' :
if ( ! _.isString( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : invalid "obj_id" for skope ' + _candidate_val.skope );
}
api_ready_skope[_key] = _candidate_val;
break;
case 'skope_id' :
if ( ! _.isString( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : invalid "skope_key" for skope ' + _candidate_val.skope );
}
api_ready_skope[_key] = _candidate_val;
break;
case 'values' :
// if ( ! _.isString( _candidate_val ) ) {
// throw new Error('prepareSkopeForAPI : invalid "values" for skope ' + _candidate_val.skope );
// }
api_ready_skope[_key] = _candidate_val;
break;
default :
api_ready_skope[_key] = _candidate_val;
break;
}//switch
});
//Finally, generate the id and the title
api_ready_skope.id = api_ready_skope.skope + '_' + api_ready_skope.skope_id;
if ( ! _.isString( api_ready_skope.id ) || _.isEmpty( api_ready_skope.id ) ) {
throw new Error('prepareSkopeForAPI : a skope id must a string not empty');
}
if ( ! _.isString( api_ready_skope.title ) || _.isEmpty( api_ready_skope.title ) ) {
api_ready_skope.title = api_ready_skope.id;
api_ready_skope.long_title = api_ready_skope.id;
}
return api_ready_skope;
},
//cb of api.czr_currentSkopesCollection.callbacks
//fired in initialize
currentSkopesCollectionReact : function( to, from ) {
var dfd = $.Deferred();
//ON INITIAL COLLECTION POPULATE, RESOLVE THE DEFERRED STATE
//=> this way we can defer earlier actions.
//For example when autofocus is requested, the section might be expanded before the initial skope collection is sent from the preview.
if ( _.isEmpty( from ) && ! _.isEmpty( to ) ) {
api.czr_initialSkopeCollectionPopulated.resolve();
}
return dfd.resolve( 'changed' ).promise();
}//listenToSkopeCollection()
});//$.extend()
})( wp.customize , jQuery, _);
@@ -0,0 +1,13 @@
//@global serverControlParams
var CZRSkopeBaseMths = CZRSkopeBaseMths || {};
(function ( api, $ ) {
// Skope
$.extend( CZRSkopeBaseMths, api.Events );
var CZR_SkopeBase = api.Class.extend( CZRSkopeBaseMths );
// Schedule skope instantiation on api ready
// api.bind( 'ready' , function() {
// api.czr_skopeBase = new api.CZR_SkopeBase();
// });
api.czr_skopeBase = new CZR_SkopeBase();
})( wp.customize, jQuery );
@@ -0,0 +1,323 @@
//@global serverControlParams
var CZRSkopeBaseMths = CZRSkopeBaseMths || {};
(function ( api, $, _ ) {
$.extend( CZRSkopeBaseMths, {
initialize: function() {
var self = this;
///////////////////// DEFINITIONS /////////////////////
//Store the state of the first skope collection state
api.czr_initialSkopeCollectionPopulated = $.Deferred();
//the czr_skopeCollection stores all skopes instantiated by the user
//this collection is not updated directly
//=> it's updated on skope() instance change
api.czr_skopeCollection = new api.Value([]);//all available skope, including the current skopes
//the current skopes collection get updated each time the 'czr-new-skopes-synced' event is triggered on the api by the preview
api.czr_currentSkopesCollection = new api.Value([]);
//the currently active skopes
api.czr_activeSkopes = new api.Value( { local : '', group : ''} );
///////////////////// SKOPE COLLECTIONS SYNCHRONISATION AND LISTENERS /////////////////////
//LISTEN TO SKOPE SYNC => UPDATE SKOPE COLLECTION ON START AND ON EACH REFRESH
//the sent data look like :
//{
// czr_new_skopes : _wpCustomizeSettings.czr_new_skopes || [],
// isChangesetDirty : boolean
// }
api.bind( 'ready' , function() {
api.previewer.bind( 'czr-new-skopes-synced', function( skope_server_data ) {
if ( serverControlParams.isDevMode ) {
api.infoLog( 'API SKOPE SYNCED', skope_server_data );
}
// set the currently active stylesheet
if ( ! _.has( skope_server_data, 'czr_stylesheet') ) {
api.errorLog( "On 'czr-new-skopes-synced' : missing stylesheet in the server data" );
return;
}
api.czr_skopeBase.stylesheet = api.czr_skopeBase.stylesheet || new api.Value( api.settings.theme.stylesheet );
api.czr_skopeBase.stylesheet( skope_server_data.czr_stylesheet );
//api.consoleLog('czr-skopes-ready DATA', skope_server_data );
var preview = this,
previousSkopeCollection = api.czr_currentSkopesCollection();
//initialize skopes with the server sent skope_server_data
//if skope has not been initialized yet and the server sent wrong skope_server_data, then reject the skope ready promise()
if ( ! _.has( skope_server_data, 'czr_new_skopes') ) {
api.errorLog( "On 'czr-new-skopes-synced' : missing skopes in the server data" );
return;
}
// If no "group" skope has been sent, check if we should have one
// array( 'home', 'search', '404', 'date' ) <= have no group
if ( _.isEmpty( _.findWhere( skope_server_data.czr_new_skopes, { skope : 'group' } ) ) ){
var _local_ = _.findWhere( skope_server_data.czr_new_skopes, { skope : 'local' } );
if ( ! _.isEmpty( _local_ ) && ! _.contains( FlatSkopeLocalizedData.noGroupSkopeList, _local_.level ) ) {
api.errorLog( 'No group level skope sent while there should be one' );
}
}
//1) Updated the collection with normalized skopes => prepareSkopeForAPI + api.czr_currentSkopesCollection( collection )
//2) When the api.czr_currentSkopesCollection() Value is set => instantiates the missing skope
//3) Set the skope layout view when the skope embedded promise is resolved
if ( serverControlParams.isDevMode ) {
api.czr_skopeBase.updateSkopeCollection( skope_server_data.czr_new_skopes , preview.channel() );
} else {
try {
api.czr_skopeBase.updateSkopeCollection( skope_server_data.czr_new_skopes , preview.channel() );
} catch ( er ) {
console.log('UPDATE SKOPE COLLECTION ERROR', er);
return;
}
}
//@return void()
// => refresh skope notice below the skope switcher title
// => refresh bottom skope infos in the preview
// var _refreshSkopeInfosNotices = function() {
// console.log('REFRESH SKOPE TITLE IF NEEDED ?');
// //WRITE THE CURRENT SKOPE TITLE
// //self._writeCurrentSkopeTitle();
// };
//Always wait for the initial collection to be populated
api.czr_initialSkopeCollectionPopulated.then( function() {
//console.log('INITIAL SKOPE COLLECTION POPULATED');
if ( ! _.has( skope_server_data, 'czr_new_skopes' ) || _.isEmpty( skope_server_data.czr_new_skopes ) ) {
api.errorLog( 'Missing skope data after refresh', skope_server_data );
}
// set the local and group skope id
api.czr_activeSkopes( {
'local' : self.getSkopeProperty( 'skope_id', 'local' ),
'group' : self.getSkopeProperty( 'skope_id', 'group' )
});
// if ( ! _.isEmpty( previousSkopeCollection ) ) { //Rewrite the title when the local skope has changed
// var _prevLoc = _.findWhere( previousSkopeCollection , { skope : 'local' } ).opt_name,
// _newLoc =_.findWhere( skope_server_data.czr_new_skopes, { skope : 'local' } ).opt_name;
// if ( _newLoc !== _prevLoc ) {
// //REFRESH SKOPE INFOS IN TITLE AND PREVIEW FRAME
// _refreshSkopeInfosNotices();
// }
// }
});
});//api.previewer.bind
});//api.bind( 'ready'
//CURRENT SKOPE COLLECTION LISTENER
//The skope collection is set on 'czr-new-skopes-synced' triggered by the preview
//setup the callbacks of the skope collection update
//on init and on preview change : the collection of skopes is populated with new skopes
//=> instanciate the relevant skope object + render them
api.czr_currentSkopesCollection.bind( function( to, from ) {
return self.currentSkopesCollectionReact( to, from );
}, { deferred : true });
///////////////////// VARIOUS /////////////////////
//DECLARE THE LIST OF CONTROL TYPES FOR WHICH THE VIEW IS REFRESHED ON CHANGE
//self.refreshedControls = [ 'czr_cropped_image'];// [ 'czr_cropped_image', 'czr_multi_module', 'czr_module' ];
api.trigger( 'czr_skopeBase_initialized' );
}//initialize
});//$.extend()
})( wp.customize , jQuery, _);//@global serverControlParams
var CZRSkopeBaseMths = CZRSkopeBaseMths || {};
( function ( api, $, _ ) {
$.extend( CZRSkopeBaseMths, {
//////////////////////////////////////////////////////////
/// <SKOPE HELPERSS>
// @return string
getSkopeProperty : function( what, skope_level ) {
what = what || 'skope_id';
skope_level = skope_level || 'local';
var _skope_data = _.findWhere( api.czr_currentSkopesCollection(), { skope : skope_level });
if ( _.isEmpty( _skope_data ) ){
// display an error message if local skope not found. Should always be defined.
if ( 'local' == skope_level ) {
api.errorLog( "getSkopeProperty => local skope missing, returning not_set" );
}
return "_skope_not_set_";//for example when trying to get a group skope_id in a context where there can't be a group skope like home or search.
} else if ( !_.has( _skope_data, what ) ) {
api.errorLog( "getSkopeProperty => " + what + " property does not exist" );
return "_skope_not_set_";
} else {
return _skope_data[ what ];
}
},
//@return string
firstToUpperCase : function( str ) {
return ! _.isString( str ) ? '' : str.substr(0, 1).toUpperCase() + str.substr(1);
}
// //@return string
// buildSkopeLink : function( skope_id ) {
// if ( ! api.czr_skope.has( skope_id ) ) {
// api.errorLog( 'buildSkopeLink : the requested skope id is not registered : ' + skope_id );
// return '';
// }
// var _link_title = [ serverControlParams.i18n.skope['Switch to scope'], api.czr_skope( skope_id )().title ].join(' : ');
// return [
// '<span class="czr-skope-switch" title=" ' + _link_title + '" data-skope-id="' + skope_id + '">',
// api.czr_skope( skope_id )().title,
// '</span>'
// ].join( '' );
// },
});//$.extend
})( wp.customize , jQuery, _ );//@global serverControlParams
var CZRSkopeBaseMths = CZRSkopeBaseMths || {};
(function ( api, $, _ ) {
$.extend( CZRSkopeBaseMths, {
//Fired on 'czr-new-skopes-synced' triggered by the preview, each time the preview is refreshed.
//On a Save Action, api.czr_savedDirties has been populated =>
// 1) check if the server sends the same saved values
// 2) update the skope db properties with the latests saved ones
//
//A skope candidate is structured this way :
//{
// id:""
// long_title:"Site wide options"
// obj_id:""
// skope:"global"
// title:"Site wide options"
//}
//@see api_overrides
updateSkopeCollection : function( sent_collection ) {
var self = this,
_api_ready_collection = [];
//normalize each sent skopes
_.each( sent_collection, function( _skope ) {
var skope_candidate = $.extend( true, {}, _skope );//deep clone to avoid any shared references
_api_ready_collection.push( self.prepareSkopeForAPI( skope_candidate ) );
});
//set the new collection of current skopes
//=> this will instantiate the not instantiated skopes
api.czr_currentSkopesCollection( _api_ready_collection );
// set the group skope id
//console.log( "SKOPE COLLECTION UPDATED", api.czr_currentSkopesCollection() );
},
//@param skope_candidate
////A skope candidate is structured this way :
//{
// id:""
// long_title:"Site wide options"
// obj_id:""
// skope:"global"
// title:"Site wide options"
//}
prepareSkopeForAPI : function( skope_candidate ) {
if ( ! _.isObject( skope_candidate ) ) {
throw new Error('prepareSkopeForAPI : a skope must be an object to be API ready');
}
var api_ready_skope = skope_candidate;
_.each( FlatSkopeLocalizedData.defaultSkopeModel , function( _value, _key ) {
var _candidate_val = skope_candidate[_key];
switch( _key ) {
case 'title' :
if ( ! _.isString( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : a skope title property must a string');
}
api_ready_skope[_key] = _candidate_val;
break;
case 'long_title' :
if ( ! _.isString( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : a skope title property must a string');
}
api_ready_skope[_key] = _candidate_val;
break;
case 'ctx_title' :
if ( ! _.isString( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : a skope context title property must a string');
}
api_ready_skope[_key] = _candidate_val;
break;
case 'skope' :
if ( ! _.isString( _candidate_val ) || _.isEmpty( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : a skope "skope" property must a string not empty');
}
api_ready_skope[_key] = _candidate_val;
break;
case 'obj_id' :
if ( ! _.isString( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : invalid "obj_id" for skope ' + _candidate_val.skope );
}
api_ready_skope[_key] = _candidate_val;
break;
case 'skope_id' :
if ( ! _.isString( _candidate_val ) ) {
throw new Error('prepareSkopeForAPI : invalid "skope_key" for skope ' + _candidate_val.skope );
}
api_ready_skope[_key] = _candidate_val;
break;
case 'values' :
// if ( ! _.isString( _candidate_val ) ) {
// throw new Error('prepareSkopeForAPI : invalid "values" for skope ' + _candidate_val.skope );
// }
api_ready_skope[_key] = _candidate_val;
break;
default :
api_ready_skope[_key] = _candidate_val;
break;
}//switch
});
//Finally, generate the id and the title
api_ready_skope.id = api_ready_skope.skope + '_' + api_ready_skope.skope_id;
if ( ! _.isString( api_ready_skope.id ) || _.isEmpty( api_ready_skope.id ) ) {
throw new Error('prepareSkopeForAPI : a skope id must a string not empty');
}
if ( ! _.isString( api_ready_skope.title ) || _.isEmpty( api_ready_skope.title ) ) {
api_ready_skope.title = api_ready_skope.id;
api_ready_skope.long_title = api_ready_skope.id;
}
return api_ready_skope;
},
//cb of api.czr_currentSkopesCollection.callbacks
//fired in initialize
currentSkopesCollectionReact : function( to, from ) {
var dfd = $.Deferred();
//ON INITIAL COLLECTION POPULATE, RESOLVE THE DEFERRED STATE
//=> this way we can defer earlier actions.
//For example when autofocus is requested, the section might be expanded before the initial skope collection is sent from the preview.
if ( _.isEmpty( from ) && ! _.isEmpty( to ) ) {
api.czr_initialSkopeCollectionPopulated.resolve();
}
return dfd.resolve( 'changed' ).promise();
}//listenToSkopeCollection()
});//$.extend()
})( wp.customize , jQuery, _);//@global serverControlParams
var CZRSkopeBaseMths = CZRSkopeBaseMths || {};
(function ( api, $ ) {
// Skope
$.extend( CZRSkopeBaseMths, api.Events );
var CZR_SkopeBase = api.Class.extend( CZRSkopeBaseMths );
// Schedule skope instantiation on api ready
// api.bind( 'ready' , function() {
// api.czr_skopeBase = new api.CZR_SkopeBase();
// });
api.czr_skopeBase = new CZR_SkopeBase();
})( wp.customize, jQuery );
@@ -0,0 +1 @@
var CZRSkopeBaseMths=CZRSkopeBaseMths||{};!function(t,e,s){e.extend(CZRSkopeBaseMths,{initialize:function(){var r=this;t.czr_initialSkopeCollectionPopulated=e.Deferred(),t.czr_skopeCollection=new t.Value([]),t.czr_currentSkopesCollection=new t.Value([]),t.czr_activeSkopes=new t.Value({local:"",group:""}),t.bind("ready",function(){t.previewer.bind("czr-new-skopes-synced",function(e){if(serverControlParams.isDevMode&&t.infoLog("API SKOPE SYNCED",e),s.has(e,"czr_stylesheet")){t.czr_skopeBase.stylesheet=t.czr_skopeBase.stylesheet||new t.Value(t.settings.theme.stylesheet),t.czr_skopeBase.stylesheet(e.czr_stylesheet);t.czr_currentSkopesCollection();if(s.has(e,"czr_new_skopes")){if(s.isEmpty(s.findWhere(e.czr_new_skopes,{skope:"group"}))){var o=s.findWhere(e.czr_new_skopes,{skope:"local"});s.isEmpty(o)||s.contains(FlatSkopeLocalizedData.noGroupSkopeList,o.level)||t.errorLog("No group level skope sent while there should be one")}if(serverControlParams.isDevMode)t.czr_skopeBase.updateSkopeCollection(e.czr_new_skopes,this.channel());else try{t.czr_skopeBase.updateSkopeCollection(e.czr_new_skopes,this.channel())}catch(e){return void console.log("UPDATE SKOPE COLLECTION ERROR",e)}t.czr_initialSkopeCollectionPopulated.then(function(){s.has(e,"czr_new_skopes")&&!s.isEmpty(e.czr_new_skopes)||t.errorLog("Missing skope data after refresh",e),t.czr_activeSkopes({local:r.getSkopeProperty("skope_id","local"),group:r.getSkopeProperty("skope_id","group")})})}else t.errorLog("On 'czr-new-skopes-synced' : missing skopes in the server data")}else t.errorLog("On 'czr-new-skopes-synced' : missing stylesheet in the server data")})}),t.czr_currentSkopesCollection.bind(function(e,o){return r.currentSkopesCollectionReact(e,o)},{deferred:!0}),t.trigger("czr_skopeBase_initialized")}})}(wp.customize,jQuery,_);CZRSkopeBaseMths=CZRSkopeBaseMths||{};!function(t,e,s){e.extend(CZRSkopeBaseMths,{getSkopeProperty:function(e,o){e=e||"skope_id",o=o||"local";var r=s.findWhere(t.czr_currentSkopesCollection(),{skope:o});return s.isEmpty(r)?("local"==o&&t.errorLog("getSkopeProperty => local skope missing, returning not_set"),"_skope_not_set_"):s.has(r,e)?r[e]:(t.errorLog("getSkopeProperty => "+e+" property does not exist"),"_skope_not_set_")},firstToUpperCase:function(e){return s.isString(e)?e.substr(0,1).toUpperCase()+e.substr(1):""}})}(wp.customize,jQuery,_);CZRSkopeBaseMths=CZRSkopeBaseMths||{};!function(s,i,p){i.extend(CZRSkopeBaseMths,{updateSkopeCollection:function(e){var r=this,t=[];p.each(e,function(e){var o=i.extend(!0,{},e);t.push(r.prepareSkopeForAPI(o))}),s.czr_currentSkopesCollection(t)},prepareSkopeForAPI:function(t){if(!p.isObject(t))throw new Error("prepareSkopeForAPI : a skope must be an object to be API ready");var s=t;if(p.each(FlatSkopeLocalizedData.defaultSkopeModel,function(e,o){var r=t[o];switch(o){case"title":case"long_title":if(!p.isString(r))throw new Error("prepareSkopeForAPI : a skope title property must a string");s[o]=r;break;case"ctx_title":if(!p.isString(r))throw new Error("prepareSkopeForAPI : a skope context title property must a string");s[o]=r;break;case"skope":if(!p.isString(r)||p.isEmpty(r))throw new Error('prepareSkopeForAPI : a skope "skope" property must a string not empty');s[o]=r;break;case"obj_id":if(!p.isString(r))throw new Error('prepareSkopeForAPI : invalid "obj_id" for skope '+r.skope);s[o]=r;break;case"skope_id":if(!p.isString(r))throw new Error('prepareSkopeForAPI : invalid "skope_key" for skope '+r.skope);s[o]=r;break;case"values":default:s[o]=r}}),s.id=s.skope+"_"+s.skope_id,!p.isString(s.id)||p.isEmpty(s.id))throw new Error("prepareSkopeForAPI : a skope id must a string not empty");return p.isString(s.title)&&!p.isEmpty(s.title)||(s.title=s.id,s.long_title=s.id),s},currentSkopesCollectionReact:function(e,o){var r=i.Deferred();return p.isEmpty(o)&&!p.isEmpty(e)&&s.czr_initialSkopeCollectionPopulated.resolve(),r.resolve("changed").promise()}})}(wp.customize,jQuery,_);CZRSkopeBaseMths=CZRSkopeBaseMths||{};!function(e,o){jQuery.extend(CZRSkopeBaseMths,e.Events);var r=e.Class.extend(CZRSkopeBaseMths);e.czr_skopeBase=new r}(wp.customize);
@@ -0,0 +1,924 @@
<?php
namespace Nimble;
if ( did_action('nimble_skope_loaded') ) {
if ( ( defined( 'CZR_DEV' ) && CZR_DEV ) || ( defined( 'NIMBLE_DEV' ) && NIMBLE_DEV ) ) {
error_log( __FILE__ . ' => The skope has already been loaded' );
}
return;
}
// Set the namsepace as a global so we can use it when fired from another theme/plugin using the fmk
global $czr_skope_namespace;
$czr_skope_namespace = __NAMESPACE__ . '\\';
do_action( 'nimble_skope_loaded' );
//Creates a new instance
function Flat_Skop_Base( $params = array() ) {
return Flat_Skop_Base::skp_get_instance( $params );
}
/////////////////////////////////////////////////////////////////
// <DEFINITIONS>
// THE SKOPE MODEL
function skp_get_default_skope_model() {
return array(
'title' => '',
'long_title' => '',
'ctx_title' => '',
'id' => '',
'skope' => '',
//'level' => '',
'obj_id' => '',
'skope_id' => '',
'values' => ''
);
}
// those contexts have no group
function skp_get_no_group_skope_list() {
return array( 'home', 'search', '404', 'date' );
}
/////////////////////////////////////////////////////////////////
// </DEFINITIONS>
/////////////////////////////////////////////////////////////////
// HELPERS
function skp_trim_text( $text, $text_length, $more ) {
if ( !$text )
return '';
$text = trim( strip_tags( $text ) );
if ( !$text_length )
return $text;
$end_substr = $_text_length = strlen( $text );
if ( $_text_length > $text_length ){
$end_substr = strpos( $text, ' ' , $text_length);
$end_substr = ( $end_substr !== FALSE ) ? $end_substr : $text_length;
$text = substr( $text , 0 , $end_substr );
}
return ( ( $end_substr < $text_length ) && $more ) ? $text : $text . ' ' .$more ;
}
/////////////////////////////////////////////////////////////////
// SKOPE HELPERS
/**
* Return the current skope
* Front / Back agnostic.
* @param $_requesting_wot is a string with the following possible values : 'meta_type' (like post) , 'type' (like page), 'id' (like page id)
* @param $_return_string string param stating if the return value should be a string or an array
* @param $requested_parts is an array of parts looking like
* Array
* (
* [meta_type] => post
* [type] => page
* [obj_id] => 9
* )
* USE CASE when $requested_parts is passed : when a post gets deleted, we need to clean any skope posts associated. That's when we invoke skp_get_skope( null, true, $requested_parts )
* @return a string of all concatenated ctx parts (default) 0R an array of the ctx parts
*/
function skp_get_skope( $_requesting_wot = null, $_return_string = true, $requested_parts = array() ) {
//skope builder from the wp $query
//=> returns :
// the meta_type : post, tax, user
// the type : post_type, taxonomy name, author
// the id : post id, term id, user id
// if $parts are provided, use them.
// Note that the value of skp_get_query_skope() is cached when get the first time for better performance
$parts = ( is_array( $requested_parts ) && !empty( $requested_parts ) ) ? $requested_parts : skp_get_query_skope();
// error_log( '<SKOPE PARTS>' );
// error_log( print_r( $parts, true ) );
// error_log( '</SKOPE PARTS>' );
$_return = array();
$meta_type = $type = $obj_id = false;
if ( is_array( $parts ) && !empty( $parts ) ) {
$meta_type = isset( $parts['meta_type'] ) ? $parts['meta_type'] : false;
$type = isset( $parts['type'] ) ? $parts['type'] : false;
$obj_id = isset( $parts['obj_id'] ) ? $parts['obj_id'] : false;
}
switch ( $_requesting_wot ) {
case 'meta_type':
if ( false !== $meta_type ) {
$_return = array( "meta_type" => "{$meta_type}" );
}
break;
case 'type':
if ( false !== $type ) {
$_return = array( "type" => "{$type}" );
}
break;
case 'id':
if ( false !== $obj_id ) {
$_return = array( "id" => "{$obj_id}" );
}
break;
default:
//LOCAL
//here we don't check if there's a type this is the case where there must be one when a meta type (post, tax, user) is defined.
//typically the skope will look like post_page_25
if ( false !== $meta_type && false !== $obj_id ) {
$_return = array( "meta_type" => "{$meta_type}" , "type" => "{$type}", "id" => "{$obj_id}" );
}
//GROUP
else if ( false !== $meta_type && !$obj_id ) {
$_return = array( "meta_type" => "{$meta_type}", "type" => "{$type}" );
}
//LOCAL WITH NO GROUP : home ( when home displays "Your latests posts" ) , 404, search, date, post type archive
else if ( false !== $obj_id ) {
$_return = array( "id" => "{$obj_id}" );
}
else {
// don't print the skope error log if not in dev mode
// fixes : https://github.com/presscustomizr/czr-skope/issues/1
if ( defined( 'NIMBLE_DEV' ) && NIMBLE_DEV ) {
// the favicon request break skope building, so skip this case
// see https://github.com/presscustomizr/nimble-builder/issues/658
if ( '/favicon.ico' !== $_SERVER['REQUEST_URI'] ) {
error_log( __FUNCTION__ . ' error when building the local skope, no object_id provided.');
error_log( print_r( $parts, true) );
}
}
}
break;
}
//return the parts array if not a string requested
if ( !$_return_string ) {
return $_return;
}
//don't go further if not an array or empty
if ( !is_array( $_return ) || ( is_array( $_return ) && empty( $_return ) ) ) {
return '';
}
//if a specific part of the ctx is requested, don't concatenate
//return the part if exists
if ( !is_null( $_requesting_wot ) ) {
return isset( $_return[ $_requesting_wot ] ) ? $_return[ $_requesting_wot ] : '';
}
//generate the ctx string from the array of ctx_parts
$_concat = "";
foreach ( $_return as $_key => $_part ) {
if ( empty( $_concat) ) {
$_concat .= $_part;
} else {
$_concat .= '_'. $_part;
}
}
return $_concat;
}
/**
* skope builder from the wp $query
* !!has to be fired after 'template_redirect'
* Used on front ( not customizing preview ? => @todo make sure of this )
* @return array of ctx parts
*/
function skp_get_query_skope() {
//don't call get_queried_object if the $query is not defined yet
global $wp_the_query;
if ( !isset( $wp_the_query ) || empty( $wp_the_query ) ) {
return array();
}
// is it cached already ?
if ( !empty( Flat_Skop_Base()->query_skope ) ) {
return Flat_Skop_Base()->query_skope;
}
$queried_object = get_queried_object();
// error_log( '<GET QUERIED OBJECT>' . gettype( $queried_object ) );
// error_log( print_r( $wp_the_query , true ) );
// error_log( '</GET QUERIED OBJECT>' );
$meta_type = $type = $obj_id = false;
// The queried object is NULL on
// - home when displaying the latest posts
// - date archives
// - 404 page
// - search page
if ( !is_null( $queried_object ) && is_object( $queried_object ) ) {
//post, custom post types, page
if ( isset($queried_object->post_type) ) {
$meta_type = 'post';
$type = $queried_object->post_type;
$obj_id = $queried_object->ID;
}
//taxinomies : tags, categories, custom tax type
if ( isset($queried_object->taxonomy) && isset($queried_object->term_id) ) {
$meta_type = 'tax';
$type = $queried_object->taxonomy;
$obj_id = $queried_object->term_id;
}
}
//author archive page
if ( is_author() ) {
$meta_type = 'user';
$type = 'author';
$obj_id = $wp_the_query->get( 'author' );
}
//SKOPES WITH NO GROUPS
//post type archive object
if ( is_post_type_archive() ) {
$obj_id = 'post_type_archive' . '_'. $wp_the_query->get( 'post_type' );
}
if ( is_404() ) {
$obj_id = '404';
}
if ( is_search() ) {
$obj_id = 'search';
}
if ( is_date() ) {
$obj_id = 'date';
}
if ( skp_is_real_home() ) {
$obj_id = 'home';
// December 2018
// when the home page is a page, the skope now includes the page id, instead of being generic as it was since then : skp__post_page_home
// This has been introduced to facilitate the compatibility of Nimble Builder with multilanguage plugins like polylang
// => Allows user to create a different home page for each languages
//
// To summarize,
// Before dec 2018 :
// - home page is blog page => skope_id = skp___home
// - home page is page => skope_id = skp__post_page_home
//
// After Dec 2018
// - hope page is blog page => skope_id is unchanged = skp__home
// - home page is a page => skope_id is changed to = skp__post_page_{$static_home_page_id}
//
// This means that if Nimble sections, or any other contextualizations had been made on home when 'page' === get_option( 'show_on_front' ),
// for which the corresponding skope_id was skp__post_page_home,
// those settings have to be copied in the skp__post_page_{$static_home_page_id} skope settings
// If we are on the real home page, but displaying a static page then set the static page id as obj_id
if ( !is_home() && 'page' === get_option( 'show_on_front' ) ) {
$home_page_id = get_option( 'page_on_front' );
if ( 0 < $home_page_id ) {
$obj_id = $home_page_id;
}
}
}
// cache now
if ( did_action( 'wp' ) ) {
Flat_Skop_Base()->query_skope = apply_filters( 'skp_get_query_skope' , array( 'meta_type' => $meta_type , 'type' => $type , 'obj_id' => $obj_id ), $queried_object );
}
return Flat_Skop_Base()->query_skope;
}
//@return the skope prefix used both when customizing and on front
function skp_get_skope_id( $level = 'local' ) {
// CACHE THE SKOPE WHEN 'wp' DONE
// the skope id is used when filtering the options, called hundreds of times.
// We get higher performances with a cached value instead of using the skp_get_skope_id() function on each call.
$new_skope_ids = array( 'local' => '_skope_not_set_', 'group' => '_skope_not_set_' );
if ( did_action( 'wp' ) ) {
if ( empty( Flat_Skop_Base()->current_skope_ids ) ) {
$new_skope_ids['local'] = skp_build_skope_id( array( 'skope_string' => skp_get_skope(), 'skope_level' => 'local' ) );
$new_skope_ids['group'] = skp_build_skope_id( array( 'skope_level' => 'group' ) );
Flat_Skop_Base()->current_skope_ids = $new_skope_ids;
$skope_id_to_return = $new_skope_ids[ $level ];
// error_log('<SKOPE ID cached in skp_get_skope_id>');
// error_log( print_r( $new_skope_ids, true ) );
// error_log('</SKOPE ID cached in skp_get_skope_id>');
} else {
$new_skope_ids = Flat_Skop_Base()->current_skope_ids;
$skope_id_to_return = $new_skope_ids[ $level ];
}
} else {
$skope_id_to_return = array_key_exists( $level, $new_skope_ids ) ? $new_skope_ids[ $level ] : '_skope_not_set_';
}
// if ( !(bool)did_action( 'wp' ) ) {
// sek_error_log('ACTION WP NOT FIRED', did_action('wp'));
// }
// Jan 2021, while working on https://github.com/presscustomizr/nimble-builder-pro/issues/81
// when customizing and firing this function during ajax calls, the check for did_action('wp') will return 0.
// => which will lead to skope_id set to '_skope_not_set_'
// in order to prevent this, let's get the skope_id value from the customizer posted value when available.
if ( skp_is_customizing() && '_skope_not_set_' === $skope_id_to_return && 'local' === $level && !empty($_POST['local_skope_id']) ) {
$skope_id_to_return = sanitize_text_field($_POST['local_skope_id']);
}
// Feb 2021 => added for https://github.com/presscustomizr/nimble-builder/issues/478
if ( skp_is_customizing() && '_skope_not_set_' === $skope_id_to_return && 'group' === $level && !empty($_POST['group_skope_id']) ) {
$skope_id_to_return = sanitize_text_field($_POST['group_skope_id']);
}
$skope_id_to_return = apply_filters( 'skp_get_skope_id', $skope_id_to_return, $level );
// At this point, the skope_id should be set
if ( '_skope_not_set_' === $skope_id_to_return ) {
//error_log( __FUNCTION__ . ' error => skope_id not set for level ' . $level );
}
// error_log('$skope_id_to_return => ' . $level . ' ' . $skope_id_to_return );
// error_log( print_r( Flat_Skop_Base()->current_skope_ids , true ) );
return $skope_id_to_return;
}
//@param args = array(
// 'skope_string' => skp_get_skope(),
// 'skope_type' => $skp_type,
// 'skope_level' => 'local'
//)
//@return string
function skp_build_skope_id( $args = array() ) {
$skope_id = '_skope_not_set_';
// normalizes
$args = is_array( $args ) ? $args : array();
$args = wp_parse_args(
$args,
array( 'skope_string' => '', 'skope_type' => '', 'skope_level' => '' )
);
// set params if not provided
$args['skope_level'] = empty( $args['skope_level'] ) ? 'local' : $args['skope_level'];
$args['skope_string'] = ( 'local' == $args['skope_level'] && empty( $args['skope_string'] ) ) ? skp_get_skope() : $args['skope_string'];
$args['skope_type'] = ( 'group' == $args['skope_level'] && empty( $args['skope_type'] ) ) ? skp_get_skope( 'type' ) : $args['skope_type'];
// generate skope_id for two cases : local or group
switch( $args[ 'skope_level'] ) {
case 'local' :
$skope_id = strtolower( NIMBLE_SKOPE_ID_PREFIX . $args[ 'skope_string' ] );
break;
case 'group' :
if ( !empty( $args[ 'skope_type' ] ) ) {
$skope_id = strtolower( NIMBLE_SKOPE_ID_PREFIX . 'all_' . $args[ 'skope_type' ] );
}
break;
}
return $skope_id;
}
/**
* Used when localizing the customizer js params
* Can be a post ( post, pages, CPT) , tax(tag, cats, custom taxs), author, date, search page, 404.
* @param $args : array(
* 'level' => string,
* 'meta_type' => string
* 'long' => bool
* 'is_prefixed' => bool //<= indicated if we should add the "Options for" prefix
* )
* @return string title of the current ctx if exists. If not => false.
*/
function skp_get_skope_title( $args = array() ) {
$defaults = array(
'level' => '',
'meta_type' => null,
'long' => false,
'is_prefixed' => true
);
$args = wp_parse_args( $args, $defaults );
$level = $args['level'];
$meta_type = $args['meta_type'];
$long = $args['long'];
$is_prefixed = $args['is_prefixed'];
$_dyn_type = ( skp_is_customize_preview_frame() && isset( $_POST['dyn_type']) ) ? sanitize_text_field($_POST['dyn_type']) : '';
$type = skp_get_skope('type');
$skope = skp_get_skope();
$title = '';
if( 'local' == $level ) {
$type = skp_get_skope( 'type' );
$title = $is_prefixed ? __( 'Options for', 'text_doma') . ' ' : $title;
if ( skp_skope_has_a_group( $meta_type ) ) {
$_id = skp_get_skope('id');
switch ($meta_type) {
case 'post':
$type_obj = get_post_type_object( $type );
$title .= sprintf( '%1$s "%3$s" (id : %2$s)', strtolower( $type_obj->labels->singular_name ), $_id, get_the_title( $_id ) );
break;
case 'tax':
$type_obj = get_taxonomy( $type );
$term = get_term( $_id, $type );
$title .= sprintf( '%1$s "%3$s" (id : %2$s)', strtolower( $type_obj->labels->singular_name ), $_id, $term->name );
break;
case 'user':
$author = get_userdata( $_id );
$title .= sprintf( '%1$s "%3$s" (id : %2$s)', __('user', 'text_doma'), $_id, $author->user_login );
break;
}
} else if ( ( 'trans' == $_dyn_type || skp_skope_has_no_group( $skope ) ) ) {
if ( is_post_type_archive() ) {
global $wp_the_query;
$title .= sprintf( __( '%1$s archive page', 'text_doma'), $wp_the_query->get( 'post_type' ) );
} else {
$title .= strtolower( $skope );
}
} else {
$title .= __( 'Undefined', 'text_doma');
}
}
if ( 'group' == $level || 'special_group' == $level ) {
$title = $is_prefixed ? __( 'Options for all', 'text_doma') . ' ' : __( 'All' , 'text_doma' ) . ' ';
switch( $meta_type ) {
case 'post' :
$type_obj = get_post_type_object( $type );
$title .= strtolower( $type_obj->labels->name );
break;
case 'tax' :
$type_obj = get_taxonomy( $type );
$title .= strtolower( $type_obj->labels->name );
break;
case 'user' :
$title .= __('users', 'text_doma');
break;
}
}
if ( 'global' == $level ) {
$title = __( 'Sitewide options', 'text_doma');
}
$title = ucfirst( $title );
return skp_trim_text( $title, $long ? 45 : 28, '...');
}
//@return bool
//=> tells if the current skope is part of the ones without group
function skp_skope_has_no_group( $meta_type ) {
return in_array(
$meta_type,
skp_get_no_group_skope_list()
) || is_post_type_archive();
}
//@return bool
//Tells if the current skope has a group level
function skp_skope_has_a_group( $meta_type ) {
return in_array(
$meta_type,
array('post', 'tax', 'user')
);
}
//@return bool
function skp_is_real_home() {
// Warning : when show_on_front is a page, but no page_on_front has been picked yet, is_home() is true
// beware of https://github.com/presscustomizr/nimble-builder/issues/349
return ( is_home() && ( 'posts' == get_option( 'show_on_front' ) || '__nothing__' == get_option( 'show_on_front' ) ) )
|| ( is_home() && 0 == get_option( 'page_on_front' ) && 'page' == get_option( 'show_on_front' ) )//<= this is the case when the user want to display a page on home but did not pick a page yet
|| is_front_page();
}
/**
* Returns a boolean
*/
function skp_is_customizing() {
//checks if is customizing : two contexts, admin and front (preview frame)
global $pagenow;
$_is_ajaxing_from_customizer = isset( $_POST['customized'] ) || isset( $_POST['wp_customize'] );
$is_customizing = false;
// the check on $pagenow does NOT work on multisite install @see https://github.com/presscustomizr/nimble-builder/issues/240
// That's why we also check with other global vars
// @see wp-includes/theme.php, _wp_customize_include()
$is_customize_php_page = ( is_admin() && 'customize.php' == basename( $_SERVER['PHP_SELF'] ) );
$is_customize_admin_page_one = (
$is_customize_php_page
||
( isset( $_REQUEST['wp_customize'] ) && 'on' == sanitize_text_field($_REQUEST['wp_customize']) )
||
( !empty( $_GET['customize_changeset_uuid'] ) || !empty( $_POST['customize_changeset_uuid'] ) )
);
$is_customize_admin_page_two = is_admin() && isset( $pagenow ) && 'customize.php' == $pagenow;
if ( $is_customize_admin_page_one || $is_customize_admin_page_two ) {
$is_customizing = true;
//hu_is_customize_preview_frame() ?
// Note : is_customize_preview() is not able to differentiate when previewing in the customizer and when previewing a changeset draft.
// @todo => change this
} else if ( is_customize_preview() || ( !is_admin() && isset($_REQUEST['customize_messenger_channel']) ) ) {
$is_customizing = true;
// hu_doing_customizer_ajax()
} else if ( $_is_ajaxing_from_customizer && ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
$is_customizing = true;
}
return $is_customizing;
}
/**
* Is the customizer preview panel being displayed ?
* @return boolean
*/
function skp_is_customize_preview_frame() {
return is_customize_preview() || ( !is_admin() && isset($_REQUEST['customize_messenger_channel']) );
}
/**
* @return boolean
*/
function skp_is_previewing_live_changeset() {
return !isset( $_POST['customize_messenger_channel']) && is_customize_preview();
}
?><?php
////////////////////////////////////////////////////////////////
// FLAT SKOPE BASE
if ( !class_exists( 'Flat_Skop_Base' ) ) :
class Flat_Skop_Base {
static $instance;
public $query_skope = array();//<= will cache the query skope ( otherwise called multiple times ) on the first invokation of skp_get_query_skope() IF 'wp' done
public $current_skope_ids = array();// will cache the skope ids on the first invokation of skp_get_skope_id, if 'wp' done
public static function skp_get_instance( $params ) {
if ( !isset( self::$instance ) && !( self::$instance instanceof Flat_Skop_Base ) )
self::$instance = new Flat_Skope_Clean_Final( $params );
return self::$instance;
}
function __construct( $params = array() ) {
$defaults = array(
'base_url_path' => ''//NIMBLE_BASE_URL . '/inc/czr-skope/'
);
$params = wp_parse_args( $params, $defaults );
if ( !defined( 'NIMBLE_SKOPE_BASE_URL' ) ) { define( 'NIMBLE_SKOPE_BASE_URL' , $params['base_url_path'] ); }
if ( !defined( 'NIMBLE_SKOPE_ID_PREFIX' ) ) { define( 'NIMBLE_SKOPE_ID_PREFIX' , "skp__" ); }
$this->skp_register_and_load_control_assets();
$this->skp_export_skope_data_and_schedule_sending_to_panel();
$this->skp_schedule_cleaning_on_object_delete();
}//__construct
}
endif;
?><?php
/////////////////////////////////////////////////////////////////
// PRINT CUSTOMIZER JAVASCRIPT + LOCALIZED DATA
if ( !class_exists( 'Flat_Skop_Register_And_Load_Control_Assets' ) ) :
class Flat_Skop_Register_And_Load_Control_Assets extends Flat_Skop_Base {
// Fired in Flat_Skop_Base::__construct()
public function skp_register_and_load_control_assets() {
add_action( 'customize_controls_enqueue_scripts', array( $this, 'skp_enqueue_controls_js_css' ), 20 );
}
public function skp_enqueue_controls_js_css() {
$_use_unminified = defined('CZR_DEV')
&& true === CZR_DEV
// && false === strpos( dirname( dirname( dirname (__FILE__) ) ) , 'inc/wfc' )
&& file_exists( sprintf( '%s/assets/czr/js/czr-skope-base.js' , dirname( __FILE__ ) ) );
$_prod_script_path = sprintf(
'%1$s/assets/czr/js/%2$s' ,
NIMBLE_SKOPE_BASE_URL,
$_use_unminified ? 'czr-skope-base.js' : 'czr-skope-base.min.js'
);
wp_enqueue_script(
'czr-skope-base',
//dev / debug mode mode?
$_prod_script_path,
array('customize-controls' , 'jquery', 'underscore'),
( defined('WP_DEBUG') && true === WP_DEBUG ) ? time() : wp_get_theme()->version,
$in_footer = true
);
wp_localize_script(
'czr-skope-base',
'FlatSkopeLocalizedData',
array(
'noGroupSkopeList' => skp_get_no_group_skope_list(),
'defaultSkopeModel' => skp_get_default_skope_model(),
'i18n' => array()
)
);
}
}//class
endif;
?><?php
/* ------------------------------------------------------------------------- *
* CUSTOMIZE PREVIEW : export skope data and send skope to the panel
/* ------------------------------------------------------------------------- */
if ( !class_exists( 'Flat_Export_Skope_Data_And_Send_To_Panel' ) ) :
class Flat_Export_Skope_Data_And_Send_To_Panel extends Flat_Skop_Register_And_Load_Control_Assets {
// Fired in Flat_Skop_Base::__construct()
public function skp_export_skope_data_and_schedule_sending_to_panel() {
add_action( 'wp_head', array( $this, 'skp_print_server_skope_data') , 30 );
}
//hook : 'wp_footer'
public function skp_print_server_skope_data() {
if ( !skp_is_customize_preview_frame() )
return;
global $wp_query, $wp_customize;
$_meta_type = skp_get_skope( 'meta_type', true );
// $_czr_scopes = array( );
$_czr_skopes = $this->_skp_get_json_export_ready_skopes();
$_czr_query_data = $this->_skp_get_json_export_ready_query_data();
ob_start();
?>
var _doSend = function() {
// December 2020 : it may happen that the 'sync' event was already sent and that we missed it
// Typically when the site is slow.
// So we need to check if the "sync" event has fired already ( see customize-base.js, ::bind method )
// For more security, let's introduce a marker and attempt to re-sent after a moment if needed
window.czr_skopes_sent = false;
var _send = function() {
wp.customize.preview.send( 'czr-new-skopes-synced', {
czr_new_skopes : _wpCustomizeSettings.czr_new_skopes || [],
czr_stylesheet : _wpCustomizeSettings.czr_stylesheet || '',
isChangesetDirty : _wpCustomizeSettings.isChangesetDirty || false,
skopeGlobalDBOpt : _wpCustomizeSettings.skopeGlobalDBOpt || [],
} );
window.czr_skopes_sent = true;
};
jQuery( function() {
if ( wp.customize.preview.topics && wp.customize.preview.topics.sync && wp.customize.preview.topics.sync.fired() ) {
_send();
} else {
wp.customize.preview.bind( 'sync', function( events ) {
_send();
});
}
setTimeout( function() {
if ( !window.czr_skopes_sent ) {
_send();
}
}, 2500 );
});
};
// recursively try to load jquery every 200ms during 6s ( max 30 times )
var _doWhenCustomizeSettingsReady = function( attempts ) {
attempts = attempts || 0;
if ( typeof undefined !== typeof window._wpCustomizeSettings ) {
_wpCustomizeSettings.czr_new_skopes = <?php echo wp_json_encode( $_czr_skopes ); ?>;
_wpCustomizeSettings.czr_stylesheet = '<?php echo get_stylesheet(); ?>';
_wpCustomizeSettings.czr_query_params = <?php echo wp_json_encode($_czr_query_data); ?>;
_doSend();
} else if ( attempts < 30 ) {
setTimeout( function() {
attempts++;
_doWhenCustomizeSettingsReady( attempts );
}, 20 );
} else {
if ( window.console && window.console.log ) {
console.log('Nimble Builder problem : _wpCustomizeSettings is not defined');
}
}
};
_doWhenCustomizeSettingsReady();
<?php
$script = ob_get_clean();
wp_register_script( 'nb_print_skope_data_js', '');
wp_enqueue_script( 'nb_print_skope_data_js' );
wp_add_inline_script( 'nb_print_skope_data_js', $script );
}
// introduced in october 2019 for https://github.com/presscustomizr/nimble-builder/issues/401
private function _skp_get_json_export_ready_query_data() {
global $wp_query;
global $authordata;
add_filter('get_the_archive_title_prefix', '__return_false');
$archive_title = get_the_archive_title();
remove_filter('get_the_archive_title_prefix', '__return_false');
return [
'is_singular' => $wp_query->is_singular,
'is_archive' => $wp_query->is_archive,
'is_search' => $wp_query->is_search,
'is_attachment' => $wp_query->is_attachment,
'is_front_page' => is_front_page(),
'the_archive_title' => $archive_title,
'the_archive_description' => get_the_archive_description(),
'the_previous_post_link' => is_singular() ? get_previous_post_link( $format = '%link' ) : '',
'the_next_post_link' => is_singular() ? get_next_post_link( $format = '%link' ) : '',
'the_search_query' => get_search_query(),
'the_search_results_nb' => (int) $wp_query->found_posts,
'the_author_id' => isset( $authordata->ID ) ? $authordata->ID : 0,
'post_id' => get_the_ID(),
'query_vars' => $wp_query->query_vars
];
}
/* ------------------------------------------------------------------------- *
* CUSTOMIZE PREVIEW : BUILD SKOPES JSON
/* ------------------------------------------------------------------------- */
//generates the array of available scopes for a given context
//ex for a single post tagged #tag1 and #tag2 and categroized #cat1 :
//global
//all posts
//local
//posts tagged #tag1
//posts tagged #tag2
//posts categorized #cat1
//@return array()
//
//skp_get_skope_title() takes the following default args
//array(
// 'level' => '',
// 'meta_type' => null,
// 'long' => false,
// 'is_prefixed' => true
//)
private function _skp_get_json_export_ready_skopes() {
$skopes = array();
$_meta_type = skp_get_skope( 'meta_type', true );
//default properties of the scope object
$defaults = skp_get_default_skope_model();
//global and local and always sent
$skopes[] = wp_parse_args(
array(
'title' => skp_get_skope_title( array( 'level' => 'global' ) ),
'long_title' => skp_get_skope_title( array( 'level' => 'global', 'meta_type' => null, 'long' => true ) ),
'ctx_title' => skp_get_skope_title( array( 'level' => 'global', 'meta_type' => null, 'long' => true, 'is_prefixed' => false ) ),
'skope' => 'global',
'level' => '_all_'
),
$defaults
);
//SPECIAL GROUPS
//@todo
//GROUP
//Do we have a group ? => if yes, then there must be a meta type
if ( skp_get_skope('meta_type') ) {
$skopes[] = wp_parse_args(
array(
'title' => skp_get_skope_title( array( 'level' => 'group', 'meta_type' => $_meta_type ) ),
'long_title' => skp_get_skope_title( array( 'level' => 'group', 'meta_type' => $_meta_type, 'long' => true ) ),
'ctx_title' => skp_get_skope_title( array( 'level' => 'group', 'meta_type' => $_meta_type, 'long' => true, 'is_prefixed' => false ) ),
'skope' => 'group',
'level' => 'all_' . skp_get_skope('type'),
'skope_id' => skp_get_skope_id( 'group' )
),
$defaults
);
}
//LOCAL
$skopes[] = wp_parse_args(
array(
'title' => skp_get_skope_title( array( 'level' => 'local', 'meta_type' => $_meta_type ) ),
'long_title' => skp_get_skope_title( array( 'level' => 'local', 'meta_type' => $_meta_type, 'long' => true ) ),
'ctx_title' => skp_get_skope_title( array( 'level' => 'local', 'meta_type' => $_meta_type, 'long' => true, 'is_prefixed' => false ) ),
'skope' => 'local',
'level' => skp_get_skope(),
'obj_id' => skp_get_skope('id'),
'skope_id' => skp_get_skope_id( 'local' )
),
$defaults
);
return apply_filters( 'skp_json_export_ready_skopes', $skopes );
}
}//class
endif;
?><?php
if ( !class_exists( 'Flat_Skope_Clean_Final' ) ) :
final class Flat_Skope_Clean_Final extends Flat_Export_Skope_Data_And_Send_To_Panel {
// Fired in Flat_Skop_Base::__construct()
public function skp_schedule_cleaning_on_object_delete() {
add_action( 'delete_post', array( $this, 'skp_clean_skopified_posts' ) );
add_action( 'delete_term_taxonomy', array( $this, 'skp_clean_skopified_taxonomies' ) );
add_action( 'delete_user', array( $this, 'skp_clean_skopified_users' ) );
}
// Clean any associated skope post for all public post types : post, page, public cpt
// 'delete_post' Fires immediately before a post is deleted from the database.
// @see wp-includes/post.php
// don't have to return anything
public function skp_clean_skopified_posts( $postid ) {
$deletion_candidate = get_post( $postid );
if ( !$deletion_candidate || !is_object( $deletion_candidate ) )
return;
// Stop here if the post type is not considered "viewable".
// For built-in post types such as posts and pages, the 'public' value will be evaluated.
// For all others, the 'publicly_queryable' value will be used.
// For example, the 'revision' post type, which is purely internal and not skopable, won't pass this test.
if ( !is_post_type_viewable( $deletion_candidate->post_type ) )
return;
// Force the skope parts normally retrieved with skp_get_query_skope()
$skope_string = skp_get_skope( null, true, array(
'meta_type' => 'post',
'type' => $deletion_candidate->post_type,
'obj_id' => $postid
) );
// build a skope_id with the normalized function
$skope_id = skp_build_skope_id( array( 'skope_string' => $skope_string, 'skope_level' => 'local' ) );
// fetch the skope post id which, if exists, is set as a theme mod
$skope_post_id_candidate = get_theme_mod( $skope_id );
if ( $skope_post_id_candidate > 0 && get_post( $skope_post_id_candidate ) ) {
// permanently delete the skope post from db
wp_delete_post( $skope_post_id_candidate );
// remove the theme_mod
remove_theme_mod( $skope_id );
}
}
// 'delete_term_taxonomy' Fires immediately before a term taxonomy ID is deleted.
public function skp_clean_skopified_taxonomies( $term_id ) {
$deletion_candidate = get_term( $term_id );
if ( !$deletion_candidate || !is_object( $deletion_candidate ) )
return;
//error_log( print_r( $deletion_candidate, true ) );
// Force the skope parts normally retrieved with skp_get_query_skope()
$skope_string = skp_get_skope( null, true, array(
'meta_type' => 'tax',
'type' => $deletion_candidate->taxonomy,
'obj_id' => $term_id
) );
// build a skope_id with the normalized function
$skope_id = skp_build_skope_id( array( 'skope_string' => $skope_string, 'skope_level' => 'local' ) );
// fetch the skope post id which, if exists, is set as a theme mod
$skope_post_id_candidate = get_theme_mod( $skope_id );
if ( $skope_post_id_candidate > 0 && get_post( $skope_post_id_candidate ) ) {
// permanently delete the skope post from db
wp_delete_post( $skope_post_id_candidate );
// remove the theme_mod
remove_theme_mod( $skope_id );
//error_log( 'SUCCESSFULLY REMOVED SKOPE POST ID ' . $skope_post_id_candidate . ' AND THEME MOD ' . $skope_id );
}
}
// 'delete_user' Fires immediately before a user is deleted from the database.
public function skp_clean_skopified_users( $user_id ) {
// Force the skope parts normally retrieved with skp_get_query_skope()
$skope_string = skp_get_skope( null, true, array(
'meta_type' => 'user',
'type' => 'author',
'obj_id' => $user_id
) );
// build a skope_id with the normalized function
$skope_id = skp_build_skope_id( array( 'skope_string' => $skope_string, 'skope_level' => 'local' ) );
// fetch the skope post id which, if exists, is set as a theme mod
$skope_post_id_candidate = get_theme_mod( $skope_id );
if ( $skope_post_id_candidate > 0 && get_post( $skope_post_id_candidate ) ) {
// permanently delete the skope post from db
wp_delete_post( $skope_post_id_candidate );
// remove the theme_mod
remove_theme_mod( $skope_id );
//error_log( 'SUCCESSFULLY REMOVED SKOPE POST ID ' . $skope_post_id_candidate . ' AND THEME MOD ' . $skope_id );
}
}
}//class
endif;
?>
@@ -0,0 +1,35 @@
<?php
// @return void()
function nimble_register_location( $location, $params = array() ) {
if ( empty( $location ) || !is_string( $location ) )
return;
\Nimble\register_location( $location, $params );
}
//@param $locations. mixed type
//@param $options (array)$options = wp_parse_args( $options, array(
// 'fallback_location' => null, // Typically set as 'loop_start' in the nimble templates
// ));
function render_nimble_locations( $locations, $options = array() ) {
\Nimble\render_nimble_locations( $locations, $options );
}
function nimble_get_content_as_json() {
$skope_id = \Nimble\skp_get_skope_id();
// bail now if called before skope_id is set (before @hook 'wp')
if ( empty( $skope_id ) || '_skope_not_set_' === $skope_id )
return '{}';
$global_sections = \Nimble\sek_get_skoped_seks( NIMBLE_GLOBAL_SKOPE_ID );
$local_sections = \Nimble\sek_get_skoped_seks( $skope_id );
$raw_content = \Nimble\sek_sniff_and_decode_richtext([
'local_sections' => $local_sections,
'global_sections' => $global_sections
]);
return wp_json_encode( $raw_content );
}
function nimble_allow_display_attribute( $styles ){
$styles[] = 'display';
return $styles;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,935 @@
<?php
add_action( 'customize_controls_print_footer_scripts', '\Nimble\sek_print_nimble_input_templates' );
function sek_print_nimble_input_templates() {
// data structure :
// {
// input_type : input_type,
// input_data : input_data,
// input_id : input_id,
// item_model : item_model,
// input_tmpl : wp.template( 'nimble-input___' + input_type )
// }
?>
<script type="text/html" id="tmpl-nimble-input-wrapper">
<# var css_attr = serverControlParams.css_attr,
input_data = data.input_data,
input_type = input_data.input_type,
is_width_100 = true === input_data['width-100'];
// some inputs have a width of 100% even if not specified in the input_data
if ( _.contains( ['color', 'radio', 'textarea'], input_type ) ) {
is_width_100 = true;
}
var width_100_class = is_width_100 ? 'width-100' : '',
hidden_class = 'hidden' === input_type ? 'hidden' : '',
data_transport_attr = !_.isEmpty( input_data.transport ) ? 'data-transport="' + input_data.transport + '"' : '',
input_width = !_.isEmpty( input_data.input_width ) ? input_data.input_width : '';
#>
<div class="{{css_attr.sub_set_wrapper}} {{width_100_class}} {{hidden_class}}" data-input-type="{{input_type}}" <# print(data_transport_attr); #>>
<# if ( input_data.html_before ) { #>
<div class="czr-html-before"><# print(input_data.html_before); #></div>
<# } #>
<# if ( input_data.notice_before_title ) { #>
<span class="czr-notice"><# print(input_data.notice_before_title); #></span><br/>
<# } #>
<# if ( 'hidden' !== input_type ) { #>
<# var title_width = !_.isEmpty( input_data.title_width ) ? input_data.title_width : ''; #>
<div class="customize-control-title {{title_width}}"><# print( input_data.title ); #></div>
<# } #>
<# if ( input_data.notice_before ) { #>
<span class="czr-notice"><# print(input_data.notice_before); #></span>
<# } #>
<?php // nested template, see https://stackoverflow.com/questions/8938841/underscore-js-nested-templates#13649447 ?>
<?php // about print(), see https://underscorejs.org/#template ?>
<div class="czr-input {{input_width}}"><# if ( _.isFunction( data.input_tmpl ) ) { print(data.input_tmpl(data)); } #></div>
<# if ( input_data.notice_after ) { #>
<span class="czr-notice"><# print(input_data.notice_after); #></span>
<# } #>
<# if ( input_data.html_after ) { #>
<div class="czr-html-after"><# print(input_data.html_after); #></div>
<# } #>
</div><?php //css_attr.sub_set_wrapper ?>
</script>
<?php
/* ------------------------------------------------------------------------- *
* PARTS FOR MULTI-ITEMS MODULES
* fixes https://github.com/presscustomizr/nimble-builder/issues/473
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-crud-module-part">
<# var css_attr = serverControlParams.css_attr; #>
<button class="{{css_attr.open_pre_add_btn}}"><?php _e('Add New', 'text_doma'); ?> <span class="fas fa-plus-square"></span></button>
<div class="{{css_attr.pre_add_wrapper}}">
<div class="{{css_attr.pre_add_success}}"><p></p></div>
<div class="{{css_attr.pre_add_item_content}}">
<span class="{{css_attr.cancel_pre_add_btn}} button"><?php _e('Cancel', 'text_doma'); ?></span> <span class="{{css_attr.add_new_btn}} button"><?php _e('Add it', 'text_doma'); ?></span>
</div>
</div>
</script>
<script type="text/html" id="tmpl-nimble-rud-item-part">
<# var css_attr = serverControlParams.css_attr, is_sortable_class ='';
if ( data.is_sortable ) {
is_sortable_class = css_attr.item_sort_handle;
}
#>
<div class="{{css_attr.item_header}} {{is_sortable_class}} czr-custom-model">
<# if ( ( true === data.is_sortable ) ) { #>
<div class="{{css_attr.item_title}} "><h4>{{ data.title }}</h4></div>
<# } else { #>
<div class="{{css_attr.item_title}}"><h4>{{ data.title }}</h4></div>
<# } #>
<div class="{{css_attr.item_btns}}">
<a title="<?php _e('Edit', 'text_doma'); ?>" href="javascript:void(0);" class="fas fa-pencil-alt {{css_attr.edit_view_btn}}"></a>&nbsp;
<# if ( ( true === data.items_are_clonable ) ) { #>
<a title="<?php _e('Clone', 'text_doma'); ?>" href="javascript:void(0);" class="far fa-clone czr-clone-item"></a>&nbsp;
<# } #>
<a title="<?php _e('Remove', 'text_doma'); ?>" href="javascript:void(0);" class="fas fa-trash {{css_attr.display_alert_btn}}"></a>
</div>
<div class="{{css_attr.remove_alert_wrapper}}"></div>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* SUBTEMPLATES
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-subtemplate___range_number">
<?php
// we save the int value + unit
// we want to keep only the numbers when printing the tmpl
// dev note : value.replace(/\D+/g, '') : ''; not working because remove "." which we might use for em for example
?>
<#
var item_model = data.item_model,
input_id = data.input_id,
rawValue = _.has( item_model, input_id ) ? item_model[input_id] : null,
value,
unit;
value = _.isString( rawValue ) ? rawValue.replace(/px|em|%/g,'') : rawValue;
unit = _.isString( rawValue ) ? rawValue.replace(/[0-9]|\.|,/g, '') : 'px';
unit = _.isEmpty( unit ) ? 'px' : unit;
var _step = _.has( data.input_data, 'step' ) ? 'step="' + data.input_data.step + '"' : '',
_saved_unit = _.has( item_model, 'unit' ) ? 'data-unit="' + data.input_data.unit + '"' : '',
_min = _.has( data.input_data, 'min' ) ? 'min="' + data.input_data.min + '"': '',
_max = _.has( data.input_data, 'max' ) ? 'max="' + data.input_data.max + '"': '';
#>
<div class="sek-range-wrapper">
<input data-czrtype="{{input_id}}" type="hidden" data-sek-unit="{{unit}}"/>
<input class="sek-range-input" type="range" <# print(_step); #> <# print(_saved_unit); #> <# print(_min); #> <# print(_max); #>/>
</div>
<div class="sek-number-wrapper">
<input class="sek-pm-input" value="{{value}}" type="number" <# print(_step); #> <# print(_min); #> <# print(_max); #> >
</div>
</script>
<script type="text/html" id="tmpl-nimble-subtemplate___unit_picker">
<div class="sek-unit-wrapper">
<div aria-label="<?php _e('unit', 'text_doma'); ?>" class="sek-ui-button-group" role="group"><button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('pixels', 'text_doma'); ?>" data-sek-unit="px">px</button><button type="button" aria-pressed="false" class="sek-ui-button" title="em" data-sek-unit="em">em</button><button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('percents', 'text_doma'); ?>" data-sek-unit="%">%</button></div>
</div>
</script>
<script type="text/html" id="tmpl-nimble-subtemplate___number">
<div class="sek-simple-number-wrapper">
<input data-czrtype="{{data.input_id}}" class="sek-pm-input" value="{{value}}" type="number" >
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* CODE EDITOR
/* ------------------------------------------------------------------------- */
?>
<?php
// data structure :
// {
// input_type : input_type,
// input_data : input_data,
// input_id : input_id,
// item_model : item_model,
// input_tmpl : wp.template( 'nimble-input___' + input_type )
// }
?>
<script type="text/html" id="tmpl-nimble-input___code_editor">
<#
var item_model = data.item_model,
input_id = data.input_id,
value = _.has( item_model, input_id ) ? item_model[input_id] : null,
code_type = data.input_data.code_type;
#>
<textarea data-czrtype="{{input_id}}" data-editor-code-type="{{code_type}}" class="width-100" name="textarea" rows="10" cols=""></textarea>
</script>
<script type="text/html" id="tmpl-nimble-input___detached_tinymce_editor">
<#
var input_data = data.input_data,
item_model = data.item_model,
input_id = data.input_id,
value = _.has( item_model, input_id ) ? item_model[input_id] : null,
code_type = data.input_data.code_type;
#>
<button type="button" class="button text_editor-button" data-czr-control-id="{{ data.control_id }}" data-czr-input-id="{{input_id}}" data-czr-action="open-tinymce-editor"><?php _e('Edit', 'text_doma'); ?></button>&nbsp;
<button type="button" class="button text_editor-button" data-czr-control-id="{{ data.control_id }}" data-czr-input-id="{{input_id}}" data-czr-action="close-tinymce-editor"><?php _e('Hide editor', 'text_doma'); ?></button>
<input data-czrtype="{{input_id}}" type="hidden" value=""/>
</script>
<script type="text/html" id="tmpl-nimble-input___nimble_tinymce_editor">
<?php
// Added an id attribute for https://github.com/presscustomizr/nimble-builder/issues/403
// needed to instantiate wp.editor.initialize(...)
?>
<#
var item_model = data.item_model,
input_id = data.input_id,
value = _.has( item_model, input_id ) ? item_model[input_id] : null;
#>
<textarea id="textarea-{{input_id}}" data-czrtype="{{input_id}}" class="width-100" name="textarea" rows="10" cols=""></textarea>
</script>
<script type="text/html" id="tmpl-nimble-input___h_alignment">
<#
var input_id = data.input_id;
#>
<div class="sek-h-align-wrapper">
<input data-czrtype="{{input_id}}" type="hidden"/>
<div class="sek-align-icons">
<div data-sek-align="left" title="<?php _e('Align left', 'text_doma'); ?>"><i class="material-icons">format_align_left</i></div>
<div data-sek-align="center" title="<?php _e('Align center', 'text_doma'); ?>"><i class="material-icons">format_align_center</i></div>
<div data-sek-align="right" title="<?php _e('Align right', 'text_doma'); ?>"><i class="material-icons">format_align_right</i></div>
</div>
</div><?php // sek-h-align-wrapper ?>
</script>
<script type="text/html" id="tmpl-nimble-input___h_text_alignment">
<#
var input_id = data.input_id;
#>
<div class="sek-h-align-wrapper">
<input data-czrtype="{{input_id}}" type="hidden"/>
<div class="sek-align-icons">
<div data-sek-align="left" title="<?php _e('Align left', 'text_doma'); ?>"><i class="material-icons">format_align_left</i></div>
<div data-sek-align="center" title="<?php _e('Align center', 'text_doma'); ?>"><i class="material-icons">format_align_center</i></div>
<div data-sek-align="right" title="<?php _e('Align right', 'text_doma'); ?>"><i class="material-icons">format_align_right</i></div>
<div data-sek-align="justify" title="<?php _e('Justified', 'text_doma'); ?>"><i class="material-icons">format_align_justify</i></div>
</div>
</div><?php // sek-h-align-wrapper ?>
</script>
<script type="text/html" id="tmpl-nimble-input___nimblecheck">
<#
var input_id = data.input_id,
item_model = data.item_model,
value = _.has( item_model, input_id ) ? item_model[input_id] : false,
_checked = ( false != value ) ? "checked=checked" : '',
_uniqueId = wp.customize.czr_sektions.guid();
#>
<div class="nimblecheck-wrap">
<input id="nimblecheck-{{_uniqueId}}" data-czrtype="{{input_id}}" type="checkbox" <# print(_checked); #> class="nimblecheck-input">
<label for="nimblecheck-{{_uniqueId}}" class="nimblecheck-label">{{sektionsLocalizedData.i18n['Switch']}}</label>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* ALPHA COLOR
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___wp_color_alpha">
<#
var item_model = data.item_model,
input_id = data.input_id,
value = _.has( item_model, input_id ) ? item_model[input_id] : null;
#>
<input data-czrtype="{{data.input_id}}" class="width-100" data-alpha="true" type="text" value="{{value}}"></input>
</script>
<?php
/* ------------------------------------------------------------------------- *
* SIMPLE SELECT : USED FOR SELECT, FONT PICKER, ICON PICKER, ...
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___simpleselect">
<select data-czrtype="{{data.input_id}}"></select>
</script>
<?php
/* ------------------------------------------------------------------------- *
* SIMPLE SELECT WITH DEVICE SWITCHER
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___simpleselect_deviceswitcher">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<select></select>
</script>
<?php
/* ------------------------------------------------------------------------- *
* NUMBER
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___number_simple">
<#
var number_tmpl = wp.customize.CZR_Helpers.getInputSubTemplate( 'number' );
if ( _.isFunction( number_tmpl ) ) { print( number_tmpl( data ) ); }
#>
</script>
<?php
/* ------------------------------------------------------------------------- *
* RANGE
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___range_simple">
<div class="sek-range-with-unit-picker-wrapper sek-no-unit-picker">
<#
var range_tmpl = wp.customize.CZR_Helpers.getInputSubTemplate( 'range_number' );
if ( _.isFunction( range_tmpl ) ) { print( range_tmpl( data ) ); }
#>
</div>
</script>
<script type="text/html" id="tmpl-nimble-input___range_with_unit_picker">
<div class="sek-range-with-unit-picker-wrapper">
<#
var range_tmpl = wp.customize.CZR_Helpers.getInputSubTemplate( 'range_number' );
if ( _.isFunction( range_tmpl ) ) { print( range_tmpl( data ) ); }
var unit_tmpl = wp.customize.CZR_Helpers.getInputSubTemplate( 'unit_picker' );
if ( _.isFunction( unit_tmpl ) ) { print( unit_tmpl( data ) ); }
#>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* SPACING
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___spacing">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<div class="sek-spacing-wrapper">
<div class="sek-pad-marg-inner">
<div class="sek-pm-top-bottom-wrap sek-flex-justify-center">
<div class="sek-flex-center-stretch" data-sek-spacing="margin-top" title="<?php _e('Margin top', 'text_doma'); ?>">
<div class="sek-pm-input-parent">
<input class="sek-pm-input" value="" type="number" >
</div>
</div>
</div>
<div class="sek-pm-middle-wrap sek-flex-justify-center">
<div class="sek-flex-center-stretch sek-pm-margin-left" data-sek-spacing="margin-left" title="<?php _e('Margin left', 'text_doma'); ?>">
<div class="sek-pm-input-parent">
<input class="sek-pm-input" value="" type="number" >
</div>
</div>
<div class="sek-pm-padding-wrapper">
<div class="sek-flex-justify-center">
<div class="sek-flex-center-stretch" data-sek-spacing="padding-top" title="<?php _e('Padding top', 'text_doma'); ?>">
<div class="sek-pm-input-parent">
<input class="sek-pm-input" value="" type="number" >
</div>
</div>
</div>
<div class="sek-flex-justify-center sek-flex-space-between">
<div class="sek-flex-center-stretch" data-sek-spacing="padding-left" title="<?php _e('Padding left', 'text_doma'); ?>">
<div class="sek-pm-input-parent">
<input class="sek-pm-input" value="" type="number" >
</div>
</div>
<div class="sek-flex-center-stretch" data-sek-spacing="padding-right" title="<?php _e('Padding right', 'text_doma'); ?>">
<div class="sek-pm-input-parent">
<input class="sek-pm-input" value="" type="number" >
</div>
</div>
</div>
<div class="sek-flex-justify-center">
<div class="sek-flex-center-stretch" data-sek-spacing="padding-bottom" title="<?php _e('Padding bottom', 'text_doma'); ?>">
<div class="sek-pm-input-parent">
<input class="sek-pm-input" value="" type="number" >
</div>
</div>
</div>
</div>
<div class="sek-flex-center-stretch sek-pm-margin-right" data-sek-spacing="margin-right" title="<?php _e('Margin right', 'text_doma'); ?>">
<div class="sek-pm-input-parent">
<input class="sek-pm-input" value="" type="number" >
</div>
</div>
</div>
<div class="sek-pm-top-bottom-wrap sek-flex-justify-center">
<div class="sek-flex-center-stretch" data-sek-spacing="margin-bottom" title="<?php _e('Margin bottom', 'text_doma'); ?>">
<div class="sek-pm-input-parent">
<input class="sek-pm-input" value="" type="number" >
</div>
</div>
</div>
</div><?php //sek-pad-marg-inner ?>
<#
var unit_tmpl = wp.customize.CZR_Helpers.getInputSubTemplate( 'unit_picker' );
if ( _.isFunction( unit_tmpl ) ) { print( unit_tmpl( data ) ); }
#>
<div class="reset-spacing-wrap"><span class="sek-do-reset"><?php _e('Reset all spacing', 'text_doma' ); ?></span></div>
</div><?php // sek-spacing-wrapper ?>
</script>
<?php
/* ------------------------------------------------------------------------- *
* TEXT
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___text">
<# var input_data = data.input_data; #>
<input data-czrtype="{{data.input_id}}" type="text" value="" placeholder="<# print(input_data.placeholder); #>"></input>
</script>
<?php
/* ------------------------------------------------------------------------- *
* CONTENT PICKER
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___content_picker">
<span data-czrtype="{{data.input_id}}"></span>
</script>
<?php
/* ------------------------------------------------------------------------- *
* UPLOAD
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___upload">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<div class="{{serverControlParams.css_attr.img_upload_container}}"></div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* BORDERS
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___borders">
<div class="sek-borders">
<div class="sek-border-type-wrapper">
<div aria-label="unit" class="sek-ui-button-group" role="group"><button type="button" aria-pressed="true" class="sek-ui-button is-selected" title="<?php _e('All', 'text_doma'); ?>" data-sek-border-type="_all_"><?php _e('All', 'text_doma'); ?></button><button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Left', 'text_doma'); ?>" data-sek-border-type="left"><?php _e('Left', 'text_doma'); ?></button><button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Top', 'text_doma'); ?>" data-sek-border-type="top"><?php _e('Top', 'text_doma'); ?></button><button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Right', 'text_doma'); ?>" data-sek-border-type="right"><?php _e('Right', 'text_doma'); ?></button><button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Bottom', 'text_doma'); ?>" data-sek-border-type="bottom"><?php _e('Bottom', 'text_doma'); ?></button></div>
</div>
<div class="sek-range-unit-wrapper">
<#
var range_tmpl = wp.customize.CZR_Helpers.getInputSubTemplate( 'range_number' );
if ( _.isFunction( range_tmpl ) ) { print( range_tmpl( data ) ); }
var unit_tmpl = wp.customize.CZR_Helpers.getInputSubTemplate( 'unit_picker' );
if ( _.isFunction( unit_tmpl ) ) { print( unit_tmpl( data ) ); }
#>
</div>
<div class="sek-color-wrapper">
<div class="sek-color-picker"><input class="sek-alpha-color-input" data-alpha="true" type="text" value=""/></div>
<div class="sek-reset-button"><button type="button" class="button sek-reset-button sek-float-right"><?php _e('Reset', 'text_doma'); ?></button></div>
</div>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* BORDER RADIUS
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___border_radius">
<div class="sek-borders">
<div class="sek-border-type-wrapper">
<div aria-label="unit" class="sek-ui-button-group sek-float-left" role="group"><button type="button" aria-pressed="true" class="sek-ui-button is-selected" title="<?php _e('All', 'text_doma'); ?>" data-sek-radius-type="_all_"><?php _e('All', 'text_doma'); ?></button><button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Top left', 'text_doma'); ?>" data-sek-radius-type="top_left"><i class="material-icons">border_style</i></button><button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Top right', 'text_doma'); ?>" data-sek-radius-type="top_right"><i class="material-icons">border_style</i></button><button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Bottom right', 'text_doma'); ?>" data-sek-radius-type="bottom_right"><i class="material-icons">border_style</i></button><button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Bottom left', 'text_doma'); ?>" data-sek-radius-type="bottom_left"><i class="material-icons">border_style</i></button></div>
<div class="sek-reset-button"><button type="button" class="button sek-reset-button sek-float-right"><?php _e('Reset', 'text_doma'); ?></button></div>
</div>
<div class="sek-range-unit-wrapper">
<#
var range_tmpl = wp.customize.CZR_Helpers.getInputSubTemplate( 'range_number' );
if ( _.isFunction( range_tmpl ) ) { print( range_tmpl( data ) ); }
var unit_tmpl = wp.customize.CZR_Helpers.getInputSubTemplate( 'unit_picker' );
if ( _.isFunction( unit_tmpl ) ) { print( unit_tmpl( data ) ); }
#>
</div>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* MODULE OPTION SWITCHER
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___module_option_switcher">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<div class="sek-content-type-wrapper">
<div aria-label="<?php _e('Option type', 'text_doma'); ?>" class="sek-ui-button-group" role="group">
<button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Module Content', 'text_doma'); ?>" data-sek-option-type="content"><span class="sek-wrap-opt-switch-btn"><i class="material-icons">create</i><span><?php _e('Module Content', 'text_doma'); ?></span></span></button>
<button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Module Settings', 'text_doma'); ?>" data-sek-option-type="settings"><span class="sek-wrap-opt-switch-btn"><i class="material-icons">tune</i><span><?php _e('Module Settings', 'text_doma'); ?></span></span></button>
</div>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* CONTENT SWITCHER
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___content_type_switcher">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<div class="sek-content-type-wrapper">
<div aria-label="<?php _e('Content type', 'text_doma'); ?>" class="sek-ui-button-group" role="group">
<button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Pick a section', 'text_doma'); ?>" data-sek-content-type="section"><?php _e('Pick a section', 'text_doma'); ?></button>
<button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Pick a module', 'text_doma'); ?>" data-sek-content-type="module"><?php _e('Pick a module', 'text_doma'); ?></button>
<button type="button" aria-pressed="false" class="sek-ui-button" title="<?php _e('Pick a template', 'text_doma'); ?>" data-sek-content-type="template"><?php _e('Pick a template', 'text_doma'); ?>&nbsp;<span class="sek-new-label"><?php _e('New!', 'text_doma'); ?></span></button>
</div>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* MODULE PICKER
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___module_picker">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<div class="sek-content-type-wrapper">
<#
var icon_img_html = '<i style="color:red">Missing Icon</i>', icon_img_src;
_.each( sektionsLocalizedData.moduleCollection, function( rawModData ) {
//normalizes the module params
var modData = jQuery.extend( true, {}, rawModData ),
defaultModParams = {
'content-type' : 'module',
'content-id' : '',
'title' : '',
'icon' : '',
'font_icon' : '',
'active' : true,
'is_pro' : false
},
modData = jQuery.extend( defaultModParams, modData );
var _assets_version = "<?php echo esc_attr(NIMBLE_ASSETS_VERSION); ?>";
if ( !_.isEmpty( modData['icon'] ) ) {
if ( 'http' === modData['icon'].substring(0, 4) ) {
icon_img_src = modData['icon'];
} else {
icon_img_src = sektionsLocalizedData.moduleIconPath + modData['icon'];
}
icon_img_src = icon_img_src + '?v=' + _assets_version;
icon_img_html = '<img draggable="false" title="' + modData['title'] + '" alt="' + modData['title'] + '" class="nimble-module-icons" src="' + icon_img_src + '"/>';
} else if ( !_.isEmpty( modData['font_icon'] ) ) {
icon_img_html = modData['font_icon'];
}
var title_attr = "<?php _e('Drag and drop or double-click to insert in your chosen target element.', 'text_doma'); ?>",
font_icon_class = !_.isEmpty( modData['font_icon'] ) ? 'is-font-icon' : '',
is_draggable = true !== modData['active'] ? 'false' : 'true',
is_pro_module = modData['is_pro'] ? 'yes' : 'no';
if ( true !== modData['active'] ) {
if ( modData['is_pro'] ) {
title_attr = "<?php _e('Pro feature', 'text_doma'); ?>";
} else {
title_attr = "<?php _e('Available soon ! This module is currently in beta, you can activate it in Site Wide Options > Beta features', 'text_doma'); ?>";
}
}
// "data-sek-eligible-for-module-dropzones" was introduced for https://github.com/presscustomizr/nimble-builder/issues/540
#>
<div draggable="{{is_draggable}}" data-sek-eligible-for-module-dropzones="true" data-sek-content-type="{{modData['content-type']}}" data-sek-content-id="{{modData['content-id']}}" title="{{title_attr}}" data-sek-is-pro-module="{{is_pro_module}}"><div class="sek-module-icon {{font_icon_class}}"><# print(icon_img_html); #></div><div class="sek-module-title"><div class="sek-centered-module-title">{{modData['title']}}</div></div>
<#
if ( 'yes' === is_pro_module ) {
var pro_img_html = '<div class="sek-is-pro"><img src="' + sektionsLocalizedData.czrAssetsPath + 'sek/img/pro_orange.svg" alt="Pro feature"/></div>';
print(pro_img_html);
}
#>
</div>
<#
});//_.each
#>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* SECTION PICKER
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___section_picker">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<div class="sek-content-type-wrapper">
<#
// June 2020 : the section collection is passed only when rendering pre-built sections
// @see sek_register_prebuilt_section_modules() and sek_get_sections_registration_params()
// For user saved sections, the rendering is done in javascript, not here
// @see @see _dev_control/modules/ui/_10_0_0_UI_module_and_section_pickers.js
var section_collection = ( data.input_data && data.input_data.section_collection ) ? data.input_data.section_collection : [];
// if ( _.isEmpty( section_collection ) ) {
// wp.customize.errare('Error in js template tmpl-nimble-input___section_picker => missing section collection');
// return;
// }
var img_version = sektionsLocalizedData.isDevMode ? Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1) : sektionsLocalizedData.nimbleVersion;
// FOR PREBUILT SECTIONS ONLY, user sections are rendered in javascript @see _dev_control/modules/ui/_10_0_0_UI_module_and_section_pickers.js
_.each( section_collection, function( rawSecParams ) {
//normalizes the params
var section_type = 'content',
secParams = jQuery.extend( true, {}, rawSecParams ),
defaultParams = {
'content-id' : '',
'thumb' : '',
'title' : '',
'section_type' : '',
'height': '',
'active' : true,
'is_pro' : false,
'demo_url' : false
},
secParams = jQuery.extend( defaultParams, secParams );
if ( !_.isEmpty( secParams['section_type'] ) ) {
section_type = secParams['section_type'];
}
var thumbUrl = [ sektionsLocalizedData.baseUrl , '/assets/img/section_assets/thumbs/', secParams['thumb'] , '?ver=' , img_version ].join(''),
styleAttr = 'background: url(' + thumbUrl + ') 50% 50% / cover no-repeat;',
is_draggable = true !== secParams['active'] ? 'false' : 'true',
is_pro_section = secParams['is_pro'] ? 'yes' : 'no';
if ( !_.isEmpty(secParams['height']) ) {
styleAttr = styleAttr + 'height:' + secParams['height'] + ';';
}
#>
<div draggable="{{is_draggable}}" data-sek-content-type="preset_section" data-sek-content-id="{{secParams['content-id']}}" style="<# print(styleAttr); #>" title="{{secParams['title']}}" data-sek-section-type="{{section_type}}" data-sek-is-pro-section="{{is_pro_section}}"><div class="sek-overlay"></div>
<#
if ( 'yes' === is_pro_section ) {
var pro_img_html = '<div class="sek-is-pro"><img src="' + sektionsLocalizedData.czrAssetsPath + 'sek/img/pro_orange.svg" alt="Pro feature"/></div>';
print(pro_img_html);
}
var demo_title = "<?php _e('View in live demo', 'text_doma'); ?>";
if ( secParams['demo_url'] && -1 === secParams['demo_url'].indexOf('http') ) { #>
<div class="sek-demo-link"><a href="https://nimblebuilder.com/nimble-builder-sections?utm_source=usersite&amp;utm_medium=link&amp;utm_campaign=section_demos{{secParams['demo_url']}}" target="_blank" rel="noopener noreferrer">{{demo_title}} <i class="fas fa-external-link-alt"></i></a></div>
<# } else if ( secParams['demo_url'] ) { #>
<div class="sek-demo-link"><a href="{{secParams['demo_url']}}" target="_blank" rel="noopener noreferrer">{{demo_title}} <i class="fas fa-external-link-alt"></i></a></div>
<# } #>
</div>
<#
});//_.each
#>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* BACKGROUND POSITION INPUT
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___bg_position">
<div class="sek-bg-pos-wrapper">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<label class="sek-bg-pos">
<input type="radio" name="sek-bg-pos" value="top_left">
<span>
<svg width="24" height="24">
<path id="sek-pth" fill-rule="evenodd" d="M14.96 16v-1h-1v-1h-1v-1h-1v-1h-1v-1.001h-1V14h-1v-4-1h5v1h-3v.938h1v.999h1v1h1v1.001h1v1h1V16h-1z" class="sek-svg-bg-pos">
</path>
</svg>
</span>
</label>
<label class="sek-bg-pos">
<input type="radio" name="sek-bg-pos" value="top">
<span>
<svg width="24" height="24">
<path id="sek-pth" fill-rule="evenodd" d="M14.969 12v-1h-1v-1h-1v7h-1v-7h-1v1h-1v1h-1v-1.062h1V9.937h1v-1h1V8h1v.937h1v1h1v1.001h1V12h-1z" class="sek-svg-bg-pos">
</path>
</svg>
</span>
</label>
<label class="sek-bg-pos">
<input type="radio" name="sek-bg-pos" value="top_right">
<span>
<svg width="24" height="24">
<path id="sek-pth" fill-rule="evenodd" d="M9.969 16v-1h1v-1h1v-1h1v-1h1v-1.001h1V14h1v-4-1h-1-4v1h3v.938h-1v.999h-1v1h-1v1.001h-1v1h-1V16h1z" class="sek-svg-bg-pos">
</path>
</svg>
</span>
</label>
<label class="sek-bg-pos">
<input type="radio" name="sek-bg-pos" value="left">
<span>
<svg width="24" height="24">
<path id="sek-pth" fill-rule="evenodd" d="M11.469 9.5h-1v1h-1v1h7v1h-7v1h1v1h1v1h-1.063v-1h-1v-1h-1v-1h-.937v-1h.937v-1h1v-1h1v-1h1.063v1z" class="sek-svg-bg-pos">
</path>
</svg>
</span>
</label>
<label class="sek-bg-pos">
<input type="radio" name="sek-bg-pos" value="center">
<span>
<svg width="24" height="24">
<path id="sek-pth" fill-rule="evenodd" d="M12 9a3 3 0 1 1 0 6 3 3 0 0 1 0-6z" class="sek-svg-bg-pos">
</path>
</svg>
</span>
</label>
<label class="sek-bg-pos">
<input type="radio" name="sek-bg-pos" value="right">
<span>
<svg width="24" height="24">
<path id="sek-pth" fill-rule="evenodd" d="M12.469 14.5h1v-1h1v-1h-7v-1h7v-1h-1v-1h-1v-1h1.062v1h1v1h1v1h.938v1h-.938v1h-1v1h-1v1h-1.062v-1z" class="sek-svg-bg-pos">
</path>
</svg>
</span>
</label>
<label class="sek-bg-pos">
<input type="radio" name="sek-bg-pos" value="bottom_left">
<span>
<svg width="24" height="24">
<path id="sek-pth" fill-rule="evenodd" d="M14.969 9v1h-1v1h-1v1h-1v1h-1v1.001h-1V11h-1v5h5v-1h-3v-.938h1v-.999h1v-1h1v-1.001h1v-1h1V9h-1z" class="sek-svg-bg-pos">
</path>
</svg>
</span>
</label>
<label class="sek-bg-pos">
<input type="radio" name="sek-bg-pos" value="bottom">
<span>
<svg width="24" height="24">
<path id="sek-pth" fill-rule="evenodd" d="M9.969 13v1h1v1h1V8h1v7h1v-1h1v-1h1v1.063h-1v.999h-1v1.001h-1V17h-1v-.937h-1v-1.001h-1v-.999h-1V13h1z" class="sek-svg-bg-pos">
</path>
</svg>
</span>
</label>
<label class="sek-bg-pos">
<input type="radio" name="sek-bg-pos" value="bottom_right">
<span>
<svg width="24" height="24">
<path id="sek-pth" fill-rule="evenodd" d="M9.969 9v1h1v1h1v1h1v1h1v1.001h1V11h1v5h-1-4v-1h3v-.938h-1v-.999h-1v-1h-1v-1.001h-1v-1h-1V9h1z" class="sek-svg-bg-pos">
</path>
</svg>
</span>
</label>
</div><?php // sek-bg-pos-wrapper ?>
</script>
<?php
/* ------------------------------------------------------------------------- *
* BUTTON CHOICE
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___buttons_choice">
<div class="sek-button-choice-wrapper">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<div aria-label="<?php _e('unit', 'text_doma'); ?>" class="sek-ui-button-group sek-float-right" role="group">
<#
var input_data = data.input_data;
if ( _.isEmpty( input_data.choices ) || !_.isObject( input_data.choices ) ) {
wp.customize.errare( 'Error in buttons_choice js tmpl => missing or invalid input_data.choices');
} else {
_.each( input_data.choices, function( label, choice ) {
#><button type="button" aria-pressed="false" class="sek-ui-button" title="{{label}}" data-sek-choice="{{choice}}">{{label}}</button><#
});
}
#>
</div>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* MULTISELECT, CATEGORY PICKER
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___multiselect">
<select multiple="multiple" data-czrtype="{{data.input_id}}"></select>
</script>
<?php
/* ------------------------------------------------------------------------- *
* GRID LAYOUT
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___grid_layout">
<div class="sek-grid-layout-wrapper">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<div class="sek-grid-icons">
<div data-sek-grid-layout="list" title="<?php _e('List layout', 'text_doma'); ?>"><i class="material-icons">view_list</i></div>
<div data-sek-grid-layout="grid" title="<?php _e('Grid layout', 'text_doma'); ?>"><i class="material-icons">view_module</i></div>
</div>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* VERTICAL ALIGNMENT
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___v_alignment">
<div class="sek-v-align-wrapper">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<div class="sek-align-icons">
<div data-sek-align="top" title="<?php _e('Align top', 'text_doma'); ?>"><i class="material-icons">vertical_align_top</i></div>
<div data-sek-align="center" title="<?php _e('Align center', 'text_doma'); ?>"><i class="material-icons">vertical_align_center</i></div>
<div data-sek-align="bottom" title="<?php _e('Align bottom', 'text_doma'); ?>"><i class="material-icons">vertical_align_bottom</i></div>
</div>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* REMOVE BUTTON
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___reset_button">
<div class="sek-button-choice-wrapper">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<button type="button" aria-pressed="false" class="sek-ui-button sek-float-right" title="<?php _e('Remove now', 'text_doma'); ?>" data-sek-reset-scope="{{data.input_data.scope}}"><?php _e('Remove now', 'text_doma'); ?></button>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* REFRESH PREVIEW BUTTON
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___refresh_preview_button">
<div class="sek-button-choice-wrapper">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<button type="button" aria-pressed="false" class="sek-refresh-button sek-float-right button button-primary" title="<?php _e('Refresh preview', 'text_doma'); ?>"><?php _e('Refresh preview', 'text_doma'); ?></button>
</div>
</script>
<?php
/* ------------------------------------------------------------------------- *
* REVISION HISTORY / HIDDEN
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___revision_history">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
</script>
<?php
/* ------------------------------------------------------------------------- *
* IMPORT / EXPORT
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___import_export">
<div class="sek-export-btn-wrap">
<div class="customize-control-title width-100"><?php //_e('Export', 'text_doma'); ?></div>
<button type="button" class="button" data-czr-control-id="{{ data.control_id }}" data-czr-input-id="{{data.input_id}}" data-czr-action="sek-export"><?php _e('Export', 'text_doma' ); ?></button>
</div>
<div class="sek-import-btn-wrap">
<div class="customize-control-title width-100"><?php _e('IMPORT', 'text_doma'); ?></div>
<span class="czr-notice"><?php _e('Select the file to import and click on Import button.', 'text_doma' ); ?></span>
<span class="czr-notice"><?php _e('Be sure to import a file generated with Nimble Builder export system.', 'text_doma' ); ?></span>
<?php // <DIALOG FOR LOCAL IMPORT> ?>
<div class="czr-import-dialog czr-local-import notice notice-info">
<div class="czr-import-message"><?php _e('Some of the imported sections need a location that is not active on this page. Sections in missing locations will not be rendered. You can continue importing or assign those sections to a contextually active location.', 'text_doma' ); ?></div>
<button type="button" class="button" data-czr-control-id="{{ data.control_id }}" data-czr-input-id="{{data.input_id}}" data-czr-action="sek-import-as-is"><?php _e('Import without modification', 'text_doma' ); ?></button>
<button type="button" class="button" data-czr-control-id="{{ data.control_id }}" data-czr-input-id="{{data.input_id}}" data-czr-action="sek-import-assign"><?php _e('Import in existing locations', 'text_doma' ); ?></button>
<button type="button" class="button" data-czr-control-id="{{ data.control_id }}" data-czr-input-id="{{data.input_id}}" data-czr-action="sek-cancel-import"><?php _e('Cancel import', 'text_doma' ); ?></button>
</div>
<?php // </DIALOG FOR LOCAL IMPORT> ?>
<?php // <DIALOG FOR GLOBAL IMPORT> ?>
<div class="czr-import-dialog czr-global-import notice notice-info">
<div class="czr-import-message"><?php _e('Some of the imported sections need a location that is not active on this page. For example, if you are importing a global header footer, you need to activate the Nimble site wide header and footer, in "Site wide header and footer" options.', 'text_doma' ); ?></div>
<button type="button" class="button" data-czr-control-id="{{ data.control_id }}" data-czr-input-id="{{data.input_id}}" data-czr-action="sek-import-as-is"><?php _e('Import', 'text_doma' ); ?></button>
<button type="button" class="button" data-czr-control-id="{{ data.control_id }}" data-czr-input-id="{{data.input_id}}" data-czr-action="sek-cancel-import"><?php _e('Cancel import', 'text_doma' ); ?></button>
</div>
<?php // </DIALOG FOR GLOBAL IMPORT> ?>
<div class="sek-uploading"><?php _e( 'Uploading...', 'text_doma' ); ?></div>
<input type="file" name="sek-import-file" class="sek-import-file" />
<input type="hidden" name="sek-skope" value="{{data.input_data.scope}}" />
<button type="button" class="button disabled" data-czr-control-id="{{ data.control_id }}" data-czr-input-id="{{data.input_id}}" data-czr-action="sek-pre-import"><?php _e('Import', 'text_doma' ); ?></button>
</div>
<input data-czrtype="{{data.input_id}}" type="hidden" value="{{data.value}}"/>
</script>
<?php
/* ------------------------------------------------------------------------- *
* INACTIVE
* Sept 2020 introduced an "inactive" input type in order to display pro info for Nimble
* this input should be "hidden" type, and should not trigger an API change.
* when working on https://github.com/presscustomizr/nimble-builder-pro/issues/67
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___inactive">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
</script>
<?php
/* ------------------------------------------------------------------------- *
* SITE TMPL PICKER
/* ------------------------------------------------------------------------- */
?>
<script type="text/html" id="tmpl-nimble-input___site_tmpl_picker">
<div class="sek-button-choice-wrapper">
<input data-czrtype="{{data.input_id}}" type="hidden"/>
<div class="sek-ui-button-group" role="group">
<button type="button" aria-pressed="false" class="sek-ui-button sek-remove-site-tmpl" title="<?php _e('Reset to default', 'text_doma'); ?>"><?php _e('Reset to default', 'text_doma'); ?></button>
<button type="button" aria-pressed="false" class="sek-ui-button sek-pick-site-tmpl" title="<?php _e('Pick a template', 'text_doma'); ?>" data-sek-group-scope="{{data.input_id}}"><?php _e('Pick a template', 'text_doma'); ?></button>
</div>
</div>
</script>
<?php
}//sek_print_nimble_input_templates() @hook 'customize_controls_print_footer_scripts'
?>
@@ -0,0 +1,81 @@
<?php
/* ------------------------------------------------------------------------- *
* SETUP DYNAMIC SERVER REGISTRATION FOR SETTING
/* ------------------------------------------------------------------------- */
// Fired @'after_setup_theme:20'
if ( !class_exists( 'SEK_CZR_Dyn_Register' ) ) :
class SEK_CZR_Dyn_Register {
static $instance;
public $sanitize_callbacks = array();// <= will be populated to cache the callbacks when invoking sek_get_module_sanitize_callbacks().
public static function get_instance( $params ) {
if ( !isset( self::$instance ) && !( self::$instance instanceof SEK_CZR_Dyn_Register ) )
self::$instance = new SEK_CZR_Dyn_Register( $params );
return self::$instance;
}
function __construct( $params = array() ) {
// Schedule the loading the skoped settings class
add_action( 'customize_register', array( $this, 'load_nimble_setting_class' ) );
add_filter( 'customize_dynamic_setting_args', array( $this, 'set_dyn_setting_args' ), 10, 2 );
add_filter( 'customize_dynamic_setting_class', array( $this, 'set_dyn_setting_class') , 10, 3 );
}//__construct
//@action 'customize_register'
function load_nimble_setting_class() {
require_once( NIMBLE_BASE_PATH . '/inc/sektions/seks_setting_class.php' );
}
//@filter 'customize_dynamic_setting_args'
function set_dyn_setting_args( $setting_args, $setting_id ) {
// shall start with "nimble___" or "nimble_global_opts"
// those are the setting that will actually be saved in DB :
// - sektion collections ( local and global skope )
// - global options
// - site template options
if ( 0 === strpos( $setting_id, NIMBLE_OPT_PREFIX_FOR_SEKTION_COLLECTION ) || 0 === strpos( $setting_id, NIMBLE_OPT_NAME_FOR_GLOBAL_OPTIONS ) ) {
//sek_error_log( 'DYNAMICALLY REGISTERING SEK SETTING => ' . $setting_id, $setting_args);
return array(
'transport' => 'refresh',
'type' => 'option',
'default' => array(),
// Only the section collections are sanitized on save
'sanitize_callback' => 0 === strpos( $setting_id, NIMBLE_OPT_PREFIX_FOR_SEKTION_COLLECTION ) ? '\Nimble\sek_sektion_collection_sanitize_cb' : null
//'validate_callback' => '\Nimble\sek_sektion_collection_validate_cb'
);
} else if ( 0 === strpos( $setting_id, NIMBLE_PREFIX_FOR_SETTING_NOT_SAVED ) ) {
//sek_error_log( 'DYNAMICALLY REGISTERING SEK SETTING => ' . $setting_id, $setting_args);
return array(
'transport' => 'refresh',
'type' => '_nimble_ui_',//won't be saved as is,
'default' => array(),
//'sanitize_callback' => array( $this, 'sanitize_callback' ),
//'validate_callback' => '\Nimble\sek_sektion_collection_validate_cb'
);
}
return $setting_args;
//return wp_parse_args( array( 'default' => array() ), $setting_args );
}
//@filter 'customize_dynamic_setting_class'
// We use a custom setting class only for the section collections ( local and global ), not for global options and site template options
function set_dyn_setting_class( $class, $setting_id, $args ) {
//sek_error_log( 'REGISTERING CLASS DYNAMICALLY for setting =>' . $setting_id );
// Setting class for NB global options and Site Template options
if ( 0 === strpos( $setting_id, NIMBLE_OPT_NAME_FOR_GLOBAL_OPTIONS ) ) {
return '\Nimble\Nimble_Options_Setting';
}
// Setting class for NB sektion collections => shall start with 'nimble___'
if ( 0 === strpos( $setting_id, NIMBLE_OPT_PREFIX_FOR_SEKTION_COLLECTION ) ) {
return '\Nimble\Nimble_Collection_Setting';
}
return $class;
}
}//class
endif;
?>
@@ -0,0 +1,327 @@
<?php
////////////////////////////////////////////////////////////////
// GENERIC HELPER FIRED IN ALL AJAX CALLBACKS
// @param $params = array('check_nonce' => true )
function sek_do_ajax_pre_checks( $params = array() ) {
$params = wp_parse_args( $params, array( 'check_nonce' => true ) );
if ( $params['check_nonce'] ) {
$action = 'save-customize_' . get_stylesheet();
if ( !check_ajax_referer( $action, 'nonce', false ) ) {
wp_send_json_error( array(
'code' => 'invalid_nonce',
'message' => __( __CLASS__ . '::' . __FUNCTION__ . ' => check_ajax_referer() failed.' ),
) );
}
}
if ( !is_user_logged_in() ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => unauthenticated' );
}
if ( !current_user_can( 'customize' ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => user_cant_edit_theme_options');
}
if ( !current_user_can( 'customize' ) ) {
status_header( 403 );
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => customize_not_allowed' );
} else if ( !isset( $_SERVER['REQUEST_METHOD'] ) || 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
status_header( 405 );
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => bad_method' );
}
}//sek_do_ajax_pre_checks()
// IMPORT IMG
add_action( 'wp_ajax_sek_import_attachment', '\Nimble\sek_ajax_import_attachment' );
// Fetches the list of revision for a given skope_id
add_action( 'wp_ajax_sek_get_revision_history', '\Nimble\sek_get_revision_history' );
// Fetches the revision for a given post id
add_action( 'wp_ajax_sek_get_single_revision', '\Nimble\sek_get_single_revision' );
// Fetches the category collection to generate the options for a select input
// @see api.czrInputMap.category_picker
add_action( 'wp_ajax_sek_get_post_categories', '\Nimble\sek_get_post_categories' );
// Fetches the code editor params to generate the options for a textarea input
// @see api.czrInputMap.code_editor
add_action( 'wp_ajax_sek_get_code_editor_params', '\Nimble\sek_get_code_editor_params' );
add_action( 'wp_ajax_sek_postpone_feedback', '\Nimble\sek_postpone_feedback_notification' );
// <AJAX TO FETCH INPUT COMPONENTS>
// this dynamic filter is declared on wp_ajax_ac_get_template in the czr_base_fmk
// It allows us to populate the server response with the relevant module html template
// $html = apply_filters( "ac_set_ajax_czr_tmpl___{$module_type}", '', $tmpl );
add_filter( "ac_set_ajax_czr_tmpl___fa_icon_picker_input", '\Nimble\sek_get_fa_icon_list_tmpl', 10, 3 );
// this dynamic filter is declared on wp_ajax_ac_get_template in the czr_base_fmk
// It allows us to populate the server response with the relevant module html template
// $html = apply_filters( "ac_set_ajax_czr_tmpl___{$module_type}", '', $tmpl );
add_filter( "ac_set_ajax_czr_tmpl___font_picker_input", '\Nimble\sek_get_font_list_tmpl', 10, 3 );
// </AJAX TO FETCH INPUT COMPONENTS>
/////////////////////////////////////////////////////////////////
// hook : wp_ajax_sek_import_attachment
function sek_ajax_import_attachment() {
sek_do_ajax_pre_checks( array( 'check_nonce' => false ) );
if ( !isset( $_POST['img_url'] ) || !is_string($_POST['img_url']) ) {
wp_send_json_error( 'missing_or_invalid_img_url_when_importing_image');
}
$id = sek_sideload_img_and_return_attachment_id( sanitize_text_field($_POST['img_url']) );
if ( is_wp_error( $id ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => problem when trying to wp_insert_attachment() for img : ' . sanitize_text_field($_POST['img_url']) . ' | SERVER ERROR => ' . json_encode( $id ) );
} else {
wp_send_json_success([
'id' => $id,
'url' => wp_get_attachment_url( $id )
]);
}
}
////////////////////////////////////////////////////////////////
// REVISIONS
// Fired in __construct()
function sek_get_revision_history() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
if ( !isset( $_POST['skope_id'] ) || empty( $_POST['skope_id'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => missing skope_id' );
}
$rev_list = sek_get_revision_history_from_posts( sanitize_text_field($_POST['skope_id']) );
wp_send_json_success( $rev_list );
}
function sek_get_single_revision() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
if ( !isset( $_POST['revision_post_id'] ) || empty( $_POST['revision_post_id'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => missing revision_post_id' );
}
$revision = sek_get_single_post_revision( sanitize_text_field($_POST['revision_post_id']) );
wp_send_json_success( $revision );
}
////////////////////////////////////////////////////////////////
// POST CATEGORIES => to be used in the category picker select input
// Fired in __construct()
function sek_get_post_categories() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
$raw_cats = get_categories();
$raw_cats = is_array( $raw_cats ) ? $raw_cats : array();
$cat_collection = array();
foreach( $raw_cats as $cat ) {
$cat_collection[] = array(
'id' => $cat->term_id,
'slug' => $cat->slug,
'name' => sprintf( '%s (%s %s)', $cat->cat_name, $cat->count, __('posts', 'text_doma') )
);
}
wp_send_json_success( $cat_collection );
}
////////////////////////////////////////////////////////////////
// CODE EDITOR PARAMS => to be used in the code editor input
// Fired in __construct()
function sek_get_code_editor_params() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
$code_type = isset( $_POST['code_type'] ) ? sanitize_text_field($_POST['code_type']) : 'text/html';
$editor_params = nimble_get_code_editor_settings( array(
'type' => $code_type
));
wp_send_json_success( $editor_params );
}
////////////////////////////////////////////////////////////////
// POSTPONE FEEDBACK NOTIFICATION IN CUSTOMIZER
// INSPIRED FROM CORE DISMISS POINTER MECHANISM
// @see wp-admin/includes/ajax-actions.php
// Nov 2020 => DEPRECATED https://github.com/presscustomizr/nimble-builder/issues/701
function sek_postpone_feedback_notification() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
if ( !isset( $_POST['transient_duration_in_days'] ) ||!is_numeric( $_POST['transient_duration_in_days'] ) ) {
$transient_duration = 7 * DAY_IN_SECONDS;
} else {
$transient_duration = sanitize_text_field($_POST['transient_duration_in_days']) * DAY_IN_SECONDS;
}
set_transient( NIMBLE_FEEDBACK_NOTICE_ID, 'maybe_later', $transient_duration );
wp_die( 1 );
}
////////////////////////////////////////////////////////////////
// FETCH FONT AWESOME ICONS
// hook : ac_set_ajax_czr_tmpl___czr_tiny_mce_editor_module
// this dynamic filter is declared on wp_ajax_ac_get_template
// It allows us to populate the server response with the relevant module html template
// $html = apply_filters( "ac_set_ajax_czr_tmpl___{$module_type}", '', $tmpl );
//
// For czr_tiny_mce_editor_module, we request the font_list tmpl
function sek_get_fa_icon_list_tmpl( $html, $requested_tmpl = '', $posted_params = array() ) {
if ( empty( $requested_tmpl ) ) {
wp_send_json_error( __FUNCTION__ . ' => the requested tmpl is empty' );
}
return wp_json_encode(
sek_retrieve_decoded_font_awesome_icons()
);//will be sent by wp_send_json_success() in ::ac_set_ajax_czr_tmpl()
}
//retrieves faicons:
// 1) from faicons.json if needed (transient doesn't exists, or is new version => set in TC_wfc ) and decodes them
// otherwise
// 2) from the transient set if it exists
function sek_retrieve_decoded_font_awesome_icons() {
// this file must be generated with: https://github.com/presscustomizr/nimble-builder/issues/57
$faicons_json_path = NIMBLE_BASE_PATH . '/assets/faicons.json';
$faicons_transient_name = NIMBLE_FAWESOME_TRANSIENT_ID;
if ( false == get_transient( $faicons_transient_name ) ) {
if ( file_exists( $faicons_json_path ) ) {
$faicons_raw = @file_get_contents( $faicons_json_path );
if ( false === $faicons_raw ) {
$faicons_raw = wp_remote_fopen( $faicons_json_path );
}
$faicons_decoded = json_decode( $faicons_raw, true );
set_transient( $faicons_transient_name , $faicons_decoded , 60*60*24*3000 );
} else {
wp_send_json_error( __FUNCTION__ . ' => the file faicons.json is missing' );
}
}
else {
$faicons_decoded = get_transient( $faicons_transient_name );
}
return $faicons_decoded;
}
////////////////////////////////////////////////////////////////
// FETCH FONT LISTS
// hook : ac_set_ajax_czr_tmpl___czr_tiny_mce_editor_module
// For czr_tiny_mce_editor_module, we request the font_list tmpl
function sek_get_font_list_tmpl( $html, $requested_tmpl = '', $posted_params = array() ) {
if ( empty( $requested_tmpl ) ) {
wp_send_json_error( __FUNCTION__ . ' => the requested tmpl is empty' );
}
return wp_json_encode( array(
'cfonts' => sek_get_cfonts(),
'gfonts' => sek_get_gfonts(),
) );//will be sent by wp_send_json_success() in ::ac_set_ajax_czr_tmpl()
}
function sek_get_cfonts() {
$cfonts = array();
$raw_cfonts = array(
'-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue, Arial, sans-serif',
'Arial Black,Arial Black,Gadget,sans-serif',
'Century Gothic',
'Comic Sans MS,Comic Sans MS,cursive',
'Courier New,Courier New,Courier,monospace',
'Georgia,Georgia,serif',
'Helvetica Neue, Helvetica, Arial, sans-serif',
'Impact,Charcoal,sans-serif',
'Lucida Console,Monaco,monospace',
'Lucida Sans Unicode,Lucida Grande,sans-serif',
'Palatino Linotype,Book Antiqua,Palatino,serif',
'Tahoma,Geneva,sans-serif',
'Times New Roman,Times,serif',
'Trebuchet MS,Helvetica,sans-serif',
'Verdana,Geneva,sans-serif',
);
foreach ( $raw_cfonts as $font ) {
//no subsets for cfonts => epty array()
$cfonts[] = array(
'name' => $font ,
'subsets' => array()
);
}
return apply_filters( 'sek_font_picker_cfonts', $cfonts );
}
//retrieves gfonts:
// 1) from webfonts.json if needed (transient doesn't exists, or is new version => set in TC_wfc ) and decodes them
// otherwise
// 2) from the transiet set if it exists
//
// => Until June 2017, the webfonts have been stored in 'tc_gfonts' transient
// => In June 2017, the Google Fonts have been updated with a new webfonts.json
// generated from : https://www.googleapis.com/webfonts/v1/webfonts?key=AIzaSyBID8gp8nBOpWyH5MrsF7doP4fczXGaHdA
//
// => The transient name is now : czr_gfonts_june_2017
function sek_retrieve_decoded_gfonts() {
if ( false == get_transient( NIMBLE_GFONTS_TRANSIENT_ID ) ) {
$gfont_raw = @file_get_contents( NIMBLE_BASE_PATH ."/assets/webfonts.json" );
if ( $gfont_raw === false ) {
$gfont_raw = wp_remote_fopen( NIMBLE_BASE_PATH ."/assets/webfonts.json" );
}
$gfonts_decoded = json_decode( $gfont_raw, true );
set_transient( NIMBLE_GFONTS_TRANSIENT_ID , $gfonts_decoded , 60*60*24*3000 );
}
else {
$gfonts_decoded = get_transient( NIMBLE_GFONTS_TRANSIENT_ID );
}
return $gfonts_decoded;
}
//@return the google fonts
function sek_get_gfonts( $what = null ) {
//checks if transient exists or has expired
$gfonts_decoded = sek_retrieve_decoded_gfonts();
$gfonts = array();
//$subsets = array();
// $subsets['all-subsets'] = sprintf( '%1$s ( %2$s %3$s )',
// __( 'All languages' , 'text_doma' ),
// count($gfonts_decoded['items']) + count( get_cfonts() ),
// __('fonts' , 'text_doma' )
// );
foreach ( $gfonts_decoded['items'] as $font ) {
foreach ( $font['variants'] as $variant ) {
$name = str_replace( ' ', '+', $font['family'] );
$gfonts[] = array(
'name' => $name . ':' .$variant
//'subsets' => $font['subsets']
);
}
//generates subset list : subset => font number
// foreach ( $font['subsets'] as $sub ) {
// $subsets[$sub] = isset($subsets[$sub]) ? $subsets[$sub]+1 : 1;
// }
}
//finalizes the subset array
// foreach ( $subsets as $subset => $font_number ) {
// if ( 'all-subsets' == $subset )
// continue;
// $subsets[$subset] = sprintf('%1$s ( %2$s %3$s )',
// $subset,
// $font_number,
// __('fonts' , 'text_doma' )
// );
// }
return ('subsets' == $what) ? apply_filters( 'sek_font_picker_gfonts_subsets ', $subsets ) : apply_filters( 'sek_font_picker_gfonts', $gfonts ) ;
}
?>
@@ -0,0 +1,269 @@
<?php
add_action( 'customize_register', '\Nimble\sek_catch_export_action', PHP_INT_MAX );
function sek_catch_export_action( $wp_customize ) {
if ( current_user_can( 'customize' ) ) {
if ( isset( $_REQUEST['sek_export_nonce'] ) ) {
sek_maybe_export();
}
}
}
// fire from sek_catch_export_action() @hook 'customize_register'
function sek_maybe_export() {
$nonce = 'save-customize_' . get_stylesheet();
if ( !isset( $_REQUEST['sek_export_nonce'] ) ) {
sek_error_log( __FUNCTION__ . ' => missing nonce.');
return;
}
if ( !isset( $_REQUEST['skope_id']) || empty( $_REQUEST['skope_id'] ) ) {
sek_error_log( __FUNCTION__ . ' => missing or empty skope_id.');
return;
}
if ( !isset( $_REQUEST['active_locations'] ) || empty( $_REQUEST['active_locations'] ) ) {
sek_error_log( __FUNCTION__ . ' => missing active locations param.');
return;
}
if ( !wp_verify_nonce( $_REQUEST['sek_export_nonce'], $nonce ) ) {
sek_error_log( __FUNCTION__ . ' => invalid none.');
return;
}
if ( !is_user_logged_in() ) {
sek_error_log( __FUNCTION__ . ' => user not logged in.');
return;
}
if ( !current_user_can( 'customize' ) ) {
sek_error_log( __FUNCTION__ . ' => missing customize capabilities.');
return;
}
$seks_data = sek_get_skoped_seks( sanitize_text_field($_REQUEST['skope_id']) );
//sek_error_log('EXPORT BEFORE FILTER ? ' . $_REQUEST['skope_id'] , $seks_data );
// the filter 'nimble_pre_export' is used to :
// replace image id by the absolute url
// clean level ids and replace them with a placeholder string
$seks_data = apply_filters( 'nimble_pre_export', $seks_data );
// March 2021 : make sure text input are sanitized like in #544 #792
//$seks_data = sek_sektion_collection_sanitize_cb( $seks_data );
$theme_name = sanitize_title_with_dashes( get_stylesheet() );
//sek_error_log('EXPORT AFTER FILTER ?', $seks_data );
$export = array(
'data' => $seks_data,
'metas' => array(
'skope_id' => sanitize_text_field($_REQUEST['skope_id']),
'version' => NIMBLE_VERSION,
// is sent as a string : "__after_header,__before_main_wrapper,loop_start,__before_footer"
'active_locations' => is_string( $_REQUEST['active_locations'] ) ? explode( ',', sanitize_text_field($_REQUEST['active_locations']) ) : array(),
'date' => date("Y-m-d"),
'theme' => $theme_name
)
);
//sek_error_log('$export ?', $export );
$skope_id = str_replace('skp__', '', sanitize_text_field($_REQUEST['skope_id']) );
$filename = $theme_name . '_' . $skope_id . '.nimblebuilder';
// Set the download headers.
header( 'Content-disposition: attachment; filename=' . $filename );
header( 'Content-Type: application/octet-stream; charset=' . get_option( 'blog_charset' ) );
echo wp_json_encode( $export );
// Start the download.
die();
}
// Ajax action before processing the export
// control that all required fields are there
// This is to avoid a white screen when generating the download window afterwards
add_action( 'wp_ajax_sek_pre_export_checks', '\Nimble\sek_ajax_pre_export_checks' );
function sek_ajax_pre_export_checks() {
//sek_error_log('PRE EXPORT CHECKS ?', $_POST );
$action = 'save-customize_' . get_stylesheet();
if ( !check_ajax_referer( $action, 'nonce', false ) ) {
wp_send_json_error( 'check_ajax_referer_failed' );
}
if ( !is_user_logged_in() ) {
wp_send_json_error( 'user_unauthenticated' );
}
if ( !current_user_can( 'customize' ) ) {
status_header( 403 );
wp_send_json_error( 'customize_not_allowed' );
} else if ( !isset( $_SERVER['REQUEST_METHOD'] ) || 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
status_header( 405 );
wp_send_json_error( 'bad_ajax_method' );
}
if ( !isset( $_POST['skope_id'] ) || empty( $_POST['skope_id'] ) ) {
wp_send_json_error( 'missing_skope_id' );
}
if ( !isset( $_POST['active_locations'] ) || empty( $_POST['active_locations'] ) ) {
wp_send_json_error( 'no_active_locations_to_export' );
}
wp_send_json_success();
}
// EXPORT FILTER
add_filter( 'nimble_pre_export', '\Nimble\sek_parse_img_and_clean_id' );
function sek_parse_img_and_clean_id( $seks_data ) {
$new_seks_data = array();
foreach ( $seks_data as $key => $value ) {
if ( is_array($value) ) {
$new_seks_data[$key] = sek_parse_img_and_clean_id( $value );
} else {
switch( $key ) {
case 'bg-image' :
case 'img' :
if ( is_int( $value ) && (int)$value > 0 ) {
$value = '__img_url__' . wp_get_attachment_url((int)$value);
}
break;
case 'id' :
if ( is_string( $value ) && false !== strpos( $value, '__nimble__' ) ) {
$value = '__rep__me__';
}
break;
}
$new_seks_data[$key] = $value;
}
}
return $new_seks_data;
}
// fetch the content from a user imported file
add_action( 'wp_ajax_sek_get_manually_imported_file_content', '\Nimble\sek_ajax_get_manually_imported_file_content' );
function sek_ajax_get_manually_imported_file_content() {
// sek_error_log(__FUNCTION__ . ' AJAX $_POST ?', $_POST );
// sek_error_log(__FUNCTION__ . ' AJAX $_FILES ?', $_FILES );
// sek_error_log(__FUNCTION__ . ' AJAX $_REQUEST ?', $_REQUEST );
$action = 'save-customize_' . get_stylesheet();
if ( !check_ajax_referer( $action, 'nonce', false ) ) {
wp_send_json_error( 'check_ajax_referer_failed' );
}
if ( !is_user_logged_in() ) {
wp_send_json_error( 'user_unauthenticated' );
}
if ( !current_user_can( 'customize' ) ) {
status_header( 403 );
wp_send_json_error( 'customize_not_allowed' );
} else if ( !isset( $_SERVER['REQUEST_METHOD'] ) || 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
status_header( 405 );
wp_send_json_error( 'bad_ajax_method' );
}
if ( !isset( $_FILES['file_candidate'] ) || empty( $_FILES['file_candidate'] ) ) {
wp_send_json_error( 'missing_file_candidate' );
}
if ( !isset( $_POST['skope'] ) || empty( $_POST['skope'] ) ) {
wp_send_json_error( 'missing_skope' );
}
// load WP upload if not done yet
if ( !function_exists( 'wp_handle_upload' ) ) {
require_once( ABSPATH . 'wp-admin/includes/file.php' );
}
// @see https://codex.wordpress.org/Function_Reference/wp_handle_upload
// Important => always run unlink( $file['file'] ) before sending the json success or error
// otherwise WP will write the file in the /wp-content folder
$file = wp_handle_upload(
$_FILES['file_candidate'],
array(
'test_form' => false,
'test_type' => false,
'mimes' => array(
'text' => 'text/plain',
//'nimblebuilder' => 'text/plain',
'json' => 'application/json',
'nimblebuilder' => 'application/json'
)
)
);
// Make sure we have an uploaded file.
if ( isset( $file['error'] ) ) {
unlink( $file['file'] );
wp_send_json_error( 'import_file_error' );
return;
}
if ( !file_exists( $file['file'] ) ) {
unlink( $file['file'] );
wp_send_json_error( 'import_file_do_not_exist' );
return;
}
// Get the upload data.
$raw = file_get_contents( $file['file'] );
//$raw_unserialized_data = @unserialize( $raw );
$raw_unserialized_data = json_decode( $raw, true );
// VALIDATE IMPORTED CONTENT
// data structure :
// $raw_unserialized_data = array(
// 'data' => $seks_data,
// 'metas' => array(
// 'skope_id' => $_REQUEST['skope_id'],
// 'version' => NIMBLE_VERSION,
// // is sent as a string : "__after_header,__before_main_wrapper,loop_start,__before_footer"
// 'active_locations' => is_string( $_REQUEST['active_locations'] ) ? explode( ',', $_REQUEST['active_locations'] ) : array(),
// 'date' => date("Y-m-d")
// )
// );
// check import structure
if ( !is_array( $raw_unserialized_data ) || empty( $raw_unserialized_data['data']) || !is_array( $raw_unserialized_data['data'] ) || empty( $raw_unserialized_data['metas'] ) || !is_array( $raw_unserialized_data['metas'] ) ) {
unlink( $file['file'] );
wp_send_json_error( 'invalid_import_content' );
return;
}
// check version
// => current Nimble Version must be at least import version
if ( !empty( $raw_unserialized_data['metas']['version'] ) && version_compare( NIMBLE_VERSION, $raw_unserialized_data['metas']['version'], '<' ) ) {
unlink( $file['file'] );
wp_send_json_error( 'nimble_builder_needs_update' );
return;
}
$maybe_import_images = true;
// in a pre-import-check context, we don't need to sniff and upload images
if ( array_key_exists( 'pre_import_check', $_POST ) && true === sek_booleanize_checkbox_val( sanitize_text_field($_POST['pre_import_check']) ) ) {
$maybe_import_images = false;
}
// april 2020 : introduced for https://github.com/presscustomizr/nimble-builder/issues/663
if ( array_key_exists( 'import_img', $_POST ) && false === sek_booleanize_checkbox_val( sanitize_text_field($_POST['import_img']) ) ) {
$maybe_import_images = false;
}
// Make sure NB decodes encoded rich text before sending to the customizer
// see #544 and #791
$raw_unserialized_data['data'] = sek_sniff_and_decode_richtext( $raw_unserialized_data['data'] );
$imported_content = array(
//'data' => apply_filters( 'nimble_pre_import', $raw_unserialized_data['data'], $do_import_images ),
'data' => sek_maybe_import_imgs( $raw_unserialized_data['data'], $maybe_import_images ),
'metas' => $raw_unserialized_data['metas'],
// the image import errors won't block the import
// they are used when notifying user in the customizer
'img_errors' => !empty( Nimble_Manager()->img_import_errors ) ? implode(',', Nimble_Manager()->img_import_errors) : array()
);
// Remove the uploaded file
// Important => always run unlink( $file['file'] ) before sending the json success or error
// otherwise WP will write the file in the /wp-content folder
unlink( $file['file'] );
// Send
wp_send_json_success( $imported_content );
}
?>
@@ -0,0 +1,324 @@
<?php
////////////////////////////////////////////////////////////////
// Fetches the user saved templates
add_action( 'wp_ajax_sek_get_all_saved_tmpl', '\Nimble\sek_ajax_get_all_saved_templates' );
// @hook wp_ajax_sek_get_user_saved_templates
function sek_ajax_get_all_saved_templates() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
$decoded_templates = sek_get_all_saved_templates();
if ( is_array($decoded_templates) ) {
wp_send_json_success( $decoded_templates );
} else {
if ( !empty( $decoded_templates ) ) {
sek_error_log( __FUNCTION__ . ' error => invalid templates returned', $decoded_templates );
wp_send_json_error( __FUNCTION__ . ' error => invalid templates returned' );
}
}
}
////////////////////////////////////////////////////////////////
// Fetches the api templates
add_action( 'wp_ajax_sek_get_all_api_tmpl', '\Nimble\sek_ajax_get_all_api_templates' );
// @hook wp_ajax_sek_get_user_saved_templates
function sek_ajax_get_all_api_templates() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
$decoded_templates = sek_get_all_api_templates();
if ( is_array($decoded_templates) ) {
wp_send_json_success( $decoded_templates );
} else {
if ( !empty( $decoded_templates ) ) {
sek_error_log( __FUNCTION__ . ' error => invalid templates returned', $decoded_templates );
wp_send_json_error( __FUNCTION__ . ' error => invalid templates returned' );
}
}
}
////////////////////////////////////////////////////////////////
// TEMPLATE GET CONTENT + METAS
// Fetches the json of a given user template
add_action( 'wp_ajax_sek_get_user_tmpl_json', '\Nimble\sek_ajax_sek_get_user_tmpl_json' );
// @hook wp_ajax_sek_get_user_saved_templates
function sek_ajax_sek_get_user_tmpl_json() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
// We must have a tmpl_post_name
if ( empty( $_POST['tmpl_post_name']) || !is_string( $_POST['tmpl_post_name'] ) ) {
wp_send_json_error( __FUNCTION__ . '_missing_tmpl_post_name' );
}
// if ( !isset( $_POST['skope_id'] ) || empty( $_POST['skope_id'] ) ) {
// wp_send_json_error( __FUNCTION__ . '_missing_skope_id' );
// }
$tmpl_post = sek_get_saved_tmpl_post( sanitize_text_field($_POST['tmpl_post_name']) );
if ( !is_wp_error( $tmpl_post ) && $tmpl_post && is_object( $tmpl_post ) ) {
$tmpl_decoded = maybe_unserialize( $tmpl_post->post_content );
// Structure of $content :
// array(
// 'data' => $_POST['tmpl_data'],//<= json stringified
// 'tmpl_post_name' => ( !empty( $_POST['tmpl_post_name'] ) && is_string( $_POST['tmpl_post_name'] ) ) ? $_POST['tmpl_post_name'] : null,
// 'metas' => array(
// 'title' => $_POST['tmpl_title'],
// 'description' => $_POST['tmpl_description'],
// 'skope_id' => $_POST['skope_id'],
// 'version' => NIMBLE_VERSION,
// // is sent as a string : "__after_header,__before_main_wrapper,loop_start,__before_footer"
// 'tmpl_locations' => is_string( $_POST['tmpl_locations'] ) ? explode( ',', $_POST['tmpl_locations'] ) : array(),
// 'date' => date("Y-m-d"),
// 'theme' => sanitize_title_with_dashes( get_stylesheet() )
// )
// );
if ( is_array( $tmpl_decoded ) && !empty( $tmpl_decoded['data'] ) && is_array( $tmpl_decoded['data'] ) ) {
//$tmpl_decoded['data'] = json_decode( wp_unslash( $tmpl_decoded['data'], true ) );
$tmpl_decoded['data'] = sek_maybe_import_imgs( $tmpl_decoded['data'], $do_import_images = true );
// the image import errors won't block the import
// they are used when notifying user in the customizer
$tmpl_decoded['img_errors'] = !empty( Nimble_Manager()->img_import_errors ) ? implode(',', Nimble_Manager()->img_import_errors) : array();
// Make sure we decode encoded rich text before sending to the customizer
// see #544 and #791
$tmpl_decoded['data'] = sek_sniff_and_decode_richtext( $tmpl_decoded['data'] );
// added March 2021 for site templates #478
// If property '__inherits_group_skope_tmpl_when_exists__' has been saved by mistake in the template, make sure it's unset now
if ( array_key_exists('__inherits_group_skope_tmpl_when_exists__', $tmpl_decoded['data'] ) ) {
unset( $tmpl_decoded['data']['__inherits_group_skope_tmpl_when_exists__'] );
}
wp_send_json_success( $tmpl_decoded );
} else {
wp_send_json_error( __FUNCTION__ . '_invalid_tmpl_post_data' );
}
} else {
wp_send_json_error( __FUNCTION__ . '_tmpl_post_not_found' );
}
}
add_action( 'wp_ajax_sek_get_api_tmpl_json', '\Nimble\sek_ajax_sek_get_api_tmpl_json' );
// @hook wp_ajax_sek_get_user_saved_templates
function sek_ajax_sek_get_api_tmpl_json() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
// We must have a tmpl_post_name
if ( empty( $_POST['api_tmpl_name']) || !is_string( $_POST['api_tmpl_name'] ) ) {
wp_send_json_error( __FUNCTION__ . '_missing_tmpl_post_name' );
}
$tmpl_name = sanitize_text_field($_POST['api_tmpl_name']);
// Pro Template case
$is_pro_tmpl = array_key_exists('api_tmpl_is_pro', $_POST ) && 'yes' === sanitize_text_field($_POST['api_tmpl_is_pro']);
if ( $is_pro_tmpl ) {
$pro_key_status = apply_filters( 'nimble_pro_key_status_OK', 'nok' );
if ( 'pro_key_status_ok' !== $pro_key_status ) {
wp_send_json_error( $pro_key_status );
return;
}
}
$raw_tmpl_data = sek_get_single_tmpl_api_data( $tmpl_name, $is_pro_tmpl );// <= returns an unserialized array, in which the template['data'] is NOT a JSON, unlike for user saved templates
// If the api returned a pro license key problem, bail now and return the api string message
if ( $is_pro_tmpl && is_string( $raw_tmpl_data ) && !empty( $raw_tmpl_data ) ) {
wp_send_json_error( $raw_tmpl_data );
} else if ( !is_array( $raw_tmpl_data) || empty( $raw_tmpl_data ) ) {
sek_error_log( __FUNCTION__ . ' problem when getting template : ' . $tmpl_name );
wp_send_json_error( __FUNCTION__ . '_invalid_template_'. $tmpl_name );
}
//sek_error_log( __FUNCTION__ . ' api template collection', $raw_tmpl_data );
if ( !isset($raw_tmpl_data['data'] ) || empty( $raw_tmpl_data['data'] ) ) {
sek_error_log( __FUNCTION__ . ' problem => missing or invalid data property for template : ' . $tmpl_name, $raw_tmpl_data );
wp_send_json_error( __FUNCTION__ . '_missing_data_property_for_template_' . $tmpl_name );
} else {
// $tmpl_decoded = $raw_tmpl_data;
$raw_tmpl_data['data'] = sek_maybe_import_imgs( $raw_tmpl_data['data'], $do_import_images = true );
$raw_tmpl_data['img_errors'] = !empty( Nimble_Manager()->img_import_errors ) ? implode(',', Nimble_Manager()->img_import_errors) : array();
// Make sure we decode encoded rich text before sending to the customizer
// see #544 and #791
$raw_tmpl_data['data'] = sek_sniff_and_decode_richtext( $raw_tmpl_data['data'] );
// added March 2021 for site templates #478
// If property '__inherits_group_skope_tmpl_when_exists__' has been saved by mistake in the template, make sure it's unset now
if ( array_key_exists('__inherits_group_skope_tmpl_when_exists__', $raw_tmpl_data['data'] ) ) {
unset( $raw_tmpl_data['data']['__inherits_group_skope_tmpl_when_exists__'] );
}
wp_send_json_success( $raw_tmpl_data );
}
//return [];
}
////////////////////////////////////////////////////////////////
// TEMPLATE SAVE
// introduced in april 2020 for https://github.com/presscustomizr/nimble-builder/issues/655
add_action( 'wp_ajax_sek_save_user_template', '\Nimble\sek_ajax_save_user_template' );
/////////////////////////////////////////////////////////////////
// hook : wp_ajax_sek_save_user_template
function sek_ajax_save_user_template() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
$is_edit_metas_only_case = isset( $_POST['edit_metas_only'] ) && 'yes' === sanitize_text_field($_POST['edit_metas_only']);
// TMPL DATA => the nimble content
if ( !$is_edit_metas_only_case && empty( $_POST['tmpl_data']) ) {
wp_send_json_error( __FUNCTION__ . '_missing_template_data' );
}
if ( !$is_edit_metas_only_case && !is_string( $_POST['tmpl_data'] ) ) {
wp_send_json_error( __FUNCTION__ . '_template_data_must_be_a_json_stringified' );
}
// TMPL METAS
// We must have a title
if ( empty( $_POST['tmpl_title']) ) {
wp_send_json_error( __FUNCTION__ . '_missing_template_title' );
}
if ( !is_string( $_POST['tmpl_description'] ) ) {
wp_send_json_error( __FUNCTION__ . '_template_description_must_be_a_string' );
}
if ( !isset( $_POST['skope_id'] ) || empty( $_POST['skope_id'] ) ) {
wp_send_json_error( __FUNCTION__ . '_missing_skope_id' );
}
if ( !isset( $_POST['tmpl_locations'] ) || empty( $_POST['tmpl_locations'] ) ) {
wp_send_json_error( __FUNCTION__ . '_missing_tmpl_locations' );
}
if ( $is_edit_metas_only_case ) {
$tmpl_data = [];
} else {
// clean level ids and replace them with a placeholder string
$tmpl_data = json_decode( wp_unslash( $_POST['tmpl_data'] ), true );
$tmpl_data = sek_template_save_clean_id( $tmpl_data );
// added March 2021 for site templates #478
// If property '__inherits_group_skope_tmpl_when_exists__' has been set to the template, make sure it's unset now
if ( array_key_exists('__inherits_group_skope_tmpl_when_exists__', $tmpl_data ) ) {
unset( $tmpl_data['__inherits_group_skope_tmpl_when_exists__'] );
}
}
// make sure description and title are clean before DB
$tmpl_title = sek_maybe_encode_richtext( sanitize_text_field($_POST['tmpl_title']) );
$tmpl_description = sek_maybe_encode_richtext( sanitize_text_field($_POST['tmpl_description']) );
// sanitize tmpl_locations
$tmpl_locations = [];
if ( is_array($_POST['tmpl_locations']) ) {
foreach($_POST['tmpl_locations'] as $loc ) {
$tmpl_locations[] = sanitize_text_field($loc);
}
}
// sek_error_log('json decode ?', json_decode( wp_unslash( $_POST['sek_data'] ), true ) );
$template_to_save = array(
'data' => $tmpl_data,//<= array
'tmpl_post_name' => ( !empty( $_POST['tmpl_post_name'] ) && is_string( $_POST['tmpl_post_name'] ) ) ? sanitize_text_field($_POST['tmpl_post_name']) : null,
'metas' => array(
'title' => $tmpl_title,
'description' => $tmpl_description,
'skope_id' => sanitize_text_field($_POST['skope_id']),
'version' => NIMBLE_VERSION,
// is sent as a string : "__after_header,__before_main_wrapper,loop_start,__before_footer"
'tmpl_locations' => $tmpl_locations,
'tmpl_header_location' => isset( $_POST['tmpl_header_location'] ) ? sanitize_text_field($_POST['tmpl_header_location']) : '',
'tmpl_footer_location' => isset( $_POST['tmpl_footer_location'] ) ? sanitize_text_field($_POST['tmpl_footer_location']) : '',
'date' => date("Y-m-d"),
'theme' => sanitize_title_with_dashes( get_stylesheet() ),
// for api templates
'is_pro_tmpl' => false,
'thumb_url' => ''
)
);
$saved_template_post = sek_update_user_tmpl_post( $template_to_save, $is_edit_metas_only_case );
if ( is_wp_error( $saved_template_post ) || is_null($saved_template_post) || empty($saved_template_post) ) {
wp_send_json_error( __FUNCTION__ . ' => error when invoking sek_update_user_tmpl_post()' );
} else {
// sek_error_log( 'ALORS CE POST?', $saved_template_post );
wp_send_json_success( [ 'tmpl_post_id' => $saved_template_post->ID ] );
}
//sek_error_log( __FUNCTION__ . '$_POST' , $_POST);
}
// SAVE FILTER
function sek_template_save_clean_id( $tmpl_data = array() ) {
$new_tmpl_data = array();
if ( !is_array( $tmpl_data ) ) {
sek_error_log( __FUNCTION__ . ' error => tmpl_data should be an array');
return array();
}
$level = null;
if ( isset($tmpl_data['level'] ) ) {
$level = $tmpl_data['level'];
}
foreach ( $tmpl_data as $key => $value ) {
if ( is_array($value) ) {
$new_tmpl_data[$key] = sek_template_save_clean_id( $value );
} else {
switch( $key ) {
// we want to replace ids for all levels but locations
// only section, columns and modules have an id which starts by __nimble__, for ex : __nimble__2024500518bf
// locations id are like : loop_start
case 'id' :
if ( 'location' !== $level && is_string( $value ) && false !== strpos( $value, '__nimble__' ) ) {
$value = '__rep__me__';
}
break;
}
$new_tmpl_data[$key] = $value;
}
}
return $new_tmpl_data;
}
////////////////////////////////////////////////////////////////
// TEMPLATE REMOVE
// introduced in may 2020 for https://github.com/presscustomizr/nimble-builder/issues/655
add_action( 'wp_ajax_sek_remove_user_template', '\Nimble\sek_ajax_remove_user_template' );
/////////////////////////////////////////////////////////////////
// hook : wp_ajax_sek_remove_user_template
function sek_ajax_remove_user_template() {
//sek_error_log( __FUNCTION__ . ' ALORS YEAH IN REMOVAL ? ?', $_POST );
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
// We must have a tmpl_post_name
if ( empty( $_POST['tmpl_post_name']) || !is_string( $_POST['tmpl_post_name'] ) ) {
wp_send_json_error( __FUNCTION__ . '_missing_tmpl_post_name' );
}
$tmpl_post_name = sanitize_text_field($_POST['tmpl_post_name']);
// if ( !isset( $_POST['skope_id'] ) || empty( $_POST['skope_id'] ) ) {
// wp_send_json_error( __FUNCTION__ . '_missing_skope_id' );
// }
$tmpl_post_to_remove = sek_get_saved_tmpl_post( $tmpl_post_name );
//sek_error_log( __FUNCTION__ . ' => so $tmpl_post_to_remove ' . $_POST['tmpl_post_name'], $tmpl_post_to_remove );
if ( $tmpl_post_to_remove && is_object( $tmpl_post_to_remove ) ) {
// the CPT is moved to Trash instead of permanently deleted when using wp_delete_post()
$r = wp_trash_post( $tmpl_post_to_remove->ID );
if ( is_wp_error( $r ) ) {
wp_send_json_error( __FUNCTION__ . '_removal_error' );
}
// Added April 2021 for stie templates #478
do_action('nb_on_remove_saved_tmpl_post', $tmpl_post_name );
} else {
wp_send_json_error( __FUNCTION__ . '_tmpl_post_not_found' );
}
if ( is_wp_error( $tmpl_post_to_remove ) || is_null($tmpl_post_to_remove) || empty($tmpl_post_to_remove) ) {
wp_send_json_error( __FUNCTION__ . '_removal_error' );
} else {
// sek_error_log( 'ALORS CE POST?', $saved_template_post );
wp_send_json_success( [ 'tmpl_post_removed' => $tmpl_post_name ] );
}
//sek_error_log( __FUNCTION__ . '$_POST' , $_POST);
}
?>
@@ -0,0 +1,266 @@
<?php
////////////////////////////////////////////////////////////////
// Fetches the user saved sections
add_action( 'wp_ajax_sek_get_all_saved_sections', '\Nimble\sek_ajax_get_all_saved_sections' );
// @hook wp_ajax_sek_get_user_saved_sections
function sek_ajax_get_all_saved_sections() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
$decoded_sections = sek_get_all_saved_sections();
if ( is_array($decoded_sections) ) {
wp_send_json_success( $decoded_sections );
} else {
if ( !empty( $decoded_sections ) ) {
sek_error_log( __FUNCTION__ . ' error => invalid sections returned', $decoded_sections );
wp_send_json_error( __FUNCTION__ . ' error => invalid sections returned' );
}
}
}
// Fetches the preset_sections
add_action( 'wp_ajax_sek_get_single_api_section_data', '\Nimble\sek_ajax_get_single_api_section_data' );
////////////////////////////////////////////////////////////////
// PRESET SECTIONS
// Fired in __construct()
// hook : 'wp_ajax_sek_get_preset_sektions'
function sek_ajax_get_single_api_section_data() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
// September 2020 => force update every 24 hours so users won't miss a new pre-build section
// Note that the refresh should have take place on 'upgrader_process_complete'
// always force refresh when developing
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
// We must have a api_section_id
if ( empty( $_POST['api_section_id']) || !is_string( $_POST['api_section_id'] ) ) {
wp_send_json_error( __FUNCTION__ . '_missing_api_section_id' );
}
$api_section_id = sanitize_text_field($_POST['api_section_id']);
$is_pro_section_id = sek_is_pro() && is_string($api_section_id) && 'pro_' === substr($api_section_id,0,4);
$pro_key_status = apply_filters( 'nimble_pro_key_status_OK', 'nok' );
if ( $is_pro_section_id && 'pro_key_status_ok' !== $pro_key_status ) {
wp_send_json_error( $pro_key_status );
return;
}
$raw_api_sec_data = sek_api_get_single_section_data( $api_section_id );// <= returns an unserialized array
// When injecting a pro section, NB checks the validity of the key.
// if the api response is not an array, there was a problem when checking the key
// and in this case the response is a string like : 'Expired.'
if ( $is_pro_section_id && is_string($raw_api_sec_data) && !empty($raw_api_sec_data) ) {
wp_send_json_error( $raw_api_sec_data );
return;
}
if( !is_array( $raw_api_sec_data) || empty( $raw_api_sec_data ) ) {
sek_error_log( __FUNCTION__ . ' problem when getting section : ' . $api_section_id );
wp_send_json_error( 'Error : empty or invalid section data : '. $api_section_id );
return;
}
//sek_error_log( __FUNCTION__ . ' api section data', $raw_api_sec_data );
if ( !isset($raw_api_sec_data['collection'] ) || empty( $raw_api_sec_data['collection'] ) ) {
sek_error_log( __FUNCTION__ . ' problem => missing or invalid data property for section : ' . $api_section_id, $raw_api_sec_data );
wp_send_json_error( 'Error : missing_data_property_for_section : ' . $api_section_id );
} else {
// $tmpl_decoded = $raw_api_sec_data;
$raw_api_sec_data['collection'] = sek_maybe_import_imgs( $raw_api_sec_data['collection'], $do_import_images = true );
//$raw_api_sec_data['img_errors'] = !empty( Nimble_Manager()->img_import_errors ) ? implode(',', Nimble_Manager()->img_import_errors) : array();
// Make sure we decode encoded rich text before sending to the customizer
// see #544 and #791
$raw_api_sec_data['collection'] = sek_sniff_and_decode_richtext( $raw_api_sec_data['collection'] );
wp_send_json_success( $raw_api_sec_data );
}
}
////////////////////////////////////////////////////////////////
// SECTION GET CONTENT + METAS
// Fetches the json of a given user section
add_action( 'wp_ajax_sek_get_user_section_json', '\Nimble\sek_ajax_sek_get_user_section_json' );
// @hook wp_ajax_sek_get_user_saved_sections
function sek_ajax_sek_get_user_section_json() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
// We must have a section_post_name
if ( empty( $_POST['section_post_name']) || !is_string( $_POST['section_post_name'] ) ) {
wp_send_json_error( __FUNCTION__ . '_missing_section_post_name' );
}
// if ( !isset( $_POST['skope_id'] ) || empty( $_POST['skope_id'] ) ) {
// wp_send_json_error( __FUNCTION__ . '_missing_skope_id' );
// }
$section_post = sek_get_saved_section_post( sanitize_text_field($_POST['section_post_name']) );
if ( !is_wp_error( $section_post ) && $section_post && is_object( $section_post ) ) {
$section_decoded = maybe_unserialize( $section_post->post_content );
// Structure of $content :
// array(
// 'data' => $_POST['section_data'],//<= json stringified
// 'section_post_name' => ( !empty( $_POST['section_post_name'] ) && is_string( $_POST['section_post_name'] ) ) ? $_POST['section_post_name'] : null,
// 'metas' => array(
// 'title' => $_POST['section_title'],
// 'description' => $_POST['section_description'],
// 'skope_id' => $_POST['skope_id'],
// 'version' => NIMBLE_VERSION,
// // is sent as a string : "__after_header,__before_main_wrapper,loop_start,__before_footer"
// 'active_locations' => is_string( $_POST['active_locations'] ) ? explode( ',', $_POST['active_locations'] ) : array(),
// 'date' => date("Y-m-d"),
// 'theme' => sanitize_title_with_dashes( get_stylesheet() )
// )
// );
if ( is_array( $section_decoded ) && !empty( $section_decoded['data'] ) && is_string( $section_decoded['data'] ) ) {
$section_decoded['data'] = json_decode( wp_unslash( $section_decoded['data'], true ) );
}
// Make sure we decode encoded rich text before sending to the customizer
// see #544 and #791
$section_decoded['data'] = sek_sniff_and_decode_richtext( $section_decoded['data'] );
wp_send_json_success( $section_decoded );
} else {
wp_send_json_error( __FUNCTION__ . '_section_post_not_found' );
}
}
////////////////////////////////////////////////////////////////
// SECTION SAVE
// introduced in april 2020 for https://github.com/presscustomizr/nimble-builder/issues/655
// ENABLED WHEN CONSTANT NIMBLE_SECTION_SAVE_ENABLED === true
add_action( 'wp_ajax_sek_save_user_section', '\Nimble\sek_ajax_save_user_section' );
/////////////////////////////////////////////////////////////////
// hook : wp_ajax_sek_save_user_section
function sek_ajax_save_user_section() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
$is_edit_metas_only_case = isset( $_POST['edit_metas_only'] ) && 'yes' === sanitize_text_field($_POST['edit_metas_only']);
// TMPL DATA => the nimble content
if ( !$is_edit_metas_only_case && empty( $_POST['section_data']) ) {
wp_send_json_error( __FUNCTION__ . '_missing_section_data' );
}
if ( !$is_edit_metas_only_case && !is_string( $_POST['section_data'] ) ) {
wp_send_json_error( __FUNCTION__ . '_section_data_must_be_a_json_stringified' );
}
// TMPL METAS
// We must have a title
if ( empty( $_POST['section_title']) ) {
wp_send_json_error( __FUNCTION__ . '_missing_section_title' );
}
if ( !is_string( $_POST['section_description'] ) ) {
wp_send_json_error( __FUNCTION__ . '_section_description_must_be_a_string' );
}
if ( !isset( $_POST['skope_id'] ) || empty( $_POST['skope_id'] ) ) {
wp_send_json_error( __FUNCTION__ . '_missing_skope_id' );
}
// if ( !isset( $_POST['active_locations'] ) || empty( $_POST['active_locations'] ) ) {
// wp_send_json_error( __FUNCTION__ . '_missing_active_locations' );
// }
if ( $is_edit_metas_only_case ) {
$seks_data = [];
} else {
// clean level ids and replace them with a placeholder string
$seks_data = json_decode( wp_unslash( $_POST['section_data'] ), true );
$seks_data = sek_section_save_clean_id( $seks_data );
}
// make sure description and title are clean before DB
$sec_title = sek_maybe_encode_richtext( sanitize_text_field($_POST['section_title']) );
$sec_description = sek_maybe_encode_richtext( sanitize_text_field($_POST['section_description']) );
$section_to_save = array(
'data' => $seks_data,//<= json stringified
// the section post name is provided only when updating
'section_post_name' => ( !empty( $_POST['section_post_name'] ) && is_string( $_POST['section_post_name'] ) ) ? sanitize_text_field($_POST['section_post_name']) : null,
'metas' => array(
'title' => $sec_title,
'description' => $sec_description,
'skope_id' => sanitize_text_field($_POST['skope_id']),
'version' => NIMBLE_VERSION,
// is sent as a string : "__after_header,__before_main_wrapper,loop_start,__before_footer"
//'active_locations' => is_array( $_POST['active_locations'] ) ? $_POST['active_locations'] : array(),
'date' => date("Y-m-d"),
'theme' => sanitize_title_with_dashes( get_stylesheet() )
)
);
$saved_section_post = sek_update_saved_section_post( $section_to_save, $is_edit_metas_only_case );
if ( is_wp_error( $saved_section_post ) || is_null($saved_section_post) || empty($saved_section_post) ) {
wp_send_json_error( __FUNCTION__ . ' => error when invoking sek_update_saved_section_post()' );
} else {
wp_send_json_success( [ 'section_post_id' => $saved_section_post->ID ] );
}
}
// SAVE FILTER
function sek_section_save_clean_id( $seks_data = array() ) {
$new_seks_data = array();
if ( !is_array( $seks_data ) ) {
sek_error_log( __FUNCTION__ . ' error => seks_data should be an array');
return array();
}
foreach ( $seks_data as $key => $value ) {
if ( is_array($value) ) {
$new_seks_data[$key] = sek_section_save_clean_id( $value );
} else {
switch( $key ) {
case 'id' :
if ( is_string( $value ) && false !== strpos( $value, '__nimble__' ) ) {
$value = '__rep__me__';
}
break;
}
$new_seks_data[$key] = $value;
}
}
return $new_seks_data;
}
////////////////////////////////////////////////////////////////
// SECTION REMOVE
// introduced in may 2020 for https://github.com/presscustomizr/nimble-builder/issues/655
// ENABLED WHEN CONSTANT NIMBLE_SECTION_SAVE_ENABLED === true
add_action( 'wp_ajax_sek_remove_user_section', '\Nimble\sek_ajax_remove_user_section' );
/////////////////////////////////////////////////////////////////
// hook : wp_ajax_sek_remove_user_section
function sek_ajax_remove_user_section() {
sek_do_ajax_pre_checks( array( 'check_nonce' => true ) );
// We must have a section_post_name
if ( empty( $_POST['section_post_name']) || !is_string( $_POST['section_post_name'] ) ) {
wp_send_json_error( __FUNCTION__ . '_missing_section_post_name' );
}
// if ( !isset( $_POST['skope_id'] ) || empty( $_POST['skope_id'] ) ) {
// wp_send_json_error( __FUNCTION__ . '_missing_skope_id' );
// }
$section_post_to_remove = sek_get_saved_section_post( sanitize_text_field($_POST['section_post_name']) );
if ( $section_post_to_remove && is_object( $section_post_to_remove ) ) {
// the CPT is moved to Trash instead of permanently deleted when using wp_delete_post()
$r = wp_trash_post( $section_post_to_remove->ID );
if ( is_wp_error( $r ) ) {
wp_send_json_error( __FUNCTION__ . '_removal_error' );
}
} else {
wp_send_json_error( __FUNCTION__ . '_section_post_not_found' );
}
if ( is_wp_error( $section_post_to_remove ) || is_null($section_post_to_remove) || empty($section_post_to_remove) ) {
wp_send_json_error( __FUNCTION__ . '_removal_error' );
} else {
wp_send_json_success( [ 'section_post_removed' => sanitize_text_field($_POST['section_post_name']) ] );
}
}
?>
@@ -0,0 +1,13 @@
<?php
// WP 5.0.0 compat. until the bug is fixed
// this hook fires before the customize changeset is inserter / updated in database
// Removing the wp_targeted_link_rel callback from the 'content_save_pre' filter prevents corrupting the changeset JSON
// more details in this ticket : https://core.trac.wordpress.org/ticket/45292
add_action( 'customize_save_validation_before', '\Nimble\sek_remove_callback_wp_targeted_link_rel' );
function sek_remove_callback_wp_targeted_link_rel( $wp_customize ) {
if ( false !== has_filter( 'content_save_pre', 'wp_targeted_link_rel' ) ) {
remove_filter( 'content_save_pre', 'wp_targeted_link_rel' );
}
};
?>
@@ -0,0 +1,442 @@
<?php
////////////////////////////////////////////////////////////////
// SEK Front Class
if ( !class_exists( 'SEK_Front_Construct' ) ) :
class SEK_Front_Construct {
static $instance;
public $seks_posts = [];// <= march 2020 : used to cache the current local and global sektion posts
public $model = array();//<= when rendering, the current level model
public $parent_model = array();//<= when rendering, the current parent model
public $default_models = array();// <= will be populated to cache the default models when invoking sek_get_default_module_model
public $cached_input_lists = array(); // <= will be populated to cache the input_list of each registered module. Useful when we need to get info like css_selector for a particular input type or id.
public $ajax_action_map = array();
public $default_locations = [
'loop_start' => array( 'priority' => 10 ),
'before_content' => array(),
'after_content' => array(),
'loop_end' => array( 'priority' => 10 ),
];
public $registered_locations = [];
// the model used to register a location
public $default_registered_location_model = [
'priority' => 10,
'is_global_location' => false,
'is_header_location' => false,
'is_footer_location' => false
];
// the model used when saving a location in db
public $default_location_model = [
'id' => '',
'level' => 'location',
'collection' => [],
'options' => [],
'ver_ini' => NIMBLE_VERSION
];
public $rendered_levels = [];//<= stores the ids of the level rendered with ::render()
public static function get_instance( $params ) {
if ( !isset( self::$instance ) && !( self::$instance instanceof Sek_Nimble_Manager ) ) {
self::$instance = new Sek_Nimble_Manager( $params );
// this hook is used to add_action( 'nimble_front_classes_ready', array( $this, 'sek_register_nimble_global_locations') );
do_action( 'nimble_front_classes_ready', self::$instance );
}
return self::$instance;
}
// store the local and global options
public $local_options = '_not_cached_yet_';
public $local_options_without_tmpl_inheritance = '_not_cached_yet_';//Introduced for site templates, when using function sek_is_inheritance_locally_disabled()
public $global_nimble_options = '_not_cached_yet_';
public $img_smartload_enabled = 'not_cached';
public $video_bg_lazyload_enabled = 'not_cached';//<= for https://github.com/presscustomizr/nimble-builder/issues/287
public $has_local_header_footer = '_not_cached_yet_';//used in sek_maybe_set_local_nimble_header() and sek_maybe_set_local_nimble_footer()
public $has_global_header_footer = '_not_cached_yet_';//used in sek_maybe_set_local_nimble_header() and sek_maybe_set_local_nimble_footer()
public $recaptcha_enabled = '_not_cached_yet_';//enabled in the global options
public $recaptcha_badge_displayed = '_not_cached_yet_';//enabled in the global options
// option key as saved in db => module_type
// is used in _1_6_5_sektions_generate_UI_global_options.js and when normalizing the global option in sek_normalize_global_options_with_defaults()
public static $global_options_map = [
'global_header_footer' => 'sek_global_header_footer',
'global_text' => 'sek_global_text',
'site_templates' => 'sek_site_tmpl_pickers',
'widths' => 'sek_global_widths',
'breakpoint' => 'sek_global_breakpoint',
'performances' => 'sek_global_performances',
'recaptcha' => 'sek_global_recaptcha',
'global_revisions' => 'sek_global_revisions',
'global_reset' => 'sek_global_reset',
'global_imp_exp' => 'sek_global_imp_exp',
'beta_features' => 'sek_global_beta_features'// may 2021 not rendered anymore in ::controls customizer
];
// option key as saved in db => module_type
// is used in _1_6_4_sektions_generate_UI_local_skope_options.js and when normalizing the global option in sek_normalize_local_options_with_defaults()
public static $local_options_map = [
'template' => 'sek_local_template',
'local_header_footer' => 'sek_local_header_footer',
'widths' => 'sek_local_widths',
'custom_css' => 'sek_local_custom_css',
'local_performances' => 'sek_local_performances',
'local_reset' => 'sek_local_reset',
'import_export' => 'sek_local_imp_exp',
'local_revisions' => 'sek_local_revisions'
];
// introduced when implementing import/export feature
// @see https://github.com/presscustomizr/nimble-builder/issues/411
public $img_import_errors = [];
// stores the active module collection
// @see populated in sek_populate_collection_of_contextually_active_modules()
// list of modules displayed on local + global sektions for a givent page.
// populated 'wp'@PHP_INT_MAX and used to
// 1) determine which module should be registered when not customizing or ajaxing. See sek_register_modules_when_not_customizing_and_not_ajaxing()
// 2) determine which assets ( css / js ) is needed for this context. see ::sek_enqueue_front_assets
//
// updated for https://github.com/presscustomizr/nimble-builder/issues/612
public $contextually_active_modules = 'not_set';
public static $ui_picker_modules = [
// UI CONTENT PICKER
'sek_content_type_switcher_module',
'sek_module_picker_module'
];
// JUNE 2020
// PREBUILT AND USER SECTION MODULES ARE REGISTERED IN add_action( 'after_setup_theme', '\Nimble\sek_schedule_module_registration', 50 );
// with sek_register_prebuilt_section_modules(); and sek_register_user_sections_module();
public static $ui_level_modules = [
// UI LEVEL MODULES
'sek_mod_option_switcher_module',
'sek_level_bg_module',
'sek_level_text_module',
'sek_level_border_module',
//'sek_level_section_layout_module',<// deactivated for now. Replaced by sek_level_width_section
'sek_level_height_module',
'sek_level_spacing_module',
'sek_level_spacing_module_for_columns',
'sek_level_width_module',
'sek_level_width_column',
'sek_level_width_section',
'sek_level_anchor_module',
'sek_level_visibility_module',
'sek_level_breakpoint_module'
];
public static $ui_local_global_options_modules = [
// local skope options modules
'sek_local_template',
'sek_local_widths',
'sek_local_custom_css',
'sek_local_reset',
'sek_local_performances',
'sek_local_header_footer',
'sek_local_revisions',
'sek_local_imp_exp',
// global options modules
'sek_global_text',
'sek_global_widths',
'sek_global_breakpoint',
'sek_global_header_footer',
'sek_global_performances',
'sek_global_recaptcha',
'sek_global_revisions',
'sek_global_reset',
'sek_global_imp_exp',
'sek_global_beta_features',
// site template options module
'sek_site_tmpl_pickers'
];
// Is merged with front module when sek_is_header_footer_enabled() === true
// @see sek_register_modules_when_customizing_or_ajaxing
// and sek_register_modules_when_not_customizing_and_not_ajaxing
public static $ui_front_beta_modules = [];
// introduced for https://github.com/presscustomizr/nimble-builder/issues/456
public $global_sections_rendered = false;
// introduced for https://github.com/presscustomizr/nimble-builder/issues/494
// september 2019
// this guid is used to differentiate dynamically rendered content from static content that may include a Nimble generated HTML structure
// an attribute "data-sek-preview-level-guid" is added to each rendered level when customizing or ajaxing
// @see ::render() method
// otherwise the preview UI can be broken
public $preview_level_guid = '_preview_level_guid_not_set_';
// March 2020 : introduction of individual stylesheet for some modules
// October 2020 : implementation of dynamic stylesheet concatenation when generating stylesheets
public $big_module_stylesheet_map = [
'czr_quote_module' => 'quote-module',
'czr_icon_module' => 'icon-module',
'czr_img_slider_module' => 'img-slider-module',
'czr_accordion_module' => 'accordion-module',
'czr_menu_module' => 'menu-module',
'czr_post_grid_module' => 'post-grid-module',
'czr_simple_form_module' => 'simple-form-module',
'czr_image_module' => 'image-module',
'czr_special_img_module' => 'special-image-module',
'czr_advanced_list_module' => 'advanced-list-module',
'czr_social_icons_module' => 'social-icons-module',
'czr_button_module' => 'button-module',
'czr_heading_module' => 'heading-module',
'czr_gallery_module' => 'gallery-module',
];
// March 2020, for https://github.com/presscustomizr/nimble-builder/issues/629
public $google_fonts_print_candidates = 'not_set';// will cache the google font candidates to print in ::_setup_hook_for_front_css_printing_or_enqueuing()
public $css_loader_html = '<div class="sek-css-loader sek-mr-loader"><div></div><div></div><div></div></div>';
// March 2020, for https://github.com/presscustomizr/nimble-builder/issues/649
public $nimble_customizing_or_content_is_printed_on_this_page = false;//<= tells if any Nimble Content has been printed.
// October 2020
public $page_has_local_or_global_sections = 'not_set';//<= set @wp_enqueue_script, used to determine if we should load css, js and fonts assets or not.
// feb 2021, introduced for #478
public $page_has_local_sections = 'not_set';
public $page_has_global_sections = 'not_set';
// April 2020 for https://github.com/presscustomizr/nimble-builder/issues/679
public $is_content_restricted = false; //<= set at 'wp'
// May 2020
// those location properties are set when walking Nimble content on rendering
// @see #705 prevent lazyloading images when in header section.
public $current_location_is_header = false;
public $current_location_is_footer = false;
// September 2020 for https://github.com/presscustomizr/nimble-builder-pro/issues/67
public $local_levels_custom_css = '';
public $global_levels_custom_css = '';
// October 2020
public $rendering = false;//<= set to true when rendering NB content
// October 2020
public $emitted_js_event = [];//<= collection of unique js event emitted with a script like nb_.emit('nb-needs-parallax')
// October 2020, for https://github.com/presscustomizr/nimble-builder/issues/751
public $partial_front_scripts = [
'slider-module' => 'nb-needs-swiper',
'menu-module' => 'nb-needs-menu-js',
'front-parallax' => 'nb-needs-parallax',
'accordion-module' => 'nb-needs-accordion'
];
// janv 2021 => will populate the modules stylesheets already concatenated, so that NB doesn't concatenate a module stylesheet twice for the local css and for the global css (if any)
// see in inc\sektions\_front_dev_php\dyn_css_builder_and_google_fonts_printer\5_0_1_class-sek-dyn-css-builder.php
public $concatenated_module_stylesheets = [];
// April 2021 => added some properties when implementing late escape for attributes
// @see ::render() and base-tmpl PHP files
public $level_css_classes;
public $level_custom_anchor;
public $level_custom_attr;
/////////////////////////////////////////////////////////////////
// <CONSTRUCTOR>
function __construct( $params = array() ) {
if ( did_action('nimble_manager_ready') )
return;
// INITIALIZE THE REGISTERED LOCATIONS WITH THE DEFAULT LOCATIONS
$this->registered_locations = $this->default_locations;
// AJAX
$this->_schedule_front_ajax_actions();
// FRONT ASSETS
$this->_schedule_front_assets_printing();
// CUSTOOMIZER PREVIEW ASSETS
$this->_schedule_preview_assets_printing();
// RENDERING
$this->_schedule_front_rendering();
// RENDERING
$this->_setup_hook_for_front_css_printing_or_enqueuing();
// LOADS SIMPLE FORM
$this->_setup_simple_forms();
// REGISTER NIMBLE WIDGET ZONES
add_action( 'widgets_init', array( $this, 'sek_nimble_widgets_init' ) );
do_action('nimble_manager_ready');
// MAYBE REGISTER PRO UPSELL MODUlES
add_filter('nb_level_module_collection', function( $module_collection ) {
if ( is_array($module_collection) && ( sek_is_pro() || sek_is_upsell_enabled() ) ) {
array_push($module_collection, 'sek_level_cust_css_level' );
array_push($module_collection, 'sek_level_animation_module' );
}
return $module_collection;
});
// see #838
// prevents using persistent cache object systems like Memcached which override the default WP class WP_Object_Cache () which is normally refreshed on each page load )
add_action('init', array( $this, 'sek_clear_cached_objects_when_customizing') );
// FLUSH CACHE OBJECT ON POST SAVE / UPDATE
// for https://github.com/presscustomizr/nimble-builder/issues/867
add_action( 'save_post', array( $this, 'sek_flush_object_cache_on_post_update') );
}//__construct
// @init
public function sek_clear_cached_objects_when_customizing() {
if ( skp_is_customizing() ) {
// Make sure cached objects are cleaned
wp_cache_flush();
}
}
// @save_post
function sek_flush_object_cache_on_post_update() {
wp_cache_flush();
}
// @fired @hook 'widgets_init'
// Creates 10 widget zones
public function sek_nimble_widgets_init() {
if ( sek_is_widget_module_disabled() )
return;
$number_of_widgets = apply_filters( 'nimble_number_of_wp_widgets', 10 );
// Header/footer, widgets module, menu module have been beta tested during 5 months and released in June 2019, in version 1.8.0
$defaults = array(
'name' => '',
'id' => '',
'description' => '',
'class' => '',
'before_widget' => '<aside id="%1$s" class="widget %2$s">',
'after_widget' => '</aside>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
);
for ( $i=1; $i < ( intval( $number_of_widgets) + 1 ); $i++ ) {
$args['id'] = NIMBLE_WIDGET_PREFIX . $i;//'nimble-widget-area-'
$args['name'] = sprintf( __('Nimble widget area #%1$s', 'text_domain_to_replace' ), $i );
$args['description'] = $args['name'];
$args = wp_parse_args( $args, $defaults );
register_sidebar( $args );
}
}
// Invoked @'after_setup_theme'
static function sek_get_front_module_collection() {
$front_module_collection = [
// FRONT MODULES
'czr_simple_html_module',
'czr_tiny_mce_editor_module' => array(
'czr_tiny_mce_editor_module',
'czr_tinymce_child',
'czr_font_child'
),
'czr_image_module' => array(
'czr_image_module',
'czr_image_main_settings_child',
'czr_image_borders_corners_child'
),
'czr_heading_module' => array(
'czr_heading_module',
'czr_heading_child',
'czr_heading_spacing_child',
'czr_font_child'
),
'czr_spacer_module',
'czr_divider_module',
'czr_icon_module' => array(
'czr_icon_module',
'czr_icon_settings_child',
'czr_icon_spacing_border_child',
),
'czr_map_module',
'czr_quote_module' => array(
'czr_quote_module',
'czr_quote_quote_child',
'czr_quote_cite_child',
'czr_quote_design_child',
),
'czr_button_module' => array(
'czr_button_module',
'czr_btn_content_child',
'czr_btn_design_child',
'czr_font_child'
),
// simple form father + children
'czr_simple_form_module' => array(
'czr_simple_form_module',
'czr_simple_form_fields_child',
'czr_simple_form_button_child',
'czr_simple_form_design_child',
'czr_simple_form_fonts_child',
'czr_simple_form_submission_child'
),
'czr_post_grid_module' => array(
'czr_post_grid_module',
'czr_post_grid_main_child',
'czr_post_grid_thumb_child',
'czr_post_grid_metas_child',
'czr_post_grid_fonts_child'
),
// widgets module, menu module have been beta tested during 5 months and released in June 2019, in version 1.8.0
'czr_menu_module' => array(
'czr_menu_module',
'czr_menu_content_child',
'czr_menu_mobile_options',
'czr_font_child'
),
//'czr_menu_design_child',
'czr_social_icons_module' => array(
'czr_social_icons_module',
'czr_social_icons_settings_child',
'czr_social_icons_style_child'
),
'czr_img_slider_module' => array(
'czr_img_slider_module',
'czr_img_slider_collection_child',
'czr_img_slider_opts_child'
),
'czr_accordion_module' => array(
'czr_accordion_module',
'czr_accordion_collection_child',
'czr_accordion_opts_child'
),
'czr_gallery_module' => array(
'czr_gallery_module',
'czr_gallery_collection_child',
'czr_gallery_opts_child'
),
'czr_shortcode_module',
];
if ( !sek_is_widget_module_disabled() ) {
$front_module_collection[] = 'czr_widget_area_module';
}
return apply_filters( 'sek_get_front_module_collection', $front_module_collection );
}
}//class
endif;
?>
@@ -0,0 +1,387 @@
<?php
if ( !class_exists( 'SEK_Front_Ajax' ) ) :
class SEK_Front_Ajax extends SEK_Front_Construct {
// Fired in __construct()
function _schedule_front_ajax_actions() {
add_action( 'wp_ajax_sek_get_content', array( $this, 'sek_get_level_content_for_injection' ) );
// Returns the customize url for the edit button when using Gutenberg editor
// implemented for https://github.com/presscustomizr/nimble-builder/issues/449
// @see assets/admin/js/nimble-gutenberg.js
add_action( 'wp_ajax_sek_get_customize_url_for_nimble_edit_button', array( $this, 'sek_get_customize_url_for_nimble_edit_button' ) );
// This is the list of accepted actions
$this->ajax_action_map = array(
'sek-add-section',
'sek-remove-section',
'sek-duplicate-section',
// fired when dropping a module or a preset_section
'sek-add-content-in-new-nested-sektion',
'sek-add-content-in-new-sektion',
// add, duplicate, remove column is a re-rendering of the parent sektion collection
'sek-add-column',
'sek-remove-column',
'sek-duplicate-column',
'sek-resize-columns',
'sek-refresh-columns-in-sektion',
'sek-add-module',
'sek-remove-module',
'sek-duplicate-module',
'sek-refresh-modules-in-column',
'sek-refresh-stylesheet',
'sek-refresh-level'
);
}
////////////////////////////////////////////////////////////////
// GENERIC HELPER FIRED IN ALL AJAX CALLBACKS
// @param $params = array('check_nonce' => true )
function sek_do_ajax_pre_checks( $params = array() ) {
$params = wp_parse_args( $params, array( 'check_nonce' => true ) );
if ( $params['check_nonce'] ) {
$action = 'save-customize_' . get_stylesheet();
if ( !check_ajax_referer( $action, 'nonce', false ) ) {
wp_send_json_error( array(
'code' => 'invalid_nonce',
'message' => __( __CLASS__ . '::' . __FUNCTION__ . ' => check_ajax_referer() failed.' ),
) );
}
}
if ( !is_user_logged_in() ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => unauthenticated' );
}
if ( !current_user_can( 'customize' ) ) {
status_header( 403 );
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => customize_not_allowed' );
} else if ( !isset( $_SERVER['REQUEST_METHOD'] ) || 'POST' !== $_SERVER['REQUEST_METHOD'] ) {
status_header( 405 );
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => bad_method' );
}
}//sek_do_ajax_pre_checks()
// hook : 'wp_ajax_sek_get_html_for_injection'
function sek_get_level_content_for_injection( $params ) {
$this->sek_do_ajax_pre_checks( array( 'check_nonce' => false ) );
if ( !isset( $_POST['location_skope_id'] ) || empty( $_POST['location_skope_id'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => missing skope_id' );
}
// introduced for https://github.com/presscustomizr/nimble-builder/issues/494
// september 2019
// this guid is used to differentiate dynamically rendered content from static content that may include a Nimble generated HTML structure
// an attribute "data-sek-preview-level-guid" is added to each rendered level when customizing or ajaxing
// otherwise the preview UI can be broken
if ( !isset( $_POST['preview-level-guid'] ) || empty( $_POST['preview-level-guid'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => missing preview-level-guid' );
}
if ( !isset( $_POST['sek_action'] ) || empty( $_POST['sek_action'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => missing sek_action' );
}
$sek_action = sanitize_text_field($_POST['sek_action']);
$exported_setting_validities = array();
// CHECK THE SETTING VALIDITIES BEFORE RENDERING
// When a module has been registered with a sanitize_callback, we can collect the possible problems here before sending the response.
// Then, on ajax.done(), in SekPreviewPrototype::schedulePanelMsgReactions, we will send the setting validities object to the panel
if ( is_customize_preview() ) {
global $wp_customize;
// prepare the setting validities so we can pass them when sending the ajax response
$setting_validities = $wp_customize->validate_setting_values( $wp_customize->unsanitized_post_values() );
$raw_exported_setting_validities = array_map( array( $wp_customize, 'prepare_setting_validity_for_js' ), $setting_validities );
// filter the setting validity to only keep the __nimble__ prefixed ui settings
$exported_setting_validities = array();
foreach( $raw_exported_setting_validities as $setting_id => $validity ) {
// don't consider the not Nimble UI settings, not starting with __nimble__
if ( false === strpos( $setting_id , NIMBLE_PREFIX_FOR_SETTING_NOT_SAVED ) )
continue;
$exported_setting_validities[ $setting_id ] = $validity;
}
}
$html = '';
// is this action possible ?
if ( in_array( $sek_action, $this->ajax_action_map ) ) {
$content_type = null;
if ( array_key_exists( 'content_type', $_POST ) && is_string( $_POST['content_type'] ) ) {
$content_type = sanitize_text_field($_POST['content_type']);
}
// This 'preset_section' === $content_type statement has been introduced when implementing support for multi-section pre-build sections
// @see https://github.com/presscustomizr/nimble-builder/issues/489
if ( 'preset_section' === $content_type ) {
switch ( $sek_action ) {
// when 'sek-add-content-in-new-sektion' is fired, the section has already been populated with a column and a module
case 'sek-add-content-in-new-sektion' :
case 'sek-add-content-in-new-nested-sektion' :
if ( 'preset_section' === $content_type ) {
if ( !array_key_exists( 'collection_of_preset_section_id', $_POST ) || !is_array( $_POST['collection_of_preset_section_id'] ) || empty( $_POST['collection_of_preset_section_id'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' ' . $sek_action .' => missing param collection_of_preset_section_id when injecting a preset section' );
break;
}
foreach ( $_POST['collection_of_preset_section_id'] as $preset_section_id ) {
$html .= $this->sek_ajax_fetch_content( $sek_action, sanitize_text_field($preset_section_id ));
}
// 'module' === $content_type
} else {
$html = $this->sek_ajax_fetch_content( $sek_action );
}
break;
default :
$html = $this->sek_ajax_fetch_content( $sek_action );
break;
}
} else {
$html = $this->sek_ajax_fetch_content( $sek_action );
}
//sek_error_log(__CLASS__ . '::' . __FUNCTION__ , $html );
if ( is_wp_error( $html ) ) {
wp_send_json_error( $html );
} else {
$response = array(
'contents' => $html,
'setting_validities' => $exported_setting_validities
);
wp_send_json_success( apply_filters( 'sek_content_results', $response, $sek_action ) );
}
} else {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => this ajax action ( ' . $sek_action . ' ) is not listed in the map ' );
}
}//sek_get_content_for_injection()
// hook : add_filter( "sek_set_ajax_content___{$action}", array( $this, 'sek_ajax_fetch_content' ) );
// $_POST looks like Array
// (
// [action] => sek_get_content
// [withNonce] => false
// [id] => __nimble__0b7c85561448ab4eb8adb978
// [skope_id] => skp__post_page_home
// [sek_action] => sek-add-section
// [SEKFrontNonce] => 3713b8ac5c
// [customized] => {\"nimble___loop_start[skp__post_page_home]\":{...}}
// )
// @return string
// @param $sek_action is $_POST['sek_action']
// @param $maybe_preset_section_id is used when injecting a collection of preset sections
private function sek_ajax_fetch_content( $sek_action = '', $maybe_preset_section_id = '' ) {
//sek_error_log( __CLASS__ . '::' . __FUNCTION__ . ' POST ?', $_POST );
// Important Notes :
// 1) at this stage => the $_POST['customized'] has already been updated
// so invoking sek_get_skoped_seks() will ensure that we get the latest data
// How $_POST['customized'] is getting populated without a full refresh of the preview ?
// a) Each time the main collection setting id is updated ( @see CZRSeksPrototype::mayBeUpdateSektionsSetting() ), api.Setting.prototype.preview sends a 'setting' event to the preview
// ( note that api.Setting.prototype.preview is overriden by NB to send other events )
// b) when the core customize-preview receives the event, it updates the customized dirties
// c) then when ajaxing, the $_POST['customized'] param is added by WP core with $.ajaxPrefilter() in customize-preview.js
//
// 2) since 'wp' hook has not been fired yet, we need to use the posted skope_id param.
$sektionSettingValue = sek_get_skoped_seks( sanitize_text_field($_POST['location_skope_id']) );
if ( !is_array( $sektionSettingValue ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => invalid sektionSettingValue => it should be an array().' );
return;
}
if ( empty( $sek_action ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => invalid sek_action param' );
return;
}
$sektion_collection = array_key_exists('collection', $sektionSettingValue) ? $sektionSettingValue['collection'] : array();
if ( !is_array( $sektion_collection ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => invalid sektion_collection => it should be an array().' );
return;
}
$candidate_id = '';
$collection = array();
$level_model = array();
$is_stylesheet = false;
switch ( $sek_action ) {
case 'sek-add-section' :
case 'sek-duplicate-section' :
if ( array_key_exists( 'is_nested', $_POST ) && true === json_decode( sanitize_text_field($_POST['is_nested']) ) ) {
// we need to set the parent_mode here to access it later in the ::render method to calculate the column width.
$this->parent_model = sek_get_level_model( sanitize_text_field($_POST[ 'in_sektion' ]), $sektion_collection );
$level_model = sek_get_level_model( sanitize_text_field($_POST[ 'in_column' ]), $sektion_collection );
} else {
//$level_model = sek_get_level_model( $_POST[ 'id' ], $sektion_collection );
$level_model = sek_get_level_model( sanitize_text_field($_POST[ 'id' ]), $sektion_collection );
}
break;
// This $content_type var has been introduced when implementing support for multi-section pre-build sections
// @see https://github.com/presscustomizr/nimble-builder/issues/489
// when 'sek-add-content-in-new-sektion' is fired, the section has already been populated with a column and a module
case 'sek-add-content-in-new-sektion' :
case 'sek-add-content-in-new-nested-sektion' :
$content_type = null;
if ( array_key_exists( 'content_type', $_POST ) && is_string( $_POST['content_type'] ) ) {
$content_type = sanitize_text_field($_POST['content_type']);
}
if ( 'preset_section' === $content_type ) {
if ( !array_key_exists( 'collection_of_preset_section_id', $_POST ) || !is_array( $_POST['collection_of_preset_section_id'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' ' . $sek_action .' => missing param collection_of_preset_section_id when injecting a preset section' );
break;
}
if ( !is_string( $maybe_preset_section_id ) || empty( $maybe_preset_section_id ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' ' . $sek_action .' => invalid preset section id' );
break;
}
$level_id = $maybe_preset_section_id;
// module content type case.
// the level id has been passed the regular way
} else {
$level_id = sanitize_text_field($_POST[ 'id' ]);
}
if ( array_key_exists( 'is_nested', $_POST ) && true === json_decode( sanitize_text_field($_POST['is_nested']) ) ) {
// we need to set the parent_mode here to access it later in the ::render method to calculate the column width.
$this->parent_model = sek_get_level_model( sanitize_text_field($_POST[ 'in_sektion' ]), $sektion_collection );
$level_model = sek_get_level_model( sanitize_text_field($_POST[ 'in_column' ]), $sektion_collection );
} else {
$level_model = sek_get_level_model( $level_id, $sektion_collection );
}
break;
//only used for nested section
case 'sek-remove-section' :
if ( !array_key_exists( 'is_nested', $_POST ) || true !== json_decode( sanitize_text_field($_POST['is_nested'] )) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' ' . $sek_action .' => the section must be nested in this ajax action' );
break;
} else {
// we need to set the parent_model here to access it later in the ::render method to calculate the column width.
$this->parent_model = sek_get_parent_level_model( sanitize_text_field($_POST[ 'in_column' ]), $sektion_collection );
$level_model = sek_get_level_model( sanitize_text_field($_POST[ 'in_column' ]), $sektion_collection );
}
break;
// We re-render the entire parent sektion collection in all cases
case 'sek-add-column' :
case 'sek-remove-column' :
case 'sek-duplicate-column' :
case 'sek-refresh-columns-in-sektion' :
if ( !array_key_exists( 'in_sektion', $_POST ) || empty( $_POST['in_sektion'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' ' . $sek_action .' => missing in_sektion param' );
break;
}
// sek_error_log('sektion_collection', $sektion_collection );
$level_model = sek_get_level_model( sanitize_text_field($_POST[ 'in_sektion' ]), $sektion_collection );
break;
// We re-render the entire parent column collection
case 'sek-add-module' :
case 'sek-remove-module' :
case 'sek-refresh-modules-in-column' :
case 'sek-duplicate-module' :
if ( !array_key_exists( 'in_column', $_POST ) || empty( $_POST['in_column'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' ' . $sek_action .' => missing in_column param' );
break;
}
if ( !array_key_exists( 'in_sektion', $_POST ) || empty( $_POST[ 'in_sektion' ] ) ) {
$this->parent_model = sek_get_parent_level_model( sanitize_text_field($_POST[ 'in_column' ]), $sektion_collection );
} else {
$this->parent_model = sek_get_level_model( sanitize_text_field($_POST[ 'in_sektion' ]), $sektion_collection );
}
$level_model = sek_get_level_model( sanitize_text_field($_POST[ 'in_column' ]), $sektion_collection );
break;
case 'sek-resize-columns' :
if ( !array_key_exists( 'resized_column', $_POST ) || empty( $_POST['resized_column'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' ' . $sek_action .' => missing resized_column' );
break;
}
$is_stylesheet = true;
break;
case 'sek-refresh-stylesheet' :
$is_stylesheet = true;
break;
case 'sek-refresh-level' :
if ( !array_key_exists( 'id', $_POST ) || empty( $_POST['id'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' ' . $sek_action .' => missing level id' );
break;
}
if ( !empty( $_POST['level'] ) && 'column' === sanitize_text_field($_POST['level']) ) {
// we need to set the parent_mode here to access it later in the ::render method to calculate the column width.
$this->parent_model = sek_get_parent_level_model( sanitize_text_field($_POST['id']), $sektion_collection );
}
$level_model = sek_get_level_model( sanitize_text_field($_POST[ 'id' ]), $sektion_collection );
break;
}//Switch sek_action
// sek_error_log('LEVEL MODEL WHEN AJAXING', $level_model );
ob_start();
if ( $is_stylesheet ) {
$r = $this->print_or_enqueue_seks_style( sanitize_text_field($_POST['location_skope_id']) );
} else {
if ( 'no_match' == $level_model ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' ' . $sek_action . ' => missing level model' );
ob_end_clean();
return;
}
if ( empty( $level_model ) || !is_array( $level_model ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => empty or invalid $level_model' );
ob_end_clean();
return;
}
// note that in the case of a sektion nested inside a column, the parent_model has been set in the switch{ case : ... } above ,so we can access it in the ::render method to calculate the column width.
$r = $this->render( $level_model );
}
$html = ob_get_clean();
if ( is_wp_error( $r ) ) {
return $r;
} else {
// the $html content should not be empty when ajaxing a template
// it can be empty when ajaxing a stylesheet
if ( !$is_stylesheet && empty( $html ) ) {
// return a new WP_Error that will be intercepted in sek_get_level_content_for_injection
$html = new \WP_Error( 'ajax_fetch_content_error', __CLASS__ . '::' . __FUNCTION__ . ' => no content returned for sek_action : ' . $sek_action );
}
return apply_filters( "sek_set_ajax_content", $html, $sek_action );// this is sent with wp_send_json_success( apply_filters( 'sek_content_results', $html, $sek_action ) );
}
}
////////////////////////////////////////////////////////////////
// USED TO PRINT THE BUTTON EDIT WITH NIMBLE ON POSTS AND PAGES
// when using Gutenberg editor
// implemented for https://github.com/presscustomizr/nimble-builder/issues/449
function sek_get_customize_url_for_nimble_edit_button() {
$this->sek_do_ajax_pre_checks( array( 'check_nonce' => false ) );
if ( !isset( $_POST['nimble_edit_post_id'] ) || empty( $_POST['nimble_edit_post_id'] ) ) {
wp_send_json_error( __CLASS__ . '::' . __FUNCTION__ . ' => missing post_id' );
}
$post_id = sanitize_text_field($_POST['nimble_edit_post_id']);
// Build customize_url
// @see function sek_get_customize_url_when_is_admin()
$return_url_after_customization = '';//"/wp-admin/post.php?post={$post_id}&action=edit";
$customize_url = sek_get_customize_url_for_post_id( $post_id, $return_url_after_customization );
wp_send_json_success( $customize_url );
}
}//class
endif;
?>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,326 @@
<?php
if ( !class_exists( 'SEK_Front_Assets_Customizer_Preview' ) ) :
class SEK_Front_Assets_Customizer_Preview extends SEK_Front_Assets {
// Fired in __construct()
function _schedule_preview_assets_printing() {
add_action( 'wp_footer', array( $this, 'sek_customizr_js_stuff' ), PHP_INT_MAX );
// Load customize preview js
add_action( 'customize_preview_init', array( $this, 'sek_schedule_customize_preview_assets' ) );
}//_schedule_preview_assets_printing
// @'wp_footer'
function sek_customizr_js_stuff() {
if ( !sek_current_user_can_access_nb_ui() )
return;
if( !skp_is_customizing() )
return;
ob_start();
?>
(function(w, d){
nb_.listenTo( 'nb-app-ready', function() {
//PREVIEWED DEVICE ?
//Listen to the customizer previewed device
var _setPreviewedDevice = function() {
wp.customize.preview.bind( 'previewed-device', function( device ) {
nb_.previewedDevice = device;// desktop, tablet, mobile
});
};
if ( wp.customize.preview ) {
_setPreviewedDevice();
} else {
wp.customize.bind( 'preview-ready', function() {
_setPreviewedDevice();
});
}
// REVEAL BG IMAGE ON CHANGE ?
jQuery( function($) {
$('body').on( 'sek-level-refreshed', '[data-sek-level="location"]', function( evt, params ) {
var matches = document.querySelectorAll('div.sek-has-bg');
if ( !nb_.isObject( matches ) || matches.length < 1 )
return;
var imgSrc;
matches.forEach( function(el) {
if ( !nb_.isObject(el) )
return;
// Maybe reveal BG if lazyload is on
if ( nb_.isCustomizing() ) {
nb_.mayBeRevealBG.call(el);
}
});
});
});
});
}(window, document));
<?php
$script = ob_get_clean();
wp_add_inline_script( 'nb-js-init', $script );
}
// enqueue / print customize preview assets
// hook : 'customize_preview_init'
function sek_schedule_customize_preview_assets() {
if ( !sek_current_user_can_access_nb_ui() )
return;
// we don't need those assets when previewing a customize changeset
// added when fixing https://github.com/presscustomizr/nimble-builder/issues/351
if ( sek_is_customize_previewing_a_changeset_post() )
return;
// Load preview ui js tmpl
add_action( 'wp_footer', array( $this, 'sek_print_ui_tmpl' ) );
wp_enqueue_style(
'sek-preview',
sprintf(
'%1$s/assets/czr/sek/css/%2$s' ,
NIMBLE_BASE_URL,
sek_is_dev_mode() ? 'sek-preview.css' : 'sek-preview.min.css'
),
array( 'sek-base' ),
NIMBLE_ASSETS_VERSION,
'all'
);
// Communication between preview and customizer panel
wp_enqueue_script(
'sek-customize-preview',
sprintf(
'%1$s/assets/czr/sek/js/%2$s' ,
NIMBLE_BASE_URL,
sek_is_dev_mode() ? 'ccat-sek-preview.js' : 'ccat-sek-preview.min.js'
),
array( 'customize-preview', 'underscore'),
NIMBLE_ASSETS_VERSION,
true
);
wp_localize_script(
'sek-customize-preview',
'sekPreviewLocalized',
array(
'i18n' => array(
"You've reached the maximum number of columns allowed in this section." => __( "You've reached the maximum number of columns allowed in this section.", 'text_doma'),
"Moving elements between global and local sections is not allowed." => __( "Moving elements between global and local sections is not allowed.", 'text_doma'),
'Something went wrong, please refresh this page.' => __('Something went wrong, please refresh this page.', 'text_doma'),
'Insert here' => __('Insert here', 'text_doma'),
'This content has been created with the WordPress editor.' => __('This content has been created with the WordPress editor.', 'text_domain' ),
'Insert a new section' => __('Insert a new section', 'text_doma' ),
'@location' => __('@location', 'text_domain_to_be'),
'Insert a new global section' => __('Insert a new global section', 'text_doma' ),
'section' => __('section', 'text_doma'),
'header section' => __('header section', 'text_doma'),
'footer section' => __('footer section', 'text_doma'),
'(global)' => __('(global)', 'text_doma'),
'nested section' => __('nested section', 'text_doma'),
'Shift-click to visit the link' => __('Shift-click to visit the link', 'text_doma'),
'External links are disabled when customizing' => __('External links are disabled when customizing', 'text_doma'),
'Link deactivated while previewing' => __('Link deactivated while previewing', 'text_doma')
),
'isDevMode' => sek_is_dev_mode(),
'isPreviewUIDebugMode' => isset( $_GET['preview_ui_debug'] ) || NIMBLE_IS_PREVIEW_UI_DEBUG_MODE,
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'frontNonce' => array( 'id' => 'SEKFrontNonce', 'handle' => wp_create_nonce( 'sek-front-nonce' ) ),
'registeredModules' => CZR_Fmk_Base()->registered_modules,
// introduced for https://github.com/presscustomizr/nimble-builder/issues/494
// september 2019
// this guid is used to differentiate dynamically rendered content from static content that may include a Nimble generated HTML structure
// an attribute "data-sek-preview-level-guid" is added to each rendered level when customizing or ajaxing
// when generating the ui, we check if the localized guid matches the one rendered server side
// otherwise the preview UI can be broken
'previewLevelGuid' => $this->sek_get_preview_level_guid(),
// Assets id
'googleFontsStyleId' => NIMBLE_GOOGLE_FONTS_STYLESHEET_ID,
'globalOptionsStyleId' => NIMBLE_GLOBAL_OPTIONS_STYLESHEET_ID
)
);
wp_enqueue_script( 'jquery-ui-sortable' );
wp_enqueue_style(
'ui-sortable',
'//code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css',
array(),
null,//time(),
$media = 'all'
);
wp_enqueue_script( 'jquery-ui-resizable' );
}
//'wp_footer' in the preview frame
function sek_print_ui_tmpl() {
?>
<script type="text/html" id="sek-tmpl-add-content-button">
<# //console.log( 'data', data ); #>
<div class="sek-add-content-button <# if ( data.is_last ) { #>is_last<# } #>">
<div class="sek-add-content-button-wrapper">
<# var hook_location = '', btn_title = true !== data.is_global_location ? sekPreviewLocalized.i18n['Insert a new section'] : sekPreviewLocalized.i18n['Insert a new global section'], addContentBtnWidth = true !== data.is_global_location ? '83px' : '113px' #>
<# if ( data.location ) {
hook_location = ['(' , sekPreviewLocalized.i18n['@location'] , ':"',data.location , '")'].join('');
} #>
<button title="{{btn_title}} {{hook_location}}" data-sek-click-on="add-content" data-sek-add="section" class="sek-add-content-btn" style="--sek-add-content-btn-width:{{addContentBtnWidth}};">
<span class="sek-click-on-button-icon sek-click-on">+</span><span class="action-button-text">{{btn_title}}</span>
</button>
</div>
</div>
</script>
<?php
$icon_right_side_class = is_rtl() ? 'sek-dyn-left-icons' : 'sek-dyn-right-icons';
$icon_left_side_class = is_rtl() ? 'sek-dyn-right-icons' : 'sek-dyn-left-icons';
?>
<script type="text/html" id="sek-dyn-ui-tmpl-section">
<?php //<# console.log( 'data', data ); #> ?>
<div class="sek-dyn-ui-wrapper sek-section-dyn-ui">
<div class="sek-dyn-ui-inner <?php echo esc_attr($icon_left_side_class); ?>">
<div class="sek-dyn-ui-icons">
<?php if ( sek_is_dev_mode() ) : ?>
<i class="sek-to-json fas fa-code"></i>
<?php endif; ?>
<?php
// Code before implementing https://github.com/presscustomizr/nimble-builder/issues/521 :
/* <# if ( true !== data.is_first_section_in_parent ) { #>
<i data-sek-click-on="move-section-up" class="material-icons sek-click-on" title="<?php _e( 'Move section up', 'text_domain' ); ?>">keyboard_arrow_up</i>
<# } #>
<# if ( true !== data.is_last_section_in_parent ) { #>
<i data-sek-click-on="move-section-down" class="material-icons sek-click-on" title="<?php _e( 'Move section down', 'text_domain' ); ?>">keyboard_arrow_down</i>
<# } #>*/
?>
<i data-sek-click-on="move-section-up" class="material-icons sek-click-on" title="<?php _e( 'Move section up', 'text_domain' ); ?>">keyboard_arrow_up</i>
<i data-sek-click-on="move-section-down" class="material-icons sek-click-on" title="<?php _e( 'Move section down', 'text_domain' ); ?>">keyboard_arrow_down</i>
<?php // if this is a nested section, it has the is_nested property set to true. We don't want to make it draggable for the moment. @todo ?>
<# if ( !data.is_nested ) { #>
<# if ( true !== data.is_global_location ) { #>
<i class="fas fa-arrows-alt sek-move-section" title="<?php _e( 'Drag section', 'text_domain' ); ?>"></i>
<# } #>
<# } #>
<i data-sek-click-on="edit-options" class="material-icons sek-click-on" title="<?php _e( 'Edit section settings', 'text_domain' ); ?>">tune</i>
<# if ( data.can_have_more_columns ) { #>
<i data-sek-click-on="add-column" class="material-icons sek-click-on" title="<?php _e( 'Add a column', 'text_domain' ); ?>">view_column</i>
<# } #>
<i data-sek-click-on="duplicate" class="material-icons sek-click-on" title="<?php _e( 'Duplicate section', 'text_domain' ); ?>">filter_none</i>
<i data-sek-click-on="toggle-save-section-ui" class="sek-save far fa-save" title="<?php _e( 'Save this section', 'text_domain' ); ?>"></i>
<i data-sek-click-on="remove" class="material-icons sek-click-on" title="<?php _e( 'Remove section', 'text_domain' ); ?>">delete_forever</i>
</div>
</div><?php // .sek-dyn-ui-inner ?>
<div class="sek-dyn-ui-location-type" data-sek-click-on="edit-options" title="<?php _e( 'Edit section settings', 'text_domain' ); ?>">
<div class="sek-dyn-ui-location-inner">
<div class="sek-dyn-ui-hamb-menu-wrapper sek-collapsed">
<div class="sek-ham__toggler-spn-wrapper"><span class="line line-1"></span><span class="line line-2"></span><span class="line line-3"></span></div>
</div>
<#
var section_title = true !== data.is_global_location ? sekPreviewLocalized.i18n['section'] : sekPreviewLocalized.i18n['section (global)'];
var section_title = !data.is_nested ? sekPreviewLocalized.i18n['section'] : sekPreviewLocalized.i18n['nested section'];
if ( true === data.is_header_location && !data.is_nested ) {
section_title = sekPreviewLocalized.i18n['header section'];
} else if ( true === data.is_footer_location && !data.is_nested ) {
section_title = sekPreviewLocalized.i18n['footer section'];
}
section_title = true !== data.is_global_location ? section_title : [ section_title, sekPreviewLocalized.i18n['(global)'] ].join(' ');
#>
<div class="sek-dyn-ui-level-type">{{section_title}}</div>
</div><?php // .sek-dyn-ui-location-inner ?>
<div class="sek-minimize-ui" title="<?php _e('Hide this menu if you need to access behind', 'text-domain'); ?>"><i class="far fa-eye-slash"></i></div>
</div><?php // .sek-dyn-ui-location-type ?>
</div><?php // .sek-dyn-ui-wrapper ?>
</script>
<script type="text/html" id="sek-dyn-ui-tmpl-column">
<?php //<# console.log( 'data', data ); #> ?>
<?php
// when a column has nested section(s), its ui might be hidden by deeper columns.
// that's why a CSS class is added to position it on the top right corner, instead of bottom right
// @see https://github.com/presscustomizr/nimble-builder/issues/488
?>
<# var has_nested_section_class = true === data.has_nested_section ? 'sek-col-has-nested-section' : ''; #>
<div class="sek-dyn-ui-wrapper sek-column-dyn-ui {{has_nested_section_class}}">
<div class="sek-dyn-ui-inner <?php echo esc_attr($icon_right_side_class); ?>">
<div class="sek-dyn-ui-icons">
<i class="fas fa-arrows-alt sek-move-column" title="<?php _e( 'Move column', 'text_domain' ); ?>"></i>
<i data-sek-click-on="edit-options" class="material-icons sek-click-on" title="<?php _e( 'Edit column settings', 'text_domain' ); ?>">tune</i>
<# if ( !data.parent_is_last_allowed_nested ) { #>
<i data-sek-click-on="add-section" class="material-icons sek-click-on" title="<?php _e( 'Add a nested section', 'text_domain' ); ?>">account_balance_wallet</i>
<# } #>
<# if ( data.parent_can_have_more_columns ) { #>
<i data-sek-click-on="duplicate" class="material-icons sek-click-on" title="<?php _e( 'Duplicate column', 'text_domain' ); ?>">filter_none</i>
<# } #>
<i data-sek-click-on="pick-content" data-sek-content-type="module" class="material-icons sek-click-on" title="<?php _e( 'Add a module', 'text_domain' ); ?>">add_circle_outline</i>
<# if ( !data.parent_is_single_column ) { #>
<i data-sek-click-on="remove" class="material-icons sek-click-on" title="<?php _e( 'Remove column', 'text_domain' ); ?>">delete_forever</i>
<# } #>
</div>
</div><?php // .sek-dyn-ui-inner ?>
<div class="sek-dyn-ui-location-type" data-sek-click-on="edit-options" title="<?php _e( 'Edit column settings', 'text_domain' ); ?>">
<div class="sek-minimize-ui" title="<?php _e('Hide this menu if you need to access behind', 'text-domain'); ?>"><i class="far fa-eye-slash"></i></div>
<div class="sek-dyn-ui-location-inner">
<div class="sek-dyn-ui-hamb-menu-wrapper sek-collapsed">
<div class="sek-ham__toggler-spn-wrapper"><span class="line line-1"></span><span class="line line-2"></span><span class="line line-3"></span></div>
</div>
<div class="sek-dyn-ui-level-type"><?php _e( 'column', 'text_domain' ); ?></div>
</div><?php // .sek-dyn-ui-location-inner ?>
</div><?php // .sek-dyn-ui-location-type ?>
</div><?php // .sek-dyn-ui-wrapper ?>
</script>
<script type="text/html" id="sek-dyn-ui-tmpl-module">
<div class="sek-dyn-ui-wrapper sek-module-dyn-ui">
<div class="sek-dyn-ui-inner <?php echo esc_attr($icon_left_side_class); ?>">
<div class="sek-dyn-ui-icons">
<i class="fas fa-arrows-alt sek-move-module" title="<?php _e( 'Move module', 'text_domain' ); ?>"></i>
<i data-sek-click-on="edit-module" class="fas fa-pencil-alt sek-tip sek-click-on" title="<?php _e( 'Edit module content', 'text_domain' ); ?>"></i>
<i data-sek-click-on="edit-options" class="material-icons sek-click-on" title="<?php _e( 'Edit module settings', 'text_domain' ); ?>">tune</i>
<i data-sek-click-on="duplicate" class="material-icons sek-click-on" title="<?php _e( 'Duplicate module', 'text_domain' ); ?>">filter_none</i>
<i data-sek-click-on="remove" class="material-icons sek-click-on" title="<?php _e( 'Remove module', 'text_domain' ); ?>">delete_forever</i>
</div>
</div><?php // .sek-dyn-ui-inner ?>
<#
var module_name = !_.isEmpty( data.module_name ) ? data.module_name + ' ' + '<?php _e("module", "text_domain"); ?>' : '<?php _e("module", "text_domain"); ?>';
#>
<div class="sek-dyn-ui-location-type" data-sek-click-on="edit-module" title="<?php _e( 'Edit module settings', 'text_domain' ); ?>">
<div class="sek-dyn-ui-location-inner">
<div class="sek-dyn-ui-hamb-menu-wrapper sek-collapsed">
<div class="sek-ham__toggler-spn-wrapper"><span class="line line-1"></span><span class="line line-2"></span><span class="line line-3"></span></div>
</div>
<div class="sek-dyn-ui-level-type">{{module_name}}</div>
</div>
<div class="sek-minimize-ui" title="<?php _e('Hide this menu if you need to access behind', 'text-domain'); ?>"><i class="far fa-eye-slash"></i></div>
</div>
</div><?php // .sek-dyn-ui-wrapper ?>
</script>
<script type="text/html" id="sek-dyn-ui-tmpl-wp-content">
<div class="sek-dyn-ui-wrapper sek-wp-content-dyn-ui">
<div class="sek-dyn-ui-inner">
<div class="sek-dyn-ui-icons">
<i class="fas fa-pencil-alt sek-edit-wp-content" title="<?php _e( 'Edit this WordPress content', 'text_domain' ); ?>"></i>
</div>
</div><?php // .sek-dyn-ui-inner ?>
<span class="sek-dyn-ui-location-type" title="<?php _e( 'Edit module settings', 'text_domain' ); ?>">
<i class="fab fa-wordpress sek-edit-wp-content" title="<?php _e( 'Edit this WordPress content', 'text_domain' ); ?>"> <?php _e( 'WordPress content', 'text_domain'); ?></i>
</span>
</div><?php // .sek-dyn-ui-wrapper ?>
</script>
<?php
}
}//class
endif;
?>
@@ -0,0 +1,229 @@
<?php
if ( !class_exists( 'SEK_Front_Render_Css' ) ) :
class SEK_Front_Render_Css extends SEK_Front_Render {
// Fired in __construct()
function _setup_hook_for_front_css_printing_or_enqueuing() {
add_action( 'wp_enqueue_scripts', array( $this, 'print_or_enqueue_seks_style'), PHP_INT_MAX );
// wp_add_inline_style for global CSS
add_action( 'wp_head', array( $this, 'sek_enqueue_global_css' ) );
}
// Can be fired :
// 1) on wp_enqueue_scripts or wp_head
// 2) when ajaxing, for actions 'sek-resize-columns', 'sek-refresh-stylesheet'
function print_or_enqueue_seks_style( $skope_id = null ) {
// when this method is fired in a customize preview context :
// - the skope_id has to be built. Since we are after 'wp', this is not a problem.
// - the css rules are printed inline in the <head>
// - we set to hook to wp_head
//
// when the method is fired in an ajax refresh scenario, like 'sek-refresh-stylesheet'
// - the skope_id must be passed as param
// - the css rules are printed inline in the <head>
// - we set the hook to ''
// AJAX REQUESTED STYLESHEET
if ( ( !is_null( $skope_id ) && !empty( $skope_id ) ) && ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
if ( !isset($_POST['local_skope_id']) ) {
sek_error_log( __CLASS__ . '::' . __FUNCTION__ . ' => error missing local_skope_id');
return;
}
$local_skope_id = sanitize_text_field($_POST['local_skope_id']);
// Feb 2021 => for site template #478
$local_skope_id = apply_filters( 'nb_set_skope_id_before_generating_local_front_css', $local_skope_id );
$css_handler_instance = $this->_instantiate_css_handler( array( 'skope_id' => $skope_id, 'is_global_stylesheet' => NIMBLE_GLOBAL_SKOPE_ID === $skope_id ) );
$this->sek_get_global_css_for_ajax();
}
// in a front normal context, the css is enqueued from the already written file.
else {
// Feb 2021 => for site template #478
$local_skope_id = apply_filters( 'nb_set_skope_id_before_generating_local_front_css', skp_build_skope_id() );
// LOCAL SECTIONS STYLESHEET
$this->_instantiate_css_handler( array( 'skope_id' => $local_skope_id ) );
// GLOBAL SECTIONS STYLESHEET
// Can hold rules for global sections and global styling
$this->_instantiate_css_handler( array( 'skope_id' => NIMBLE_GLOBAL_SKOPE_ID, 'is_global_stylesheet' => true ) );
}
$google_fonts_print_candidates = $this->sek_get_gfont_print_candidates( $local_skope_id );
// GOOGLE FONTS
if ( !empty( $google_fonts_print_candidates ) ) {
// When customizing we get the google font content
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
$this->sek_get_gfont_in_ajax( $google_fonts_print_candidates );
} else {
// preload implemented for https://github.com/presscustomizr/nimble-builder/issues/629
if ( !skp_is_customizing() && sek_preload_google_fonts_on_front() ) {
add_action( 'wp_head', array( $this, 'sek_gfont_print_with_preload') );
} else {
// March 2020 added param display=swap => Ensure text remains visible during webfont load #572
wp_enqueue_style(
NIMBLE_GOOGLE_FONTS_STYLESHEET_ID,
sprintf( '//fonts.googleapis.com/css?family=%s&display=swap', $google_fonts_print_candidates ),
array(),
null,
'all'
);
}
}
}
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && empty( $local_skope_id ) ) {
sek_error_log( __CLASS__ . '::' . __FUNCTION__ . ' => the skope_id should not be empty' );
}
}//print_or_enqueue_seks_style
// @param params = array( array( 'skope_id' => NIMBLE_GLOBAL_SKOPE_ID, 'is_global_stylesheet' => true ) )
// fired @'wp_enqueue_scripts'
private function _instantiate_css_handler( $params = array() ) {
$params = wp_parse_args( $params, array( 'skope_id' => '', 'is_global_stylesheet' => false ) );
// Print inline or enqueue ?
$print_mode = Sek_Dyn_CSS_Handler::MODE_FILE;
if ( is_customize_preview() ) {
$print_mode = Sek_Dyn_CSS_Handler::MODE_INLINE;
}
// Which hook ?
$fire_at_hook = '';
if ( !defined( 'DOING_AJAX' ) && is_customize_preview() ) {
$fire_at_hook = 'wp_head';
}
$css_handler_instance = new Sek_Dyn_CSS_Handler( array(
'id' => $params['skope_id'],
'skope_id' => $params['skope_id'],
// property "is_global_stylesheet" has been added when fixing https://github.com/presscustomizr/nimble-builder/issues/273
'is_global_stylesheet' => $params['is_global_stylesheet'],
'mode' => $print_mode,
//these are taken in account only when 'mode' is 'file'
'force_write' => true, //<- write if the file doesn't exist
'force_rewrite' => is_user_logged_in() && current_user_can( 'customize' ), //<- write even if the file exists
'hook' => $fire_at_hook
));
return $css_handler_instance;
}
// When ajaxing, the link#sek-gfonts-{$this->id} gets removed from the dom and replaced by this string
// March 2020 added param display=swap => Ensure text remains visible during webfont load #572
function sek_get_gfont_in_ajax( $print_candidates ) {
if ( !empty( $print_candidates ) ) {
printf('<link rel="stylesheet" id="%1$s" href="%2$s">',
esc_attr(NIMBLE_GOOGLE_FONTS_STYLESHEET_ID),
esc_url("//fonts.googleapis.com/css?family={$print_candidates}&display=swap")
);
}
}
// hook : wp_footer
// fired on front only when not customizing
// March 2020 preload implemented for https://github.com/presscustomizr/nimble-builder/issues/629
// March 2020 added param display=swap => Ensure text remains visible during webfont load #572
function sek_gfont_print_with_preload( $print_candidates = '' ) {
// Check that current page has Nimble content before printing any Google fonts
// For https://github.com/presscustomizr/nimble-builder/issues/649
if ( !Nimble_Manager()->page_has_local_or_global_sections )
return;
// print candidates must be fetched when sek_preload_google_fonts_on_front()
$print_candidates = $this->sek_get_gfont_print_candidates();
if ( !empty( $print_candidates ) ) {
ob_start();
?>
nb_.preloadOrDeferAsset( { id : '<?php echo esc_attr(NIMBLE_GOOGLE_FONTS_STYLESHEET_ID); ?>', as : 'style', href : '//fonts.googleapis.com/css?family=<?php echo esc_attr($print_candidates); ?>&display=swap', scriptEl : document.currentScript } );
<?php
$script = ob_get_clean();
wp_register_script( 'nb_preload_gfonts', '');
wp_enqueue_script( 'nb_preload_gfonts' );
wp_add_inline_script( 'nb_preload_gfonts', $script );
}
}
// invoked when ajaxing during customization
function sek_get_global_css_for_ajax() {
// During customization, always rebuild the css from fresh values instead of relying on the saved option
// because on first call we get the customized option value, but on another one quickly after, we get the current option value in the database
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
$global_css = $this->sek_build_global_options_inline_css();
if ( is_string( $global_css ) && !empty( $global_css ) ) {
printf('<style id="%1$s">%2$s</style>', NIMBLE_GLOBAL_OPTIONS_STYLESHEET_ID, $global_css );
}
}
}
// hook wp_enqueue_script
function sek_enqueue_global_css() {
$global_css = get_option(NIMBLE_OPT_FOR_GLOBAL_CSS);
// following https://developer.wordpress.org/reference/functions/wp_add_inline_script/#comment-5304
wp_register_style( NIMBLE_GLOBAL_OPTIONS_STYLESHEET_ID, false );
wp_enqueue_style( NIMBLE_GLOBAL_OPTIONS_STYLESHEET_ID );
wp_add_inline_style( NIMBLE_GLOBAL_OPTIONS_STYLESHEET_ID, $global_css );
}
// Maybe update global inline style with a filter
// @return a css string
// This CSS is the one generated by global options like global text, global width, global breakpoint
function sek_build_global_options_inline_css() {
return apply_filters('nimble_set_global_inline_style', '');
}
//@return string
// sek_model is passed when customizing in SEK_Front_Render_Css::print_or_enqueue_seks_style()
function sek_get_gfont_print_candidates( $local_skope_id = null ) {
// return the cache version if already set
if ( 'not_set' !== Nimble_Manager()->google_fonts_print_candidates )
return Nimble_Manager()->google_fonts_print_candidates;
$local_skope_id = is_null( $local_skope_id ) ? apply_filters( 'maybe_set_skope_id_for_site_template_css', skp_build_skope_id() ) : $local_skope_id;
// local sections
$local_seks = sek_get_skoped_seks( $local_skope_id );
// global sections
$global_seks = sek_get_skoped_seks( NIMBLE_GLOBAL_SKOPE_ID );
// global options
$global_options = get_option( NIMBLE_OPT_NAME_FOR_GLOBAL_OPTIONS );
$print_candidates = '';
$ffamilies = array();
// Let's build the collection of google fonts from local sections, global sections, global options
if ( is_array( $local_seks ) && !empty( $local_seks['fonts'] ) && is_array( $local_seks['fonts'] ) ) {
$ffamilies = $local_seks['fonts'];
}
if ( is_array( $global_seks ) && !empty( $global_seks['fonts'] ) && is_array( $global_seks['fonts'] ) ) {
$ffamilies = array_merge( $ffamilies, $global_seks['fonts'] );
}
if ( is_array( $global_options ) && !empty( $global_options['fonts'] ) && is_array( $global_options['fonts'] ) ) {
$ffamilies = array_merge( $ffamilies, $global_options['fonts'] );
}
// remove duplicate if any
$ffamilies = array_unique( $ffamilies );
if ( !empty( $ffamilies ) ) {
$ffamilies = implode( "|", $ffamilies );
$print_candidates = str_replace( '|', '%7C', $ffamilies );
$print_candidates = str_replace( '[gfont]', '' , $print_candidates );
}
// cache now
Nimble_Manager()->google_fonts_print_candidates = $print_candidates;
return Nimble_Manager()->google_fonts_print_candidates;
}
}//class
endif;
?>
@@ -0,0 +1,12 @@
<?php
if ( !class_exists( '\Nimble\Sek_Nimble_Manager' ) ) :
final class Sek_Nimble_Manager extends Sek_Simple_Form {}
endif;
function Nimble_Manager( $params = array() ) {
return Sek_Nimble_Manager::get_instance( $params );
}
Nimble_Manager();
?>
@@ -0,0 +1,75 @@
<?php
namespace Nimble;
if ( !defined( 'ABSPATH' ) ) {
exit;
}
// @return bool
function sek_is_dev_mode() {
return ( defined( 'NIMBLE_DEV' ) && NIMBLE_DEV ) || ( defined( 'WP_DEBUG' ) && WP_DEBUG );
}
// @return bool
// Nov 2020 : helper used to display NB CPT in admin
function sek_is_cpt_debug_mode() {
return isset( $_GET['nimble_cpt_debug'] ) || (defined('NIMBLE_CPT_DEBUG_MODE') && NIMBLE_CPT_DEBUG_MODE);
}
if ( !defined( 'NIMBLE_CPT' ) ) { define( 'NIMBLE_CPT' , 'nimble_post_type' ); }
if ( !defined( 'NIMBLE_TEMPLATE_CPT' ) ) { define( 'NIMBLE_TEMPLATE_CPT' , 'nimble_template' ); }
if ( !defined( 'NIMBLE_SECTION_CPT' ) ) { define( 'NIMBLE_SECTION_CPT' , 'nimble_section' ); }
if ( !defined( 'NIMBLE_PREFIX_FOR_SAVED_TMPL' ) ) { define( 'NIMBLE_PREFIX_FOR_SAVED_TMPL' , 'nb_tmpl_' ); }
if ( !defined( 'NIMBLE_PREFIX_FOR_SAVED_SECTION' ) ) { define( 'NIMBLE_PREFIX_FOR_SAVED_SECTION' , 'nb_section_' ); }
if ( !defined( 'NIMBLE_DEPREC_ONE_CSS_FOLDER_NAME' ) ) { define( 'NIMBLE_DEPREC_ONE_CSS_FOLDER_NAME' , 'sek_css' ); }//<= folder name deprecated in july 2020
if ( !defined( 'NIMBLE_DEPREC_TWO_CSS_FOLDER_NAME' ) ) { define( 'NIMBLE_DEPREC_TWO_CSS_FOLDER_NAME' , 'nb_css' ); }//<= folder name deprecated in october 2020
if ( !defined( 'NIMBLE_CSS_FOLDER_NAME' ) ) { define( 'NIMBLE_CSS_FOLDER_NAME' , 'nimble_css' ); }
if ( !defined( 'NIMBLE_OPT_FOR_MODULE_CSS_READING_STATUS' ) ) { define( 'NIMBLE_OPT_FOR_MODULE_CSS_READING_STATUS' , 'nimble_module_css_read_status' ); }
if ( !defined( 'NIMBLE_OPT_SEKTION_POST_INDEX' ) ) { define( 'NIMBLE_OPT_SEKTION_POST_INDEX' , 'nimble_posts_index' ); }
if ( !defined( 'NIMBLE_OPT_PREFIX_FOR_SEKTION_COLLECTION' ) ) { define( 'NIMBLE_OPT_PREFIX_FOR_SEKTION_COLLECTION' , 'nimble___' ); }
if ( !defined( 'NIMBLE_GLOBAL_SKOPE_ID' ) ) { define( 'NIMBLE_GLOBAL_SKOPE_ID' , 'skp__global' ); }
if ( !defined( 'NIMBLE_OPT_NAME_FOR_GLOBAL_OPTIONS' ) ) { define( 'NIMBLE_OPT_NAME_FOR_GLOBAL_OPTIONS' , 'nimble_global_opts' ); }// <= name updated in march 2021 was __nimble_options__
//if ( !defined( 'NIMBLE_OPT_NAME_FOR_SAVED_SEKTIONS' ) ) { define( 'NIMBLE_OPT_NAME_FOR_SAVED_SEKTIONS' , 'nimble_saved_sektions' ); } //<= June 2020 to be removed
if ( !defined( 'NIMBLE_OPT_NAME_FOR_MOST_USED_FONTS' ) ) { define( 'NIMBLE_OPT_NAME_FOR_MOST_USED_FONTS' , 'nimble_most_used_fonts' ); }
if ( !defined( 'NIMBLE_OPT_FOR_GLOBAL_CSS' ) ) { define( 'NIMBLE_OPT_FOR_GLOBAL_CSS' , 'nimble_global_css' ); }
if ( !defined( 'NIMBLE_OPT_NAME_FOR_SECTION_JSON' ) ) { define( 'NIMBLE_OPT_NAME_FOR_SECTION_JSON' , 'nimble_prebuild_sections' ); }// <= name updated in march 2021, was nb_prebuild_section_json
if ( !defined( 'NIMBLE_OPT_NAME_FOR_BACKWARD_FIXES' ) ) { define( 'NIMBLE_OPT_NAME_FOR_BACKWARD_FIXES' , 'nb_backward_fixes' ); }
if ( !defined( 'NIMBLE_OPT_NAME_FOR_SHORTCODE_PARSING' ) ) { define( 'NIMBLE_OPT_NAME_FOR_SHORTCODE_PARSING' , 'nb_shortcodes_parsed_in_czr' ); }
if ( !defined( 'NIMBLE_OPT_NAME_FOR_DISABLING_WIDGET_MODULE' ) ) { define( 'NIMBLE_OPT_NAME_FOR_DISABLING_WIDGET_MODULE' , 'nb_widgets_disabled_in_czr' ); }
if ( !defined( 'NIMBLE_OPT_NAME_FOR_DEBUG_MODE' ) ) { define( 'NIMBLE_OPT_NAME_FOR_DEBUG_MODE' , 'nb_debug_mode_active' ); }
if ( !defined( 'NIMBLE_PREFIX_FOR_SETTING_NOT_SAVED' ) ) { define( 'NIMBLE_PREFIX_FOR_SETTING_NOT_SAVED' , '__nimble__' ); }
if ( !defined( 'NIMBLE_WIDGET_PREFIX' ) ) { define( 'NIMBLE_WIDGET_PREFIX' , 'nimble-widget-area-' ); }
if ( !defined( 'NIMBLE_ASSETS_VERSION' ) ) { define( 'NIMBLE_ASSETS_VERSION', sek_is_dev_mode() ? time() : NIMBLE_VERSION ); }
if ( !defined( 'NIMBLE_MODULE_ICON_PATH' ) ) { define( 'NIMBLE_MODULE_ICON_PATH' , NIMBLE_BASE_URL . '/assets/czr/sek/icons/modules/' ); }
if ( !defined( 'NIMBLE_DETACHED_TINYMCE_TEXTAREA_ID') ) { define( 'NIMBLE_DETACHED_TINYMCE_TEXTAREA_ID' , 'czr-customize-content_editor' ); }
// TRANSIENTS ID
if ( !defined( 'NIMBLE_WELCOME_NOTICE_ID' ) ) { define ( 'NIMBLE_WELCOME_NOTICE_ID', 'nimble-welcome-notice-12-2018' ); }
//mt_rand(0, 65535) . 'test-nimble-feedback-notice-04-2019'
if ( !defined( 'NIMBLE_FEEDBACK_NOTICE_ID' ) ) { define ( 'NIMBLE_FEEDBACK_NOTICE_ID', 'nimble-feedback-notice-01-2022' ); }
if ( !defined( 'NIMBLE_FAWESOME_TRANSIENT_ID' ) ) { define ( 'NIMBLE_FAWESOME_TRANSIENT_ID', 'sek_font_awesome_october_2021' ); }
if ( !defined( 'NIMBLE_GFONTS_TRANSIENT_ID' ) ) { define ( 'NIMBLE_GFONTS_TRANSIENT_ID', 'sek_gfonts_march_2020' ); }
if ( !defined( 'NIMBLE_FEEDBACK_STATUS_TRANSIENT_ID' ) ) { define ( 'NIMBLE_FEEDBACK_STATUS_TRANSIENT_ID', 'nimble_feedback_status' ); }
if ( !defined( 'NIMBLE_API_CHECK_TRANSIENT_ID' ) ) { define ( 'NIMBLE_API_CHECK_TRANSIENT_ID', 'nimble_version_check_for_api' ); }
if ( !defined( 'NIMBLE_GOOGLE_FONTS_STYLESHEET_ID' ) ) { define ( 'NIMBLE_GOOGLE_FONTS_STYLESHEET_ID', 'sek-gfonts-local-and-global' ); }
if ( !defined( 'NIMBLE_GLOBAL_OPTIONS_STYLESHEET_ID' ) ) { define ( 'NIMBLE_GLOBAL_OPTIONS_STYLESHEET_ID', 'nimble-global-inline-style' ); }
if ( !defined( "NIMBLE_DATA_API_URL_V2" ) ) { define( "NIMBLE_DATA_API_URL_V2",
( defined('NIMBLE_FETCH_API_LOCALLY') && NIMBLE_FETCH_API_LOCALLY && defined('NIMBLE_LOCAL_API_URL') ) ? NIMBLE_LOCAL_API_URL : 'https://api.nimblebuilder.com/wp-json/nimble/v2/cravan'
); }
if ( !defined( 'NIMBLE_PRO_URL' ) ) { define ( 'NIMBLE_PRO_URL', 'https://presscustomizr.com/nimble-builder-pro' ); }
// @return bool
function sek_is_debug_mode() {
return isset( $_GET['nimble_debug'] ) || sek_booleanize_checkbox_val( get_option( NIMBLE_OPT_NAME_FOR_DEBUG_MODE ) );
}
?>
@@ -0,0 +1,133 @@
<?php
/* ------------------------------------------------------------------------- *
* LOCATIONS UTILITIES
/* ------------------------------------------------------------------------- */
// @return array
function sek_get_locations() {
if ( !is_array( Nimble_Manager()->registered_locations ) ) {
sek_error_log( __FUNCTION__ . ' error => the registered locations must be an array');
return Nimble_Manager()->default_locations;
}
//sek_error_log( __FUNCTION__ .' => locations ?', array_merge( Nimble_Manager()->default_locations, Nimble_Manager()->registered_locations ) );
return apply_filters( 'sek_get_locations', Nimble_Manager()->registered_locations );
}
// @return array of "local" content locations => locations with the following characterictics :
// - sections in this location are specific to a given skope id
// - header and footer locations are excluded
function sek_get_local_content_locations() {
$locations = array();
$all_locations = sek_get_locations();
if ( is_array( $all_locations ) ) {
foreach ( $all_locations as $loc_id => $loc_data) {
// Normalizes with the default model used to register a location
// public $default_registered_location_model = [
// 'priority' => 10,
// 'is_global_location' => false,
// 'is_header_location' => false,
// 'is_footer_location' => false
// ];
$loc_data = wp_parse_args( $loc_data, Nimble_Manager()->default_registered_location_model );
if ( true === $loc_data['is_header_location'] || true === $loc_data['is_footer_location'] )
continue;
if ( !sek_is_global_location( $loc_id ) ) {
$locations[$loc_id] = $loc_data;
}
}
}
return $locations;
}
// DEPRECATED IN V1.4.0.
// Kept for retro compatibility
function sek_get_local_locations() {
return sek_get_local_content_locations();
}
// @return an array of "global" locations => in which the sections are displayed site wide
function sek_get_global_locations() {
$locations = array();
$all_locations = sek_get_locations();
if ( is_array( $all_locations ) ) {
foreach ( $all_locations as $loc_id => $loc_data) {
if ( sek_is_global_location( $loc_id ) ) {
$locations[$loc_id] = $loc_data;
}
}
}
return $locations;
}
// @param location_id (string)
function sek_get_registered_location_property( $location_id, $property_name = '' ) {
$all_locations = sek_get_locations();
$default_property_val = 'not_set';
//sek_error_log( __FUNCTION__ .' => locations ?', $all_locations );
if ( !isset( $all_locations[$location_id] ) || !is_array( $all_locations[$location_id] ) ) {
sek_error_log( __FUNCTION__ . ' error => the location ' . $location_id . ' is invalid or not registered.');
return $default_property_val;
}
if ( empty( $property_name ) || !is_string( $property_name ) ) {
sek_error_log( __FUNCTION__ . ' error => the requested property for location ' . $location_id . ' is invalid');
return $default_property_val;
}
$location_params = wp_parse_args( $all_locations[$location_id], Nimble_Manager()->default_registered_location_model );
return array_key_exists($property_name, $location_params) ? $location_params[$property_name] : $default_property_val;
}
// @return bool
function sek_is_global_location( $location_id ) {
if ( !is_string( $location_id ) || empty( $location_id ) ) {
sek_error_log( __FUNCTION__ . ' error => missing or invalid location_id param' );
return false;
}
$is_global_location = sek_get_registered_location_property( $location_id, 'is_global_location' );
return 'not_set' === $is_global_location ? false : true === $is_global_location;
}
// @param $location_id ( string ). Example '__after_header'
function register_location( $location_id, $params = array() ) {
$params = is_array( $params ) ? $params : array();
$params = wp_parse_args( $params, Nimble_Manager()->default_registered_location_model );
$registered_locations = Nimble_Manager()->registered_locations;
if ( is_array( $registered_locations ) ) {
$registered_locations[$location_id] = $params;
}
Nimble_Manager()->registered_locations = $registered_locations;
//sek_error_log( __FUNCTION__ .' => Nimble_Manager()->registered_locations', Nimble_Manager()->registered_locations );
}
// @return array
// @used when populating the customizer localized params
// @param $skope_id optional. Specified when we need to differentiate the local and global locations
function sek_get_default_location_model( $skope_id = null ) {
$is_global_skope = NIMBLE_GLOBAL_SKOPE_ID === $skope_id;
if ( $is_global_skope ) {
$defaut_sektions_value = [ 'collection' => [], 'fonts' => [] ];//global_options are saved in a specific option => NIMBLE_OPT_NAME_FOR_GLOBAL_OPTIONS
} else {
// March 2021 property '__inherits_group_skope_tmpl_when_exists__' added for site templates #478
$defaut_sektions_value = [ 'collection' => [], 'local_options' => [], 'fonts' => [], '__inherits_group_skope_tmpl_when_exists__' => true ];
}
foreach( sek_get_locations() as $location_id => $params ) {
$is_global_location = sek_is_global_location( $location_id );
if ( $is_global_skope && !$is_global_location )
continue;
if ( !$is_global_skope && $is_global_location )
continue;
$location_model = wp_parse_args( [ 'id' => $location_id ], Nimble_Manager()->default_location_model );
if ( $is_global_location ) {
$location_model[ 'is_global_location' ] = true;
}
$defaut_sektions_value['collection'][] = $location_model;
}
return $defaut_sektions_value;
}
?>
@@ -0,0 +1,59 @@
<?php
// @return bool
// march 2020 introduced for https://github.com/presscustomizr/nimble-builder/issues/629
// Firefox doesn not support preload
// IE is supposed to support it, but tests show that google fonts may not be loaded on each page refresh
function sek_preload_google_fonts_on_front() {
// When preload is active, browser support is checked with javascript
// with a fallback on regular style fetching
// if(strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE) // 'Internet explorer'
// return;
// elseif(strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== FALSE) // 'Mozilla Firefox'
// return;
$glob_perf = sek_get_global_option_value( 'performances' );
if ( !is_null( $glob_perf ) && is_array( $glob_perf ) && !empty( $glob_perf['preload_google_fonts'] ) ) {
return sek_booleanize_checkbox_val( $glob_perf['preload_google_fonts'] );
}
return false;
}
// @return bool
// march 2020 introduced for https://github.com/presscustomizr/nimble-builder/issues/635
function sek_load_front_assets_dynamically() {
$glob_perf = sek_get_global_option_value( 'performances' );
if ( !is_null( $glob_perf ) && is_array( $glob_perf ) && !empty( $glob_perf['load_assets_in_ajax'] ) ) {
return !skp_is_customizing() && sek_booleanize_checkbox_val( $glob_perf['load_assets_in_ajax'] );
}
return false;
}
// Adds defer attribute to enqueued / registered scripts.
// fired @wp_enqueue_scripts
function sek_defer_script($handle) {
// Adds defer attribute to enqueued / registered scripts.
wp_script_add_data( $handle, 'defer', true );
}
// oct 2020 => introduction of a normalized way to emit a js event to NB front api
// in particular to make sure NB doesn't print a <script> twice to emit the same event
function sek_emit_js_event( $event = '', $echo = true ) {
$emitted = Nimble_Manager()->emitted_js_event;
if ( !is_string($event) || in_array($event, $emitted) )
return;
$emitted[] = $event;
Nimble_Manager()->emitted_js_event = $emitted;
if ( $echo ) {
$html = sprintf('(function(){if(window.nb_){nb_.emit("%1$s");}})();', $event );
wp_register_script( 'nb_emit_' . $event, '');
wp_enqueue_script( 'nb_emit_' . $event );
wp_add_inline_script( 'nb_emit_' . $event, $html );
} else {
$html = sprintf('<script>(function(){if(window.nb_){nb_.emit("%1$s");}})();</script>', $event );
return $html;
}
}
?>
@@ -0,0 +1,315 @@
<?php
/* ------------------------------------------------------------------------- *
* IMAGE HELPER
/* ------------------------------------------------------------------------- */
// @see https://codex.wordpress.org/Function_Reference/get_intermediate_image_sizes
// used in sek_get_select_options_for_input_id()
function sek_get_img_sizes() {
global $_wp_additional_image_sizes;
$sizes = array();
$to_return = array(
'original' => __('Original image dimensions', 'text_doma')
);
foreach ( get_intermediate_image_sizes() as $_size ) {
$first_to_upper_size = ucfirst(strtolower($_size));
$first_to_upper_size = preg_replace_callback( '/[.!?].*?\w/', '\Nimble\sek_img_sizes_preg_replace_callback', $first_to_upper_size );
if ( in_array( $_size, array('thumbnail', 'medium', 'medium_large', 'large') ) ) {
$sizes[ $_size ]['width'] = get_option( "{$_size}_size_w" );
$sizes[ $_size ]['height'] = get_option( "{$_size}_size_h" );
$sizes[ $_size ]['title'] = $first_to_upper_size;
//$sizes[ $_size ]['crop'] = (bool) get_option( "{$_size}_crop" );
} elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) {
$sizes[ $_size ] = array(
'width' => $_wp_additional_image_sizes[ $_size ]['width'],
'height' => $_wp_additional_image_sizes[ $_size ]['height'],
'title' => $first_to_upper_size
//'crop' => $_wp_additional_image_sizes[ $_size ]['crop'],
);
}
}
foreach ( $sizes as $_size => $data ) {
$to_return[ $_size ] = $data['title'] . ' - ' . $data['width'] . ' x ' . $data['height'];
}
return $to_return;
}
function sek_img_sizes_preg_replace_callback( $matches ) {
return strtoupper( $matches[0] );
}
/* ------------------------------------------------------------------------- *
* SMART LOAD HELPER FOR IMAGES AND VIDEOS
/* ------------------------------------------------------------------------- */
/**
* callback of preg_replace_callback in SEK_Front_Render::sek_maybe_process_img_for_js_smart_load
* @return string
*/
function nimble_regex_callback( $matches ) {
// bail if the img has already been parsed for swiper slider lazyloading ( https://github.com/presscustomizr/nimble-builder/issues/596 )
if ( false !== strpos( $matches[0], 'data-srcset' ) || false !== strpos( $matches[0], 'data-src' ) ) {
return $matches[0];
// bail if already parsed by this regex or if smartload is disabled
} else if ( false !== strpos( $matches[0], 'data-sek-src' ) || preg_match('/ data-skip-lazyload *= *"true" */', $matches[0]) ) {
return $matches[0];
// otherwise go ahead and parse
} else {
return apply_filters( 'nimble_img_smartloaded',
// june 2020 : the spaces before strings to replace ensure we don't replace attributes that include "srcset" or "sizes"
// which can happen if another plugin has already added lazy load attributes
// see https://github.com/presscustomizr/nimble-builder/issues/723
str_replace( array(' srcset=', ' sizes='), array(' data-sek-srcset=', ' data-sek-sizes='),
sprintf('<img %1$s src="%2$s" data-sek-src="%3$s" %4$s>',
$matches[1],
'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
$matches[2],
$matches[3]
)
)
);
}
}
// @return boolean
// img smartload can be set globally with 'global-img-smart-load' and locally with 'local-img-smart-load'
// the local option wins
// if local is set to inherit, return the global option
// This option is cached
// deactivated when customizing
function sek_is_img_smartload_enabled() {
// condition added in april 2020 when implementing yoast compat https://github.com/presscustomizr/nimble-builder/issues/657
if ( is_admin() && !skp_is_customizing() )
return false;
if ( 'not_cached' !== Nimble_Manager()->img_smartload_enabled ) {
return Nimble_Manager()->img_smartload_enabled;
}
$is_img_smartload_enabled = false;
// LOCAL OPTION
// we use the ajaxily posted skope_id when available <= typically in a customizing ajax action 'sek-refresh-stylesheet'
// otherwise we fallback on the normal utility skp_build_skope_id()
$local_performances_data = sek_get_local_option_value( 'local_performances' );
$local_smartload = 'inherit';
if ( !is_null( $local_performances_data ) && is_array( $local_performances_data ) ) {
if ( !empty( $local_performances_data['local-img-smart-load'] ) && 'inherit' !== $local_performances_data['local-img-smart-load'] ) {
$local_smartload = 'yes' === $local_performances_data['local-img-smart-load'];
}
}
if ( 'inherit' !== $local_smartload ) {
$is_img_smartload_enabled = $local_smartload;
} else {
// GLOBAL OPTION
$glob_performances_data = sek_get_global_option_value( 'performances' );
if ( !is_null( $glob_performances_data ) && is_array( $glob_performances_data ) && !empty( $glob_performances_data['global-img-smart-load'] ) ) {
$is_img_smartload_enabled = sek_booleanize_checkbox_val( $glob_performances_data['global-img-smart-load'] );
}
}
// CACHE THE OPTION
Nimble_Manager()->img_smartload_enabled = $is_img_smartload_enabled;
return Nimble_Manager()->img_smartload_enabled;
}
// @return boolean
// video background lazy load can be set globally with 'global-bg-video-lazy-load'
// implemented in nov 2019 for https://github.com/presscustomizr/nimble-builder/issues/287
// This option is cached
function sek_is_video_bg_lazyload_enabled() {
// if ( skp_is_customizing() )
// return false;
if ( 'not_cached' !== Nimble_Manager()->video_bg_lazyload_enabled ) {
return Nimble_Manager()->video_bg_lazyload_enabled;
}
$is_video_bg_lazyload_enabled = false;
$glob_performances_data = sek_get_global_option_value( 'performances' );
if ( !is_null( $glob_performances_data ) && is_array( $glob_performances_data ) && !empty( $glob_performances_data['global-bg-video-lazy-load'] ) ) {
$is_video_bg_lazyload_enabled = sek_booleanize_checkbox_val( $glob_performances_data['global-bg-video-lazy-load'] );
}
// CACHE THE OPTION
Nimble_Manager()->video_bg_lazyload_enabled = $is_video_bg_lazyload_enabled;
return Nimble_Manager()->video_bg_lazyload_enabled;
}
/* ------------------------------------------------------------------------- *
* DISABLE SUPPORT FOR BROWSER NATIVE LAZY LOADING
/* ------------------------------------------------------------------------- */
// Disabled when rendering NB content only
// attribute loading="lazy" was introduced in WP 5.5, Oct 2020
// => see why NB disable it here :https://github.com/presscustomizr/nimble-builder/issues/747
add_filter( 'wp_lazy_loading_enabled', function($default) {
return Nimble_Manager()->rendering ? false : $default;
});
/* ------------------------------------------------------------------------- *
* IMPORT IMAGE IF NOT ALREADY IN MEDIA LIB
/* ------------------------------------------------------------------------- */
// @return attachment id or WP_Error
// this method uses download_url()
// it first checks if the media already exists in the media library
function sek_sideload_img_and_return_attachment_id( $img_url ) {
// Set variables for storage, fix file filename for query strings.
preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $img_url, $matches );
$filename = basename( $matches[0] );
// prefix with nimble_asset_ if not done yet
// for example, when importing a file, the img might already have the nimble_asset_ prefix if it's been uploaded by Nimble
if ( 'nimble_asset_' !== substr($filename, 0, strlen('nimble_asset_') ) ) {
$filename = 'nimble_asset_' . $filename;
}
// remove the extension
$img_title = preg_replace( '/\.[^.]+$/', '', trim( $filename ) );
//sek_error_log( __FUNCTION__ . ' ALORS img_title?', preg_replace( '/\.[^.]+$/', '', trim( $img_title ) ) );
// Make sure this img has not already been uploaded
// Meta query on the alt property, better than the title
// because of https://github.com/presscustomizr/nimble-builder/issues/435
$args = array(
'posts_per_page' => 1,
'post_type' => 'attachment',
'post_status' => 'inherit',
//'name' => $img_title,
'meta_query' => array(
array(
'key' => '_wp_attachment_image_alt',
'value' => $img_title,
'compare' => '='
),
),
);
$get_attachment = new \WP_Query( $args );
//error_log( print_r( $get_attachment->posts, true ) );
if ( is_array( $get_attachment->posts ) && array_key_exists(0, $get_attachment->posts) ) {
//wp_send_json_error( __CLASS__ . '::' . __CLASS__ . '::' . __FUNCTION__ . ' => file already uploaded : ' . $relative_path );
$img_id_already_uploaded = $get_attachment->posts[0]->ID;
}
// stop now and return the id if the attachment was already uploaded
if ( isset($img_id_already_uploaded) ) {
//sek_error_log( __FUNCTION__ . ' ALREADY UPLOADED ?', $img_id_already_uploaded );
return $img_id_already_uploaded;
}
// Insert the media
// Prepare the file_array that we will pass to media_handle_sideload()
$file_array = array();
$file_array['name'] = $filename;
// Download file to temp location.
$file_array['tmp_name'] = download_url( $img_url );
// If error storing temporarily, return the error.
if ( is_wp_error( $file_array['tmp_name'] ) ) {
sek_error_log( __FUNCTION__ . ' error when firing download_url() for image : ' . $img_url );
return $file_array['tmp_name'];
}
// Do the validation and storage stuff.
$id = media_handle_sideload( $file_array, 0 );
// If error storing permanently, unlink.
if ( is_wp_error( $id ) ) {
sek_error_log( __FUNCTION__ . ' error when firing media_handle_sideload() for image : ' . $img_url );
@unlink( $file_array['tmp_name'] );
} else {
// Store the title as image alt property
// so we can identify it uniquely next time when checking if already uploaded
// of course, if the alt property has been manually modified meanwhile, the image will be loaded again
// fixes https://github.com/presscustomizr/nimble-builder/issues/435
add_post_meta( $id, '_wp_attachment_image_alt', $img_title, true );
}
return $id;
}
// IMPORT IMG HELPER
// recursive
//add_filter( 'nimble_pre_import', '\Nimble\sek_maybe_import_imgs' );
function sek_maybe_import_imgs( $seks_data, $do_import_images = true ) {
$new_seks_data = array();
// Reset img_import_errors
Nimble_Manager()->img_import_errors = [];
foreach ( $seks_data as $key => $value ) {
if ( is_array($value) ) {
$new_seks_data[$key] = sek_maybe_import_imgs( $value, $do_import_images );
} else {
if ( is_string( $value ) && false !== strpos( $value, '__img_url__' ) && sek_is_img_url( $value ) ) {
$url = str_replace( '__img_url__', '', $value );
// april 2020 : new option to skip importing images
// introduced for https://github.com/presscustomizr/nimble-builder/issues/663
if ( !$do_import_images ) {
$value = $url;
} else {
//sek_error_log( __FUNCTION__ . ' URL?', $url );
$id = sek_sideload_img_and_return_attachment_id( $url );
if ( is_wp_error( $id ) ) {
$value = null;
$img_errors = Nimble_Manager()->img_import_errors;
$img_errors[] = $url;
Nimble_Manager()->img_import_errors = $img_errors;
} else {
$value = $id;
}
}
} else if ( is_string( $value ) && false !== strpos( $value, '__default_img_medium__' ) ) {
$value = NIMBLE_BASE_URL . '/assets/img/default-img.png';
}
$new_seks_data[$key] = $value;
}
}
return $new_seks_data;
}
// @return bool
function sek_is_img_url( $url = '' ) {
if ( is_string( $url ) ) {
if ( preg_match( '/\.(jpg|jpeg|png|gif)/i', $url ) ) {
return true;
}
}
return false;
}
/* ------------------------------------------------------------------------- *
* REMOVE IMAGE STYLE ATTRIBUTE
* Used in image module, slider module, special image module
/* ------------------------------------------------------------------------- */
// Nov 2020 : removes any additional styles added by a theme ( Twenty Twenty one ) or a plugin to the image
// because otherwise it overrides NB builder custom width, height, and custom width when scrolling ( NB Pro )
// hook : 'wp_get_attachment_image_attributes'
function sek_remove_image_style_attr( $attr ) {
if ( is_array($attr) && isset($attr['style']) ) {
unset($attr['style']);
}
return $attr;
}
?>
@@ -0,0 +1,158 @@
<?php
/* ------------------------------------------------------------------------- *
* Page Menu for menu module
/* ------------------------------------------------------------------------- */
/**
* Display or retrieve list of pages with optional home link.
* Modified copy of wp_page_menu()
* @return string html menu
*/
function sek_page_menu_fallback( $args = array() ) {
$defaults = array('show_home' => true, 'sort_column' => 'menu_order, post_title', 'menu_class' => 'menu', 'echo' => true, 'link_before' => '', 'link_after' => '');
$args = wp_parse_args( $args, $defaults );
$args = apply_filters( 'wp_page_menu_args', $args );
$menu = '';
$list_args = $args;
// Show Home in the menu
if ( !empty($args['show_home']) ) {
if ( true === $args['show_home'] || '1' === $args['show_home'] || 1 === $args['show_home'] ) {
$text = __('Home' , 'text_domain_to_replace');
} else {
$text = $args['show_home'];
}
$class = '';
if ( is_front_page() && !is_paged() ) {
$class = 'class="current_page_item"';
}
$menu .= '<li ' . $class . '><a href="' . home_url( '/' ) . '">' . $args['link_before'] . $text . $args['link_after'] . '</a></li>';
// If the front page is a page, add it to the exclude list
if (get_option('show_on_front') == 'page') {
if ( !empty( $list_args['exclude'] ) ) {
$list_args['exclude'] .= ',';
} else {
$list_args['exclude'] = '';
}
$list_args['exclude'] .= get_option('page_on_front');
}
}
$list_args['echo'] = false;
$list_args['title_li'] = '';
// limit the number of pages displayed, home excluded from the count if included
$list_args['number'] = 4;
$menu .= str_replace( array( "\r", "\n", "\t" ), '', sek_list_pages( $list_args ) );
// if ( $menu )
// $menu = '<ul>' . $menu . '</ul>';
//$menu = '<div class="' . esc_attr($args['menu_class']) . '">' . $menu . "</div>\n";
if ( $menu ) {
$menu = '<ul class="' . esc_attr( $args['menu_class'] ) . '">' . $menu . '</ul>';
}
//$menu = apply_filters( 'wp_page_menu', $menu, $args );
if ( $args['echo'] )
echo wp_kses_post($menu);
else
return $menu;
}
/**
* Retrieve or display list of pages in list (li) format.
* Modified copy of wp_list_pages
* @return string HTML list of pages.
*/
function sek_list_pages( $args = '' ) {
$defaults = array(
'depth' => 0,
'show_date' => '',
'date_format' => get_option( 'date_format' ),
'child_of' => 0,
'exclude' => '',
'title_li' => __( 'Pages', 'text_domain_to_replace' ),
'echo' => 1,
'authors' => '',
'sort_column' => 'menu_order, post_title',
'link_before' => '',
'link_after' => '',
'walker' => ''
);
$r = wp_parse_args( $args, $defaults );
$output = '';
$current_page = 0;
// sanitize, mostly to keep spaces out
$r['exclude'] = preg_replace( '/[^0-9,]/', '', $r['exclude'] );
// Allow plugins to filter an array of excluded pages (but don't put a nullstring into the array)
$exclude_array = ( $r['exclude'] ) ? explode( ',', $r['exclude'] ) : array();
$r['exclude'] = implode( ',', apply_filters( 'wp_list_pages_excludes', $exclude_array ) );
// Query pages.
$r['hierarchical'] = 0;
$pages = get_pages( $r );
if ( !empty( $pages ) ) {
if ( $r['title_li'] ) {
$output .= '<li class="pagenav">' . $r['title_li'] . '<ul>';
}
global $wp_query;
if ( is_page() || is_attachment() || $wp_query->is_posts_page ) {
$current_page = get_queried_object_id();
} elseif ( is_singular() ) {
$queried_object = get_queried_object();
if ( is_post_type_hierarchical( $queried_object->post_type ) ) {
$current_page = $queried_object->ID;
}
}
$output .= sek_walk_page_tree( $pages, $r['depth'], $current_page, $r );
if ( $r['title_li'] ) {
$output .= '</ul></li>';
}
}
$html = apply_filters( 'wp_list_pages', $output, $r );
if ( $r['echo'] ) {
echo wp_kses_post($html);
} else {
return $html;
}
}
/**
* Retrieve HTML list content for page list.
*
* @uses Walker_Page to create HTML list content.
* @since 2.1.0
* @see Walker_Page::walk() for parameters and return description.
*/
function sek_walk_page_tree( $pages, $depth, $current_page, $r ) {
// if ( empty($r['walker']) )
// $walker = new Walker_Page;
// else
// $walker = $r['walker'];
$walker = new \Walker_Page;
foreach ( (array) $pages as $page ) {
if ( $page->post_parent ) {
$r['pages_with_children'][ $page->post_parent ] = true;
}
}
$args = array( $pages, $depth, $r, $current_page );
return call_user_func_array(array($walker, 'walk'), $args);
}
function sek_get_user_created_menus() {
// if ( !skp_is_customizing() )
// return array();
$all_menus = get_terms( 'nav_menu', array( 'hide_empty' => true ) );
$user_menus = array();
foreach ( $all_menus as $menu_obj ) {
if ( is_string( $menu_obj->slug ) && !empty( $menu_obj->slug ) && !empty( $menu_obj->name ) ) {
$user_menus[ $menu_obj->slug ] = $menu_obj->name;
}
}
// sek_error_log( 'sek_get_user_created_menus', array_merge(
// array( 'nimble_page_menu' => __('Default page menu', 'text_domain_to_replace') )
// , $user_menus ) );
return array_merge(
array( 'nimble_page_menu' => __('Default page menu', 'text_domain_to_replace') )
, $user_menus );
}
?>
@@ -0,0 +1,748 @@
<?php
/* ------------------------------------------------------------------------- *
* MODULES COLLECTION
/* ------------------------------------------------------------------------- */
// introduced when implementing the level tree #359
function sek_get_module_collection() {
return apply_filters( 'sek_get_module_collection', array(
array(
'content-type' => 'preset_section',
'content-id' => 'two_columns',
'title' => __( 'Two Columns', 'text_doma' ),
'icon' => 'Nimble_2-columns_icon.svg'
),
array(
'content-type' => 'preset_section',
'content-id' => 'three_columns',
'title' => __( 'Three Columns', 'text_doma' ),
'icon' => 'Nimble_3-columns_icon.svg'
),
array(
'content-type' => 'preset_section',
'content-id' => 'four_columns',
'title' => __( 'Four Columns', 'text_doma' ),
'icon' => 'Nimble_4-columns_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_tiny_mce_editor_module',
'title' => __( 'Rich Text Editor', 'text_doma' ),
'icon' => 'Nimble_rich-text-editor_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_image_module',
'title' => __( 'Image', 'text_doma' ),
'icon' => 'Nimble__image_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_gallery_module',
'title' => __( 'Image gallery', 'text_doma' ),
'icon' => 'Nimble_gallery_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_heading_module',
'title' => __( 'Heading', 'text_doma' ),
'icon' => 'Nimble__heading_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_icon_module',
'title' => __( 'Icon', 'text_doma' ),
'icon' => 'Nimble__icon_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_special_img_module',
'title' => __( 'Nimble Image', 'text_doma' ),
'icon' => 'Nimble_img_icon.svg',
'is_pro' => !sek_is_pro(),
'active' => sek_is_pro()
),
array(
'content-type' => 'module',
'content-id' => 'czr_button_module',
'title' => __( 'Button', 'text_doma' ),
'icon' => 'Nimble_button_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_img_slider_module',
'title' => __( 'Image & Text Carousel', 'text_doma' ),
'icon' => 'Nimble_slideshow_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_accordion_module',
'title' => __( 'Accordion', 'text_doma' ),
'icon' => 'Nimble_accordion_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_advanced_list_module',
'title' => __( 'Advanced List', 'text_doma' ),
'icon' => 'Nimble__advanced_list_icon.svg',
'is_pro' => !sek_is_pro(),
'active' => sek_is_pro()
),
array(
'content-type' => 'module',
'content-id' => 'czr_simple_html_module',
'title' => __( 'Html Content', 'text_doma' ),
'icon' => 'Nimble_html_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_post_grid_module',
'title' => __( 'Post Grid', 'text_doma' ),
'icon' => 'Nimble_posts-list_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_quote_module',
'title' => __( 'Quote', 'text_doma' ),
'icon' => 'Nimble_quote_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_shortcode_module',
'title' => __( 'Shortcode', 'text_doma' ),
'icon' => 'Nimble_shortcode_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_spacer_module',
'title' => __( 'Spacer', 'text_doma' ),
'icon' => 'Nimble__spacer_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_divider_module',
'title' => __( 'Divider', 'text_doma' ),
'icon' => 'Nimble__divider_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_map_module',
'title' => __( 'Map', 'text_doma' ),
'icon' => 'Nimble_map_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_widget_area_module',
'title' => __( 'WordPress widget area', 'text_doma' ),
'font_icon' => '<i class="fab fa-wordpress-simple"></i>',
'active' => !sek_is_widget_module_disabled()
),
array(
'content-type' => 'module',
'content-id' => 'czr_social_icons_module',
'title' => __( 'Social Profiles', 'text_doma' ),
'icon' => 'Nimble_social_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_simple_form_module',
'title' => __( 'Simple Contact Form', 'text_doma' ),
'icon' => 'Nimble_contact-form_icon.svg'
),
array(
'content-type' => 'module',
'content-id' => 'czr_menu_module',
'title' => __( 'Menu', 'text_doma' ),
'font_icon' => '<i class="material-icons">menu</i>'
//'active' => sek_are_beta_features_enabled()
)
));
}
// September 2020 : filter the collection of modules
// Removes pro upsell modules if sek_is_upsell_enabled() is false
// filter declared in inc/sektions/_front_dev_php/_constants_and_helper_functions/0_0_5_modules_helpers.php
add_filter('sek_get_module_collection', function( $collection ) {
if ( sek_is_upsell_enabled() )
return $collection;
$filtered = [];
foreach ($collection as $mod => $mod_data) {
if ( array_key_exists('is_pro', $mod_data) && $mod_data['is_pro'] )
continue;
$filtered[] = $mod_data;
}
return $filtered;
});
// @return void()
// Fired in 'wp_enqueue_scripts'
// Recursively sniff the local and global sections to populate Nimble_Manager()->contextually_active_modules
// introduced for https://github.com/presscustomizr/nimble-builder/issues/612
function sek_populate_collection_of_contextually_active_modules( $skope_id = '', $recursive_data = null, $module_collection = null ) {
$skope_id = empty( $skope_id ) ? skp_get_skope_id() : $skope_id;
if ( is_null( $recursive_data ) ) {
$local_skope_settings = sek_get_skoped_seks( $skope_id );
$local_collection = ( is_array( $local_skope_settings ) && !empty( $local_skope_settings['collection'] ) ) ? $local_skope_settings['collection'] : array();
$global_skope_settings = sek_get_skoped_seks( NIMBLE_GLOBAL_SKOPE_ID );
$global_collection = ( is_array( $global_skope_settings ) && !empty( $global_skope_settings['collection'] ) ) ? $global_skope_settings['collection'] : array();
$recursive_data = array_merge( $local_collection, $global_collection );
}
if ( is_null( $module_collection ) ) {
// make sure Nimble_Manager()->contextually_active_modules is initialized as an array before starting populating it.
$module_collection = 'not_set' === Nimble_Manager()->contextually_active_modules ? [] : Nimble_Manager()->contextually_active_modules;
}
foreach ($recursive_data as $key => $value) {
if ( is_array( $value ) && array_key_exists('module_type', $value) ) {
$module_type = $value['module_type'];
if ( !array_key_exists($module_type, $module_collection) ) {
$module_collection[$module_type] = [];
}
if ( !in_array( $value['id'], $module_collection[$module_type] ) ) {
$module_collection[$module_type][] = $value['id'];
}
} else if ( is_array( $value ) ) {
$module_collection = sek_populate_collection_of_contextually_active_modules( $skope_id, $value, $module_collection);
}
}
Nimble_Manager()->contextually_active_modules = $module_collection;
return Nimble_Manager()->contextually_active_modules;
}
// return the cached collection or build it when needed
function sek_get_collection_of_contextually_active_modules( $skope_id = '' ) {
$skope_id = empty( $skope_id ) ? skp_get_skope_id() : $skope_id;
if ( 'not_set' === Nimble_Manager()->contextually_active_modules ) {
return sek_populate_collection_of_contextually_active_modules( $skope_id );
}
return Nimble_Manager()->contextually_active_modules;
}
/* ------------------------------------------------------------------------- *
* REGISTERED MODULES => GET PROPERTY
/* ------------------------------------------------------------------------- */
// Helper
function sek_get_registered_module_type_property( $module_type, $property = '' ) {
// check introduced since https://github.com/presscustomizr/nimble-builder/issues/432
// may not be mandatory
if ( !class_exists('\Nimble\CZR_Fmk_Base') ) {
sek_error_log( __FUNCTION__ . ' => error => CZR_Fmk_Base not loaded' );
return;
}
// registered modules
$registered_modules = CZR_Fmk_Base()->registered_modules;
if ( !array_key_exists( $module_type, $registered_modules ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' not registered.' );
return;
}
if ( array_key_exists( $property , $registered_modules[ $module_type ] ) ) {
return $registered_modules[ $module_type ][$property];
}
return;
}
/* ------------------------------------------------------------------------- *
* GET THE INPUT VALUE OF A GIVEN MODULE MODEL
/* ------------------------------------------------------------------------- */
// Recursive helper
// Handles simple model and multidimensional module model ( father - children ), like
// Array
// (
// [quote_content] => Array
// (
// [quote_text] => Hey, careful, man, there's a beverage here!
// [quote_font_size_css] => Array
// (
// [desktop] => 29px
// [mobile] => 12px
// )
// [quote_letter_spacing_css] => 7
// [quote___flag_important] => 1
// )
// [cite_content] => Array
// (
// [cite_text] => The Dude in <a href="https://www.imdb.com/title/tt0118715/quotes/qt0464770" rel="nofollow noopener noreferrer" target="_blank">The Big Lebowski</a>
// [cite_font_style_css] => italic
// )
// [design] => Array
// (
// [quote_design] => border-before
// )
// )
// Helper
// @param $input_id ( string )
// @param $module_model ( array )
function sek_get_input_value_in_module_model( $input_id, $module_model ) {
if ( !is_string( $input_id ) ) {
sek_error_log( __FUNCTION__ . ' => error => the $input_id param should be a string', $module_model);
return;
}
if ( !is_array( $module_model ) ) {
sek_error_log( __FUNCTION__ . ' => error => the $module_model param should be an array', $module_model );
return;
}
$input_value = '_not_set_';
foreach ( $module_model as $key => $data ) {
if ( $input_value !== '_not_set_' )
break;
if ( $input_id === $key ) {
$input_value = $data;
break;
} else {
if ( is_array( $data ) ) {
$input_value = sek_get_input_value_in_module_model( $input_id, $data );
}
}
}
return $input_value;
}
/* ------------------------------------------------------------------------- *
* REGISTERED MODULES => DEFAULT MODULE MODEL
/* ------------------------------------------------------------------------- */
// @param (string) module_type
// Walk the registered modules tree and generates the module default if not already cached
// used :
// - in sek_normalize_module_value_with_defaults(), when preprocessing the module model before printing the module template. @see SEK_Front::render()
// - when setting the css of a level option. @see for example : sek_add_css_rules_for_bg_border_background()
// @return array()
function sek_get_default_module_model( $module_type = '' ) {
$default = array();
if ( empty( $module_type ) || is_null( $module_type ) )
return $default;
// check introduced since https://github.com/presscustomizr/nimble-builder/issues/432
// may not be mandatory
if ( !class_exists('\Nimble\CZR_Fmk_Base') ) {
sek_error_log( __FUNCTION__ . ' => error => CZR_Fmk_Base not loaded' );
return $default;
}
// Did we already cache it ?
$default_models = Nimble_Manager()->default_models;
if ( !empty( $default_models[ $module_type ] ) ) {
$default = $default_models[ $module_type ];
} else {
$registered_modules = CZR_Fmk_Base()->registered_modules;
if ( !array( $registered_modules ) || !CZR_Fmk_Base()->czr_is_module_registered($module_type) ) {
sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' is not registered in the $CZR_Fmk_Base_fn()->registered_modules;' );
return $default;
}
// Is this module a father ?
if ( !empty( $registered_modules[ $module_type ]['is_father'] ) && true === $registered_modules[ $module_type ]['is_father'] ) {
if ( empty( $registered_modules[ $module_type ][ 'children' ] ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' missing children modules' );
return $default;
}
if ( !is_array( $registered_modules[ $module_type ][ 'children' ] ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' children modules should be an array' );
return $default;
}
foreach ( $registered_modules[ $module_type ][ 'children' ] as $opt_group => $child_mod_type ) {
if ( empty( $registered_modules[ $child_mod_type ][ 'tmpl' ] ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $child_mod_type . ' => missing "tmpl" property => impossible to build the father default model.' );
continue;
}
$default[$opt_group] = _sek_build_default_model( $registered_modules[ $child_mod_type ][ 'tmpl' ] );
}
}
// Not father module case
else {
if ( empty( $registered_modules[ $module_type ][ 'tmpl' ] ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' => missing "tmpl" property => impossible to build the default model.' );
return $default;
}
// Build
$default = _sek_build_default_model( $registered_modules[ $module_type ][ 'tmpl' ] );
}
// Cache
$default_models[ $module_type ] = $default;
Nimble_Manager()->default_models = $default_models;
//sek_error_log( __FUNCTION__ . ' => $default_models', $default_models );
}
return $default;
}
// @return array() default model
// Walk recursively the 'tmpl' property of the module
// 'tmpl' => array(
// 'pre-item' => array(
// 'social-icon' => array(
// 'input_type' => 'select',
// 'title' => __('Select an icon', 'text_doma')
// ),
// ),
// 'mod-opt' => array(
// 'social-size' => array(
// 'input_type' => 'number',
// 'title' => __('Size in px', 'text_doma'),
// 'step' => 1,
// 'min' => 5,
// 'transport' => 'postMessage'
// )
// ),
// 'item-inputs' => array(
// 'item-inputs' => array(
// 'tabs' => array(
// array(
// 'title' => __('Content', 'text_doma'),
// //'attributes' => 'data-sek-device="desktop"',
// 'inputs' => array(
// 'content' => array(
// 'input_type' => 'detached_tinymce_editor',
// 'title' => __('Content', 'text_doma')
// ),
// 'h_alignment_css' => array(
// 'input_type' => 'h_text_alignment',
// 'title' => __('Alignment', 'text_doma'),
// 'default' => is_rtl() ? 'right' : 'left',
// 'refresh_markup' => false,
// 'refresh_stylesheet' => true
// )
// )
// )
// )
// )
function _sek_build_default_model( $module_tmpl_data, $default_model = null ) {
$default_model = is_array( $default_model ) ? $default_model : array();
//error_log( print_r( $module_tmpl_data , true ) );
foreach( $module_tmpl_data as $key => $data ) {
if ( 'pre-item' === $key )
continue;
if ( is_array( $data ) && array_key_exists( 'input_type', $data ) ) {
$default_model[ $key ] = array_key_exists( 'default', $data ) ? $data[ 'default' ] : '';
}
if ( is_array( $data ) ) {
$default_model = _sek_build_default_model( $data, $default_model );
}
}
return $default_model;
}
/* ------------------------------------------------------------------------- *
* REGISTERED MODULES => INPUT LIST
/* ------------------------------------------------------------------------- */
// @param (string) module_type
// Walk the registered modules tree and generates the module input list if not already cached
// used :
// - when filtering 'sek_add_css_rules_for_input_id' @see Sek_Dyn_CSS_Builder::sek_css_rules_sniffer_walker()
// @return array()
function sek_get_registered_module_input_list( $module_type = '' ) {
$input_list = array();
if ( empty( $module_type ) || is_null( $module_type ) )
return $input_list;
// check introduced since https://github.com/presscustomizr/nimble-builder/issues/432
// may not be mandatory
if ( !class_exists('\Nimble\CZR_Fmk_Base') ) {
sek_error_log( __FUNCTION__ . ' => error => CZR_Fmk_Base not loaded' );
return $input_list;
}
// Did we already cache it ?
$cached_input_lists = Nimble_Manager()->cached_input_lists;
if ( !empty( $cached_input_lists[ $module_type ] ) ) {
$input_list = $cached_input_lists[ $module_type ];
} else {
$registered_modules = CZR_Fmk_Base()->registered_modules;
// sek_error_log( __FUNCTION__ . ' => registered_modules', $registered_modules );
if ( sek_is_dev_mode() && !array( $registered_modules ) || !array_key_exists( $module_type, $registered_modules ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' is not registered in the $CZR_Fmk_Base_fn()->registered_modules;' );
return $input_list;
}
// Is this module a father ?
if ( !empty( $registered_modules[ $module_type ]['is_father'] ) && true === $registered_modules[ $module_type ]['is_father'] ) {
if ( empty( $registered_modules[ $module_type ][ 'children' ] ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' missing children modules' );
return $input_list;
}
if ( !is_array( $registered_modules[ $module_type ][ 'children' ] ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' children modules should be an array' );
return $input_list;
}
$temp = array();
foreach ( $registered_modules[ $module_type ][ 'children' ] as $opt_group => $child_mod_type ) {
if ( empty( $registered_modules[ $child_mod_type ][ 'tmpl' ] ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $child_mod_type . ' => missing "tmpl" property => impossible to build the master input_list.' );
continue;
}
// $temp[$opt_group] = _sek_build_input_list( $registered_modules[ $child_mod_type ][ 'tmpl' ] );
// $input_list = array_merge( $input_list, $temp[$opt_group] );
$input_list[$opt_group] = _sek_build_input_list( $registered_modules[ $child_mod_type ][ 'tmpl' ] );
}
} else {
if ( empty( $registered_modules[ $module_type ][ 'tmpl' ] ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' => missing "tmpl" property => impossible to build the input_list.' );
return $input_list;
}
// Build
$input_list = _sek_build_input_list( $registered_modules[ $module_type ][ 'tmpl' ] );
}
// if ( empty( $registered_modules[ $module_type ][ 'tmpl' ] ) ) {
// sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' => missing "tmpl" property => impossible to build the input_list.' );
// return $input_list;
// }
// // Build
// $input_list = _sek_build_input_list( $registered_modules[ $module_type ][ 'tmpl' ] );
// Cache
$cached_input_lists[ $module_type ] = $input_list;
Nimble_Manager()->cached_input_lists = $cached_input_lists;
// sek_error_log( __FUNCTION__ . ' => $cached_input_lists', $cached_input_lists );
}
return $input_list;
}
// @return array() default model
// Walk recursively the 'tmpl' property of the module
// 'tmpl' => array(
// 'pre-item' => array(
// 'social-icon' => array(
// 'input_type' => 'select',
// 'title' => __('Select an icon', 'text_doma')
// ),
// ),
// 'mod-opt' => array(
// 'social-size' => array(
// 'input_type' => 'number',
// 'title' => __('Size in px', 'text_doma'),
// 'step' => 1,
// 'min' => 5,
// 'transport' => 'postMessage'
// )
// ),
// 'item-inputs' => array(
// 'item-inputs' => array(
// 'tabs' => array(
// array(
// 'title' => __('Content', 'text_doma'),
// //'attributes' => 'data-sek-device="desktop"',
// 'inputs' => array(
// 'content' => array(
// 'input_type' => 'detached_tinymce_editor',
// 'title' => __('Content', 'text_doma')
// ),
// 'h_alignment_css' => array(
// 'input_type' => 'h_text_alignment',
// 'title' => __('Alignment', 'text_doma'),
// 'default' => is_rtl() ? 'right' : 'left',
// 'refresh_markup' => false,
// 'refresh_stylesheet' => true
// )
// )
// )
// )
// )
// Build the input list from item-inputs and modop-inputs
function _sek_build_input_list( $module_tmpl_data, $input_list = null ) {
$input_list = is_array( $input_list ) ? $input_list : array();
//sek_error_log( '_sek_build_input_list', print_r( $module_tmpl_data , true ) );
foreach( $module_tmpl_data as $key => $data ) {
if ( 'pre-item' === $key )
continue;
if ( is_array( $data ) && array_key_exists( 'input_type', $data ) ) {
// each input_id of a module should be unique
if ( array_key_exists( $key, $input_list ) ) {
sek_error_log( __FUNCTION__ . ' => error => duplicated input_id found => ' . $key );
} else {
$input_list[ $key ] = $data;
}
} else if ( is_array( $data ) ) {
$input_list = _sek_build_input_list( $data, $input_list );
}
}
return $input_list;
}
/* ------------------------------------------------------------------------- *
* NORMALIZE MODULE VALUE WITH DEFAULT
* preprocessing the module model before printing the module template.
* used before rendering or generating css
/* ------------------------------------------------------------------------- */
// @return array() $normalized_model
function sek_normalize_module_value_with_defaults( $raw_module_model ) {
$normalized_model = $raw_module_model;
if ( empty( $normalized_model['module_type'] ) ) {
sek_error_log( __FUNCTION__ . ' => missing module type', $normalized_model );
}
$module_type = $normalized_model['module_type'];
$is_father = sek_get_registered_module_type_property( $module_type, 'is_father' );
$raw_module_value = ( !empty( $raw_module_model['value'] ) && is_array( $raw_module_model['value'] ) ) ? $raw_module_model['value'] : array();
// reset the model value and rewrite it normalized with the defaults
$normalized_model['value'] = array();
if ( $is_father ) {
$children = sek_get_registered_module_type_property( $module_type, 'children' );
if ( empty( $children ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' missing children modules' );
return $default;
}
if ( !is_array( $children ) ) {
sek_error_log( __FUNCTION__ . ' => ' . $module_type . ' children modules should be an array' );
return $default;
}
foreach ( $children as $opt_group => $child_mod_type ) {
$children_value = ( !empty( $raw_module_value[$opt_group] ) && is_array( $raw_module_value[$opt_group] ) ) ? $raw_module_value[$opt_group] : array();
$normalized_model['value'][ $opt_group ] = _sek_normalize_single_module_values( $children_value, $child_mod_type );
}
} else {
$normalized_model['value'] = _sek_normalize_single_module_values( $raw_module_value, $module_type );
}
//sek_error_log('sek_normalize_single_module_values for module type ' . $module_type , $normalized_model );
return $normalized_model;
}
// @return array()
function _sek_normalize_single_module_values( $raw_module_value, $module_type ) {
$default_value_model = sek_get_default_module_model( $module_type );//<= walk the registered modules tree and generates the module default if not already cached
// reset the model value and rewrite it normalized with the defaults
$module_values = array();
if ( czr_is_multi_item_module( $module_type ) ) {
foreach ( $raw_module_value as $item ) {
$module_values[] = wp_parse_args( $item, $default_value_model );
}
} else {
$module_values = wp_parse_args( $raw_module_value, $default_value_model );
}
return $module_values;
}
// Returns an array of allowed HTML tags and attributes when securing form echoed with wp_kses()
function sek_get_allowed_html_in_forms() {
$allowed = array(
'div' => array(),
'span' => array(),
'form' => array(
'action' => true,
'method' => true,
'post' => true
),
'button' => array(
'disabled' => true,
'name' => true,
'type' => true,
'value' => true,
),
'input' => array(
'alt' => true,
'capture' => true,
'checked' => true,
'disabled' => true,
'list' => true,
'name' => true,
'placeholder' => true,
'readonly' => true,
'type' => true,
'value' => true,
),
'label' => array(
'for' => true,
),
'textarea' => array(
'cols' => true,
'disabled' => true,
'maxlength' => true,
'minlength' => true,
'name' => true,
'placeholder' => true,
'readonly' => true,
'rows' => true,
'spellcheck' => true,
'wrap' => true,
),
);
$allowed = array_map(
function ($to_map) {
$attr = array(
'aria-checked' => true,
'aria-describedby' => true,
'aria-details' => true,
'aria-disabled' => true,
'aria-hidden' => true,
'aria-invalid' => true,
'aria-label' => true,
'aria-labelledby' => true,
'aria-live' => true,
'aria-relevant' => true,
'aria-required' => true,
'aria-selected' => true,
'class' => true,
'data-*' => true,
'id' => true,
'inputmode' => true,
'role' => true,
'style' => true,
'tabindex' => true,
'title' => true,
);
return array_merge( $attr, (array) $to_map );
},
$allowed
);
return $allowed;
}
?>
@@ -0,0 +1,249 @@
<?php
/* ------------------------------------------------------------------------- *
* BREAKPOINTS HELPER
/* ------------------------------------------------------------------------- */
function sek_get_global_custom_breakpoint() {
$global_breakpoint_data = sek_get_global_option_value('breakpoint');
if ( is_null( $global_breakpoint_data ) || empty( $global_breakpoint_data['global-custom-breakpoint'] ) )
return;
if ( empty( $global_breakpoint_data[ 'use-custom-breakpoint'] ) || false === sek_booleanize_checkbox_val( $global_breakpoint_data[ 'use-custom-breakpoint'] ) )
return;
return intval( $global_breakpoint_data['global-custom-breakpoint'] );
}
// @return bool
// introduced for https://github.com/presscustomizr/nimble-builder/issues/564
// Let us know if we need to apply the user defined custom breakpoint to all by-device customizations, like alignment
// false by default.
function sek_is_global_custom_breakpoint_applied_to_all_customizations_by_device() {
$global_breakpoint_data = sek_get_global_option_value('breakpoint');
if ( is_null( $global_breakpoint_data ) || empty( $global_breakpoint_data['global-custom-breakpoint'] ) )
return false;
if ( empty( $global_breakpoint_data[ 'use-custom-breakpoint'] ) || false === sek_booleanize_checkbox_val( $global_breakpoint_data[ 'use-custom-breakpoint'] ) )
return false;
// We need a custom breakpoint > 1
if ( intval( $global_breakpoint_data['global-custom-breakpoint'] ) <= 1 )
return;
// apply-to-all option is unchecked by default
// returns true when user has checked the apply to all option
return array_key_exists('apply-to-all', $global_breakpoint_data ) && sek_booleanize_checkbox_val( $global_breakpoint_data[ 'apply-to-all' ] ) ;
}
// invoked when filtering 'sek_add_css_rules_for__section__options'
// param 'for_responsive_columns' has been introduced for https://github.com/presscustomizr/nimble-builder/issues/564
// so we can differentiate when the custom breakpoint is requested for column responsiveness or for css rules generation
// when for columns, we always apply the custom breakpoint defined by the user
// otherwise, when generating CSS rules like alignment, the custom breakpoint is applied if user explicitely checked the 'apply_to_all' option
// 'for_responsive_columns' is set to true when sek_get_closest_section_custom_breakpoint() is invoked from Nimble_Manager()::render()
// @param params array(
// 'section_model' => array(),
// 'for_responsive_columns' => bool
// )
function sek_get_section_custom_breakpoint( $params ) {
if ( !is_array( $params ) )
return;
$params = wp_parse_args( $params, array(
'section_model' => array(),
'for_responsive_columns' => false
));
$section = $params['section_model'];
if ( !is_array( $section ) )
return;
if ( empty($section['id']) )
return;
$options = empty( $section[ 'options' ] ) ? array() : $section['options'];
if ( empty( $options[ 'breakpoint' ] ) )
return;
if ( empty( $options[ 'breakpoint' ][ 'use-custom-breakpoint'] ) || false === sek_booleanize_checkbox_val( $options[ 'breakpoint' ][ 'use-custom-breakpoint'] ) )
return;
// assign default value if use-custom-breakpoint is checked but there's no breakpoint set.
// this can also occur if the custom breakpoint is left to default in the customizer ( default values are not considered when saving )
if ( empty( $options[ 'breakpoint' ][ 'custom-breakpoint' ] ) ) {
if ( array_key_exists('custom-breakpoint', $options[ 'breakpoint' ] ) ) {
// this is the case when user has emptied the setting
$custom_breakpoint = 1;// added when fixing https://github.com/presscustomizr/nimble-builder/issues/623
} else {
$custom_breakpoint = Sek_Dyn_CSS_Builder::$breakpoints['md'];//768
}
} else {
$custom_breakpoint = intval( $options[ 'breakpoint' ][ 'custom-breakpoint' ] );
}
if ( $custom_breakpoint <= 0 )
return 1;
// 1) When the breakpoint is requested for responsive columns, we always return the custom value
if ( $params['for_responsive_columns'] )
return $custom_breakpoint;
// 2) Otherwise ( other CSS rules generation case, like alignment ) we make sure that user want to apply the custom breakpoint also to other by-device customizations
return sek_is_section_custom_breakpoint_applied_to_all_customizations_by_device( $options[ 'breakpoint' ] ) ? $custom_breakpoint : null;
}
// @return bool
// introduced for https://github.com/presscustomizr/nimble-builder/issues/564
// Let us know if we need to apply the user defined custom breakpoint to all by-device customizations, like alignment
// false by default.
// @param $section_breakpoint_options = array(
// 'use-custom-breakpoint' => bool
// 'custom-breakpoint' => int
// 'apply-to-all' => bool
// )
function sek_is_section_custom_breakpoint_applied_to_all_customizations_by_device( $section_breakpoint_options ) {
if ( !is_array( $section_breakpoint_options ) || empty( $section_breakpoint_options ) )
return;
if ( empty( $section_breakpoint_options[ 'use-custom-breakpoint'] ) || false === sek_booleanize_checkbox_val( $section_breakpoint_options[ 'use-custom-breakpoint'] ) )
return;
// We need a custom breakpoint > 1
// Make sure the custom breakpoint has not been emptied, otherwise assign a minimal value of 1px
// fixes : https://github.com/presscustomizr/nimble-builder/issues/623
$custom_breakpoint = empty( $section_breakpoint_options['custom-breakpoint'] ) ? 1 : $section_breakpoint_options['custom-breakpoint'];
if ( intval( $custom_breakpoint ) <= 1 )
return;
// apply-to-all option is unchecked by default
// returns true when user has checked the apply to all option
return array_key_exists('apply-to-all', $section_breakpoint_options ) && sek_booleanize_checkbox_val( $section_breakpoint_options[ 'apply-to-all' ] );
}
// Recursive helper
// Is also used when building the dyn_css or when firing sek_add_css_rules_for_spacing()
// @param id : mandatory
// @param collection : optional <= that's why if missing we must walk all collections : local and global
function sek_get_closest_section_custom_breakpoint( $params ) {
$params = wp_parse_args( $params, array(
'searched_level_id' => '',
'collection' => 'not_set',
'skope_id' => '',
'last_section_breakpoint_found' => 0,
'last_regular_section_breakpoint_found' => 0,
'last_nested_section_breakpoint_found' => 0,
'searched_level_id_found' => false,
// the 'for_responsive_columns' param has been introduced for https://github.com/presscustomizr/nimble-builder/issues/564
// so we can differentiate when the custom breakpoint is requested for column responsiveness or for css rules generation
// when for columns, we always apply the custom breakpoint defined by the user
// otherwise, when generating CSS rules like alignment, the custom breakpoint is applied if user explicitely checked the 'apply_to_all' option
// 'for_responsive_columns' is set to true when sek_get_closest_section_custom_breakpoint() is invoked from Nimble_Manager()::render()
'for_responsive_columns' => false
) );
extract( $params, EXTR_OVERWRITE );
if ( !is_string( $searched_level_id ) || empty( $searched_level_id ) ) {
sek_error_log( __FUNCTION__ . ' => missing or invalid child_level_id param.');
return $last_section_breakpoint_found;;
}
if ( $searched_level_id_found ) {
return $last_section_breakpoint_found;
}
// When no collection is provided, we must walk all collections, local and global.
if ( 'not_set' === $collection ) {
if ( empty( $skope_id ) ) {
if ( is_array( $_POST ) && !empty( $_POST['location_skope_id'] ) ) {
$skope_id = sanitize_text_field($_POST['location_skope_id']);
} else {
// When fired during an ajax 'customize_save' action, the skp_get_skope_id() is determined with $_POST['local_skope_id']
// @see add_filter( 'skp_get_skope_id', '\Nimble\sek_filter_skp_get_skope_id', 10, 2 );
$skope_id = skp_get_skope_id();
}
}
if ( empty( $skope_id ) || '_skope_not_set_' === $skope_id ) {
sek_error_log( __FUNCTION__ . ' => the skope_id should not be empty.');
}
$local_skope_settings = sek_get_skoped_seks( $skope_id );
$local_collection = ( is_array( $local_skope_settings ) && !empty( $local_skope_settings['collection'] ) ) ? $local_skope_settings['collection'] : array();
$global_skope_settings = sek_get_skoped_seks( NIMBLE_GLOBAL_SKOPE_ID );
$global_collection = ( is_array( $global_skope_settings ) && !empty( $global_skope_settings['collection'] ) ) ? $global_skope_settings['collection'] : array();
$collection = array_merge( $local_collection, $global_collection );
}
// Loop collections
foreach ( $collection as $level_data ) {
//sek_error_log($last_section_breakpoint_found . ' MATCH ? => LEVEL ID AND TYPE => ' . $level_data['level'] . ' | ' . $level_data['id'] );
// stop here and return if a match was recursively found
if ( $searched_level_id_found )
break;
if ( 'section' == $level_data['level'] ) {
$section_maybe_custom_breakpoint = intval( sek_get_section_custom_breakpoint( array( 'section_model' => $level_data, 'for_responsive_columns' => $for_responsive_columns ) ) );
if ( !empty( $level_data['is_nested'] ) && $level_data['is_nested'] ) {
$last_nested_section_breakpoint_found = $section_maybe_custom_breakpoint;
} else {
$last_nested_section_breakpoint_found = 0;//reset last nested breakpoint
$last_regular_section_breakpoint_found = $section_maybe_custom_breakpoint;
}
}
if ( array_key_exists( 'id', $level_data ) && $searched_level_id == $level_data['id'] ) {
//match found, break this loop
if ( $last_nested_section_breakpoint_found >= 1 ) {
$last_section_breakpoint_found = $last_nested_section_breakpoint_found;
} else if ( $last_regular_section_breakpoint_found >= 1 ) {
$last_section_breakpoint_found = $last_regular_section_breakpoint_found;
} else {
$last_section_breakpoint_found = 0;
}
$searched_level_id_found = true;
break;
}
if ( !$searched_level_id_found && array_key_exists( 'collection', $level_data ) && is_array( $level_data['collection'] ) ) {
$collection = $level_data['collection'];
$recursive_params = compact(
'searched_level_id',
'collection',
'skope_id',
'last_section_breakpoint_found',
'last_regular_section_breakpoint_found',
'last_nested_section_breakpoint_found',
'searched_level_id_found',
'for_responsive_columns'
);
$recursive_values = sek_get_closest_section_custom_breakpoint( $recursive_params );
if ( is_array($recursive_values) ) {
extract( $recursive_values );
} else {
$last_section_breakpoint_found = $recursive_values;
$searched_level_id_found = true;
break;
}
}
}
// Returns a breakpoint int if found or an array
// => this way we can determine if we continue or not to walk recursively
return $searched_level_id_found ? $last_section_breakpoint_found : compact(
'searched_level_id_found',
'last_section_breakpoint_found',
'last_regular_section_breakpoint_found',
'last_nested_section_breakpoint_found'
);
}
?>
@@ -0,0 +1,212 @@
<?php
/* ------------------------------------------------------------------------- *
* LOCAL OPTIONS HELPERS
/* ------------------------------------------------------------------------- */
// @param $option_name = string
// 'nimble_front_classes_ready' is fired when Nimble_Manager() is instanciated
function sek_get_local_option_value( $option_name = '', $skope_id = null ) {
if ( empty($option_name) ) {
sek_error_log( __FUNCTION__ . ' => invalid option name' );
return array();
}
if ( !skp_is_customizing() && did_action('nimble_front_classes_ready') && '_not_cached_yet_' !== Nimble_Manager()->local_options ) {
$local_options = Nimble_Manager()->local_options;
} else {
// use the provided skope_id if in the signature
$skope_id = ( !empty( $skope_id ) && is_string( $skope_id ))? $skope_id : skp_get_skope_id();
$localSkopeNimble = sek_get_skoped_seks( $skope_id );
$local_options = ( is_array( $localSkopeNimble ) && !empty( $localSkopeNimble['local_options'] ) && is_array( $localSkopeNimble['local_options'] ) ) ? $localSkopeNimble['local_options'] : array();
// Cache only after 'wp' && 'nimble_front_classes_ready'
// never cache when doing ajax
if ( did_action('nimble_front_classes_ready') && did_action('wp') && !defined('DOING_AJAX') ) {
Nimble_Manager()->local_options = $local_options;
}
}
// maybe normalizes with default values
$values = ( !empty( $local_options ) && !empty( $local_options[ $option_name ] ) ) ? $local_options[ $option_name ] : null;
if ( did_action('nimble_front_classes_ready') ) {
$values = sek_normalize_local_options_with_defaults( $option_name, $values );
}
return $values;
}
// Introduced for site templates, when using function sek_is_inheritance_locally_disabled()
// needed because we can't rely on sek_get_skoped_seks() to get current local sections data, because this function returns the inherited data
// @param $option_name = string
// 'nimble_front_classes_ready' is fired when Nimble_Manager() is instanciated
function sek_get_local_option_value_without_inheritance( $option_name = '', $skope_id = null ) {
if ( empty($option_name) ) {
sek_error_log( __FUNCTION__ . ' => invalid option name' );
return array();
}
if ( !skp_is_customizing() && did_action('nimble_front_classes_ready') && '_not_cached_yet_' !== Nimble_Manager()->local_options_without_tmpl_inheritance ) {
$local_options_without_tmpl_inheritance = Nimble_Manager()->local_options_without_tmpl_inheritance;
} else {
// use the provided skope_id if in the signature
$skope_id = ( !empty( $skope_id ) && is_string( $skope_id ))? $skope_id : skp_get_skope_id();
$localSkopeNimble = sek_get_seks_without_group_inheritance( $skope_id );
if ( skp_is_customizing() && NIMBLE_GLOBAL_SKOPE_ID != $skope_id ) {
// when customizing, let us filter the value with the 'customized' ones
$localSkopeNimble = apply_filters(
'sek_get_skoped_seks',
$localSkopeNimble,
$skope_id,
''
);
}
$local_options_without_tmpl_inheritance = ( is_array( $localSkopeNimble ) && !empty( $localSkopeNimble['local_options'] ) && is_array( $localSkopeNimble['local_options'] ) ) ? $localSkopeNimble['local_options'] : array();
// Cache only after 'wp' && 'nimble_front_classes_ready'
// never cache when doing ajax
if ( did_action('nimble_front_classes_ready') && did_action('wp') && !defined('DOING_AJAX') ) {
Nimble_Manager()->local_options_without_tmpl_inheritance = $local_options_without_tmpl_inheritance;
}
}
// maybe normalizes with default values
$values = ( !empty( $local_options_without_tmpl_inheritance ) && !empty( $local_options_without_tmpl_inheritance[ $option_name ] ) ) ? $local_options_without_tmpl_inheritance[ $option_name ] : null;
if ( did_action('nimble_front_classes_ready') ) {
$values = sek_normalize_local_options_with_defaults( $option_name, $values );
}
return $values;
}
// @return array() $normalized_values
// @see _1_6_4_sektions_generate_UI_local_skope_options.js
function sek_normalize_local_options_with_defaults( $option_name, $raw_module_values ) {
if ( empty($option_name) ) {
sek_error_log( __FUNCTION__ . ' => invalid option name' );
return array();
}
$normalized_values = ( !empty($raw_module_values) && is_array( $raw_module_values ) ) ? $raw_module_values : array();
// map the option key as saved in db ( @see _1_6_4_sektions_generate_UI_local_skope_options.js ) and the module type
$local_option_map = SEK_Front_Construct::$local_options_map;
if ( !array_key_exists($option_name, $local_option_map) ) {
sek_error_log( __FUNCTION__ . ' => invalid option name', $option_name );
return $raw_module_values;
} else {
$module_type = $local_option_map[$option_name];
}
// normalize with the defaults
// class_exists check introduced since https://github.com/presscustomizr/nimble-builder/issues/432
// may not be mandatory
if ( class_exists('\Nimble\CZR_Fmk_Base') ) {
if( CZR_Fmk_Base()->czr_is_module_registered($module_type) ) {
$normalized_values = _sek_normalize_single_module_values( $normalized_values, $module_type );
}
}
return $normalized_values;
}
/* ------------------------------------------------------------------------- *
* GLOBAL OPTIONS HELPERS
/* ------------------------------------------------------------------------- */
// @param $option_name = string
// 'nimble_front_classes_ready' is fired when Nimble_Manager() is instanciated
function sek_get_global_option_value( $option_name = '' ) {
if ( empty($option_name) ) {
sek_error_log( __FUNCTION__ . ' => invalid option name' );
return array();
}
if ( !skp_is_customizing() && did_action('nimble_front_classes_ready') && '_not_cached_yet_' !== Nimble_Manager()->global_nimble_options ) {
$global_nimble_options = Nimble_Manager()->global_nimble_options;
} else {
$global_nimble_options = get_option( NIMBLE_OPT_NAME_FOR_GLOBAL_OPTIONS );
//sek_error_log(' SOOO OPTIONS ?', $global_nimble_options );
// cache when nimble is ready
// this hook is fired when Nimble_Manager() is instanciated
// never cache when doing ajax
if ( did_action('nimble_front_classes_ready') && !defined('DOING_AJAX') ) {
Nimble_Manager()->global_nimble_options = $global_nimble_options;
}
}
// maybe normalizes with default values
$values = ( is_array( $global_nimble_options ) && !empty( $global_nimble_options[ $option_name ] ) ) ? $global_nimble_options[ $option_name ] : null;
if ( did_action('nimble_front_classes_ready') ) {
$values = sek_normalize_global_options_with_defaults( $option_name, $values );
}
return $values;
}
// @see _1_6_5_sektions_generate_UI_global_options.js
// @return array() $normalized_values
function sek_normalize_global_options_with_defaults( $option_name, $raw_module_values ) {
if ( empty($option_name) ) {
sek_error_log( __FUNCTION__ . ' => invalid option name' );
return array();
}
$normalized_values = ( !empty($raw_module_values) && is_array( $raw_module_values ) ) ? $raw_module_values : array();
// map the option key as saved in db ( @see _1_6_5_sektions_generate_UI_global_options.js ) and the module type
$global_option_map = SEK_Front_Construct::$global_options_map;
//sek_error_log('SEK_Front_Construct::$global_options_map', SEK_Front_Construct::$global_options_map );
if ( !array_key_exists($option_name, $global_option_map) ) {
sek_error_log( __FUNCTION__ . ' => invalid option name', $option_name );
return $raw_module_values;
} else {
$module_type = $global_option_map[$option_name];
}
// normalize with the defaults
// class_exists check introduced since https://github.com/presscustomizr/nimble-builder/issues/432
// may not be mandatory
if ( class_exists('\Nimble\CZR_Fmk_Base') ) {
if( CZR_Fmk_Base()->czr_is_module_registered($module_type) ) {
$normalized_values = _sek_normalize_single_module_values( $normalized_values, $module_type );
}
} else {
sek_error_log( __FUNCTION__ . ' => error => CZR_Fmk_Base not loaded' );
}
return $normalized_values;
}
// // @see _1_6_5_sektions_generate_UI_site_tmpl_options.js
// // @return array() $normalized_values
// function sek_normalize_site_tmpl_options_with_defaults( $option_name, $raw_module_values ) {
// if ( empty($option_name) ) {
// sek_error_log( __FUNCTION__ . ' => invalid option name' );
// return array();
// }
// $normalized_values = ( !empty($raw_module_values) && is_array( $raw_module_values ) ) ? $raw_module_values : array();
// // map the option key as saved in db ( @see _1_6_5_sektions_generate_UI_global_options.js ) and the module type
// $site_tmpl_options_map = SEK_Front_Construct::$site_tmpl_options_map;
// //sek_error_log('SEK_Front_Construct::$global_options_map', SEK_Front_Construct::$global_options_map );
// if ( !array_key_exists($option_name, $site_tmpl_options_map) ) {
// sek_error_log( __FUNCTION__ . ' => invalid option name', $option_name );
// return $raw_module_values;
// } else {
// $module_type = $site_tmpl_options_map[$option_name];
// }
// // normalize with the defaults
// // class_exists check introduced since https://github.com/presscustomizr/nimble-builder/issues/432
// // may not be mandatory
// if ( class_exists('\Nimble\CZR_Fmk_Base') ) {
// if( CZR_Fmk_Base()->czr_is_module_registered($module_type) ) {
// $normalized_values = _sek_normalize_single_module_values( $normalized_values, $module_type );
// }
// } else {
// sek_error_log( __FUNCTION__ . ' => error => CZR_Fmk_Base not loaded' );
// }
// return $normalized_values;
// }
?>
@@ -0,0 +1,457 @@
<?php
/* ------------------------------------------------------------------------- *
* Dynamic variables parsing
/* ------------------------------------------------------------------------- */
function sek_find_pattern_match($matches) {
$replace_values = apply_filters( 'sek_template_tags', array(
'home_url' => 'home_url',
'year_now' => date("Y"),
'site_title' => 'get_bloginfo',
'the_title' => 'sek_get_the_title',
'the_archive_title' => 'sek_get_the_archive_title',// works for authors, CPT, taxonomies
'the_archive_description' => 'sek_get_the_archive_description',// works for authors, CPT, taxonomies
'the_content' => 'sek_get_the_content',
'the_tags' => 'sek_get_the_tags',
'the_categories' => 'sek_get_the_categories',
'the_author_link' => 'sek_get_the_author_link',
'the_author_name' => 'sek_get_the_author_name',
'the_author_avatar' => 'sek_get_the_author_avatar',
'the_author_bio' => 'sek_get_the_author_bio',
'the_published_date' => 'sek_get_the_published_date',
'the_modified_date' => 'sek_get_the_modified_date',
'the_comments' => 'sek_get_the_comments',
'the_previous_post_link' => 'sek_get_previous_post_link',
'the_next_post_link' => 'sek_get_next_post_link',
'the_comment_number' => 'sek_get_the_comment_number',
'the_search_query' => 'sek_get_search_query',
'the_search_results_number' => 'sek_get_search_results_nb'
));
// Are we good after the filter ?
if ( !is_array($replace_values) )
return;
//sek_error_log('$matches ??', $matches );
if ( !is_array($matches) || empty($matches[1]) )
return;
//$data = html_entity_decode($matches[1], ENT_QUOTES, get_bloginfo( 'charset' ) );
$data = explode(' ', $matches[1] );
// Filter so that {{the_categories sep="/"}} becomes array('the_categories', 'sep="/"' ) with no empty entries
// => the first entry is the template tag name, the other entries are the callback arguments ( to implement April 2021 )
$new_data = array_filter($data, function($value) {
if ( !is_string($value) )
return false;
$value = ltrim($value);
return !is_null($value) && !empty($value) && preg_match("/[a-z]/i", $value) ;
});
if ( isset($new_data[0]) && array_key_exists( $new_data[0], $replace_values ) ) {
// @todo => authorize arguments passed as an array
$dyn_content = $replace_values[$new_data[0]];
$fn_name = $dyn_content;// <= typically not namespaced if WP core function, or function added with a filter from a child theme for example
$namespaced_fn_name = __NAMESPACE__ . '\\' . $dyn_content; // <= namespaced if Nimble Builder function, introduced in october 2019 for https://github.com/presscustomizr/nimble-builder/issues/401
if ( function_exists( $namespaced_fn_name ) ) {
return $namespaced_fn_name();//<= @TODO use call_user_func() here + handle the case when the callback is a method
} else if ( function_exists( $fn_name ) ) {
return $fn_name();//<= @TODO use call_user_func() here + handle the case when the callback is a method
} else if ( is_string($dyn_content) ) {
return $dyn_content;
} else {
return null;
}
}
return null;
}
// fired @filter 'nimble_parse_template_tags'
function sek_parse_template_tags( $val ) {
//the pattern could also be '!\{\{(\w+)\}\}!', but adding \s? allows us to allow spaces around the term inside curly braces
//see https://stackoverflow.com/questions/959017/php-regex-templating-find-all-occurrences-of-var#comment71815465_959026
//return is_string( $val ) ? preg_replace_callback( '!\{\{\s?(\w+)\s?\}\}!', '\Nimble\sek_find_pattern_match', $val) : $val;
return is_string( $val ) ? preg_replace_callback( '!\{\{\s?(.*?)\s?\}\}!', '\Nimble\sek_find_pattern_match', $val) : $val;
}
add_filter( 'nimble_parse_template_tags', '\Nimble\sek_parse_template_tags' );
// CALLBACKS WHEN IS_ARCHIVE()
function sek_get_the_archive_title() {
$is_archive = is_archive();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_archive = sek_get_posted_query_param_when_customizing( 'is_archive' );
}
if ( !$is_archive ) {
return sek_get_tmpl_tag_error( $tag = 'the_archive_title', $msg = __('It can be used in archive pages only.', 'text_doma') );
}
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$title = sek_get_posted_query_param_when_customizing( 'the_archive_title' );
} else {
add_filter('get_the_archive_title_prefix', '__return_false');
$title = get_the_archive_title();
remove_filter('get_the_archive_title_prefix', '__return_false');
}
return $title;
}
function sek_get_the_archive_description() {
$is_archive = is_archive();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_archive = sek_get_posted_query_param_when_customizing( 'is_archive' );
}
if ( !$is_archive ) {
return sek_get_tmpl_tag_error( $tag = 'the_archive_description', $msg = __('It can be used in archive pages only.', 'text_doma') );
}
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$title = sek_get_posted_query_param_when_customizing( 'the_archive_description' );
} else {
$title = get_the_archive_description();
}
return $title;
}
// CALLBACKS WHEN IS_SINGULAR()
function sek_get_next_post_link() {
$is_singular = is_singular();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_singular = sek_get_posted_query_param_when_customizing( 'is_singular' );
}
if ( !$is_singular ) {
return sek_get_tmpl_tag_error( $tag = 'the_next_post_link', $msg = __('It can only be used in single pages or single posts.', 'text_doma') );
}
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$title = sek_get_posted_query_param_when_customizing( 'the_next_post_link' );
} else {
$title = get_next_post_link( $format = '%link' );
}
if ( empty( $title ) ) {
return '';
} else {
return sprintf( '<span class="sek-next-post-link">%1$s</span>', $title );
}
}
function sek_get_previous_post_link() {
$is_singular = is_singular();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_singular = sek_get_posted_query_param_when_customizing( 'is_singular' );
}
if ( !$is_singular ) {
return sek_get_tmpl_tag_error( $tag = 'the_previous_post_link', $msg = __('It can only be used in single pages or single posts.', 'text_doma') );
}
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$title = sek_get_posted_query_param_when_customizing( 'the_previous_post_link' );
} else {
$title = get_previous_post_link( $format = '%link' );
}
if ( empty( $title ) ) {
return '';
} else {
return sprintf( '<span class="sek-previous-post-link">%1$s</span>', $title );
}
}
function sek_get_the_comments() {
$is_singular = is_singular();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_singular = sek_get_posted_query_param_when_customizing( 'is_singular' );
}
if ( !$is_singular ) {
return sek_get_tmpl_tag_error( $tag = 'the_comments', $msg = __('It can only be used in single pages or single posts.', 'text_doma') );
}
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
return sprintf('<div class="nimble-notice-in-preview"><i class="fas fa-info-circle"></i>&nbsp;%1$s</div>',
__('Comment template can not be refreshed while customizing', 'text_doma')
);
}
ob_start();
//load_template( $tmpl_path, false );
if ( comments_open() || get_comments_number() ) {
add_filter('comments_template', '\Nimble\sek_set_nb_comments_template_path');
comments_template();
remove_filter('comments_template', '\Nimble\sek_set_nb_comments_template_path');
}
return ob_get_clean();
}
//@filter 'comments_template'
function sek_set_nb_comments_template_path( $original_path ) {
//@to do => make this path overridable
$nb_path = sek_get_templates_dir() . "/wp/comments-template.php";
if ( file_exists( $nb_path ) ) {
return $nb_path;
}
return $original_path;
}
function sek_get_the_published_date() {
$is_singular = is_singular();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_singular = sek_get_posted_query_param_when_customizing( 'is_singular' );
}
if ( !$is_singular ) {
return sek_get_tmpl_tag_error( $tag = 'the_published_date', $msg = __('It can only be used in single pages or single posts.', 'text_doma') );
}
$post_id = sek_get_post_id_on_front_and_when_customizing();
$published_date = get_the_date( get_option('date_format'), $post_id);
$machine_readable_published_date = esc_attr( get_the_date( 'c' , $post_id ) );
return sprintf( '<time class="sek-published-date" datetime="%1$s">%2$s</time>',
$machine_readable_published_date,
$published_date
);
}
function sek_get_the_modified_date() {
$is_singular = is_singular();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_singular = sek_get_posted_query_param_when_customizing( 'is_singular' );
}
if ( !$is_singular ) {
return sek_get_tmpl_tag_error( $tag = 'the_modified_date', $msg = __('It can only be used in single pages or single posts.', 'text_doma') );
}
$post_id = sek_get_post_id_on_front_and_when_customizing();
$modified_date = get_the_modified_date( get_option('date_format'), $post_id );
$machine_readable_modified_date = esc_attr( get_the_modified_date( 'c' ), $post_id );
return sprintf( '<time class="sek-modified-date" datetime="%1$s">%2$s</time>',
$machine_readable_modified_date ,
$modified_date
);
}
function sek_get_the_tags( $separator = ' &middot; ') {
$is_singular = is_singular();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_singular = sek_get_posted_query_param_when_customizing( 'is_singular' );
}
if ( !$is_singular ) {
return sek_get_tmpl_tag_error( $tag = 'the_tags', $msg = __('It can only be used in single pages or single posts.', 'text_doma') );
}
return sprintf( '<span class="sek-post-tags">%1$s</span>', get_the_tag_list( $before = '', $sep = $separator, $after = '', $post_id = sek_get_post_id_on_front_and_when_customizing() ) );
}
function sek_get_the_categories( $separator = ' / ') {
$is_singular = is_singular();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_singular = sek_get_posted_query_param_when_customizing( 'is_singular' );
}
if ( !$is_singular ) {
return sek_get_tmpl_tag_error( $tag = 'the_categories', $msg = __('It can only be used in single pages or single posts.', 'text_doma') );
}
return sprintf( '<span class="sek-post-category">%1$s</span>', get_the_category_list( $separator, '', $post_id = sek_get_post_id_on_front_and_when_customizing() ) );
}
function sek_get_the_comment_number() {
$is_singular = is_singular();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_singular = sek_get_posted_query_param_when_customizing( 'is_singular' );
}
if ( !$is_singular ) {
return sek_get_tmpl_tag_error( $tag = 'the_comment_number', $msg = __('It can only be used in single pages or single posts.', 'text_doma') );
}
return sprintf( '<span class="sek-post-comment-number">%1$s</span>', get_comments_number_text( $zero = false, $one = false, $more = false, $post_id = sek_get_post_id_on_front_and_when_customizing() ) );
}
// AUTHOR DATA
// 2 CASES : singular or author archives
function sek_get_the_author_link() {
$author_id = sek_get_author_id_on_front_and_when_customizing();
if ( $author_id ) {
$display_name = get_the_author_meta( 'display_name', $author_id );
return sprintf(
'<a href="%1$s" title="%2$s" class="sek-author-link" rel="author">%3$s</a>',
esc_url( get_author_posts_url( $author_id, get_the_author_meta( 'user_nicename', $author_id ) ) ),
/* translators: %s: Author's display name. */
esc_attr( sprintf( __( 'Posts by %s' ), $display_name ) ),
$display_name
);
}
return null;
}
function sek_get_the_author_name() {
$author_id = sek_get_author_id_on_front_and_when_customizing();
if ( $author_id ) {
return sprintf( '<span class="sek-author-name">%1$s</span>', get_the_author_meta( 'display_name', $author_id ) );
}
return null;
}
function sek_get_the_author_avatar() {
$author_id = sek_get_author_id_on_front_and_when_customizing();
if ( $author_id ) {
return get_avatar( get_the_author_meta( 'ID', $author_id ), '85' );
}
return null;
}
function sek_get_the_author_bio() {
$author_id = sek_get_author_id_on_front_and_when_customizing();
if ( $author_id ) {
return sprintf( '<span class="sek-author-description">%1$s</span>', get_the_author_meta( 'description', $author_id ) );
}
return null;
}
// introduced in october 2019 for https://github.com/presscustomizr/nimble-builder/issues/401
function sek_get_the_title() {
$is_singular = is_singular();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_singular = sek_get_posted_query_param_when_customizing( 'is_singular' );
}
if ( !$is_singular ) {
return sek_get_tmpl_tag_error( $tag = 'the_title', $msg = __('It can only be used in single pages or single posts.', 'text_doma') );
}
return get_the_title( sek_get_post_id_on_front_and_when_customizing() );
}
// introduced in october 2019 for https://github.com/presscustomizr/nimble-builder/issues/401
function sek_get_the_content() {
$is_singular = is_singular();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_singular = sek_get_posted_query_param_when_customizing( 'is_singular' );
}
if ( !$is_singular ) {
return sek_get_tmpl_tag_error( $tag = 'the_content', $msg = __('It can only be used in single pages or single posts.', 'text_doma') );
}
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$post_id = (int)sek_get_posted_query_param_when_customizing( 'post_id' );
if ( is_int($post_id) ) {
$post_object = get_post( $post_id );
return !empty( $post_object ) ? apply_filters( 'the_content', $post_object->post_content ) : null;
}
} else {
$post_object = get_post();
return !empty( $post_object ) ? apply_filters( 'the_content', $post_object->post_content ) : null;
}
return null;
}
// CALLBACKS WHEN IS_SEARCH()
function sek_get_search_query() {
$is_search = is_search();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_search = sek_get_posted_query_param_when_customizing( 'is_search' );
$search_query = sek_get_posted_query_param_when_customizing( 'the_search_query' );
} else {
$search_query = get_search_query();
}
if ( !$is_search ) {
return sek_get_tmpl_tag_error( $tag = 'the_search_query', $msg = __('It can only be used in search results page.', 'text_doma') );
}
return sprintf( '<span class="sek-search-query">%1$s</span>', esc_html( $search_query ) );
}
function sek_get_search_results_nb() {
$is_search = is_search();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_search = sek_get_posted_query_param_when_customizing( 'is_search' );
$search_res_nb = sek_get_posted_query_param_when_customizing( 'the_search_results_nb' );
} else {
global $wp_query;
$search_res_nb = (int)$wp_query->found_posts;
}
if ( !$is_search ) {
return sek_get_tmpl_tag_error( $tag = 'the_search_results_number', $msg = __('It can only be used in search results page.', 'text_doma') );
}
return sprintf( '<span class="sek-search-results-number">%1$s</span>', esc_html( $search_res_nb ) );
}
//////////////////////////////////////////////////
///// HELPERS
/////////////////////////////////////////////////
function sek_get_author_id_on_front_and_when_customizing() {
$is_singular = is_singular();
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$is_singular = sek_get_posted_query_param_when_customizing( 'is_singular' );
}
if ( $is_singular ) {
$post_id = sek_get_post_id_on_front_and_when_customizing();
$post_object = get_post( $post_id );
if ( empty( $post_object ) || !is_object( $post_object ) ) {
$author_id = null;
}
$author_id = $post_object->post_author;
} else {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$author_id = sek_get_posted_query_param_when_customizing( 'the_author_id' );
} else {
global $authordata;
$author_id = isset( $authordata->ID ) ? $authordata->ID : 0;
}
}
return $author_id;
}
// @return the post id in all cases
// when performing ajax action, we need the posted query params made available from the ajax params
function sek_get_post_id_on_front_and_when_customizing() {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX && skp_is_customizing() ) {
$post_id = (int)sek_get_posted_query_param_when_customizing( 'post_id' );
} else {
$post_id = get_the_ID();
}
return is_int($post_id) ? $post_id : null;
}
// recursively sanitize an array of posted ($_POST) query_params to be used when customzing
// @param params (array)
function sek_sanitize_query_params_array( $params = array()) {
foreach ($params as $prm => $val) {
if ( is_array($val) ) {
if ( empty($val) ) {
$sanitized_query_params[$prm] = [];
} else {
$sanitized_query_params[$prm] = sek_sanitize_query_params_array($params);
}
} else {
$sanitized_query_params[$prm] = sanitize_text_field($val);
}
}
return $sanitized_query_params;
}
// introduced in october 2019 for https://github.com/presscustomizr/nimble-builder/issues/401
// Possible params as of October 2019
// @see inc/czr-skope/_dev/1_1_0_skop_customizer_preview_load_assets.php::
// 'is_singular' => $wp_query->is_singular,
// 'post_id' => get_the_ID()
function sek_get_posted_query_param_when_customizing( $param ) {
if ( isset( $_POST['czr_query_params'] ) ) {
$query_params = json_decode( wp_unslash( $_POST['czr_query_params'] ), true );
if ( array_key_exists( $param, $query_params ) ) {
if ( !is_array($query_params[$param]) ) {
return sanitize_text_field($query_params[$param]);
} else {
return sek_sanitize_query_params_array($query_params[$param]);
}
} else {
sek_error_log( __FUNCTION__ . ' => invalid param requested');
return null;
}
}
return null;
}
function sek_get_tmpl_tag_error( $tag, $msg ) {
if ( !skp_is_customizing() )
return;
return sprintf('<div class="nimble-notice-in-preview nimble-inline-notice-in-preview"><i class="fas fa-info-circle"></i> %1$s %2$s</div>',
'{{' . $tag . '}} ' . __('could not be printed.', 'text_doma'),
$msg
);
}
?>
@@ -0,0 +1,128 @@
<?php
/* ------------------------------------------------------------------------- *
* TEMPLATE OVERRIDE HELPERS
/* ------------------------------------------------------------------------- */
// TEMPLATES PATH
// added for #532, october 2019
/**
* Returns the path to the NIMBLE templates directory
* inspîred from /wp-content/plugins/easy-digital-downloads/includes/template-functions.php
*/
function sek_get_templates_dir() {
return NIMBLE_BASE_PATH . "/tmpl";
}
// added for #532, october 2019
/* Returns the template directory name.
* inspîred from /wp-content/plugins/easy-digital-downloads/includes/template-functions.php
*/
function sek_get_theme_template_dir_name() {
return trailingslashit( apply_filters( 'nimble_templates_dir', 'nimble_templates' ) );
}
// added for #532, october 2019
/**
* Returns a list of paths to check for template locations
* inspîred from /wp-content/plugins/easy-digital-downloads/includes/template-functions.php
*/
function sek_get_theme_template_base_paths() {
$template_dir = sek_get_theme_template_dir_name();
$file_paths = array(
1 => trailingslashit( get_stylesheet_directory() ) . $template_dir,
10 => trailingslashit( get_template_directory() ) . $template_dir
);
$file_paths = apply_filters( 'nimble_template_paths', $file_paths );
// sort the file paths based on priority
ksort( $file_paths, SORT_NUMERIC );
return array_map( 'trailingslashit', $file_paths );
}
// @return path string
// added for #400
// @param params = array(
// 'file_name' string 'nimble_template.php',
// 'folder' => string 'page-templates', 'header', 'footer'
// )
// @param
function sek_maybe_get_overriden_local_template_path( $params = array() ) {
if ( empty( $params ) || !is_array( $params ))
return;
$params = wp_parse_args( $params, array( 'file_name' => '', 'folder' => 'page-templates' ) );
if ( !in_array( $params['folder'] , array( 'page-templates', 'header', 'footer' ) ) )
return;
$overriden_template_path = '';
// try locating this template file by looping through the template paths
// inspîred from /wp-content/plugins/easy-digital-downloads/includes/template-functions.php
foreach( sek_get_theme_template_base_paths() as $path_candidate ) {
if( file_exists( $path_candidate . $params['folder'] . '/' . $params['file_name'] ) ) {
$overriden_template_path = $path_candidate . $params['folder'] . '/' . $params['file_name'];
break;
}
}
return $overriden_template_path;
}
// @return mixed null || string
function sek_get_locale_template(){
$template_path = null;
$local_template_data = sek_get_local_option_value( 'template' );
if ( !empty( $local_template_data ) && !empty( $local_template_data['local_template'] ) && 'default' !== $local_template_data['local_template'] ) {
$template_file_name = $local_template_data['local_template'];
$template_file_name_with_php_extension = $template_file_name . '.php';
// Set the default template_path first
$template_path = sek_get_templates_dir() . "/page-templates/{$template_file_name_with_php_extension}";
// Make this filtrable
// (this filter is used in Hueman theme to assign a specific template)
$template_path = apply_filters( 'nimble_get_locale_template_path', $template_path, $template_file_name );
// Use an override if any
// Default page tmpl path looks like : NIMBLE_BASE_PATH . "/tmpl/page-template/nimble_template.php",
$overriden_template_path = sek_maybe_get_overriden_local_template_path( array( 'file_name' => $template_file_name_with_php_extension, 'folder' => 'page-templates' ) );
if ( !empty( $overriden_template_path ) ) {
$template_path = $overriden_template_path;
}
if ( !file_exists( $template_path ) ) {
sek_error_log( __FUNCTION__ .' the custom template does not exist', $template_path );
$template_path = null;
}
}
return $template_path;
}
/* ------------------------------------------------------------------------- *
* HEADER FOOTER
/* ------------------------------------------------------------------------- */
// fired by sek_maybe_set_local_nimble_footer() @get_footer()
// fired by sek_maybe_set_local_nimble_header() @get_header()
function sek_page_uses_nimble_header_footer() {
// cache the properties if not done yet
Nimble_Manager()->sek_maybe_set_nimble_header_footer();
return true === Nimble_Manager()->has_local_header_footer || true === Nimble_Manager()->has_global_header_footer;
}
// DEPRECATED SINCE Nimble v1.3.0, november 2018
// was used in the Hueman theme before version 3.4.9
function render_content_sections_for_nimble_template() {
Nimble_Manager()->render_nimble_locations(
array_keys( Nimble_Manager()->default_locations ),//array( 'loop_start', 'before_content', 'after_content', 'loop_end'),
array( 'fallback_location' => 'loop_start' )
);
}
?>
@@ -0,0 +1,114 @@
<?php
// Recursively walk the level tree until a match is found
// @param id = the id of the level for which the model shall be returned
// @param $collection = sek_get_skoped_seks( $skope_id )['collection']; <= the root collection must always be provided, so we are sure it's
function sek_get_level_model( $id, $collection = array() ) {
$_data = 'no_match';
if ( !is_array( $collection ) ) {
sek_error_log( __FUNCTION__ . ' => invalid collection param when getting model for id : ' . $id );
return $_data;
}
foreach ( $collection as $level_data ) {
// stop here and return if a match was recursively found
if ( 'no_match' != $_data )
break;
if ( array_key_exists( 'id', $level_data ) && $id === $level_data['id'] ) {
$_data = $level_data;
} else {
if ( array_key_exists( 'collection', $level_data ) && is_array( $level_data['collection'] ) ) {
$_data = sek_get_level_model( $id, $level_data['collection'] );
}
}
}
return $_data;
}
// Recursive helper
// Typically used when ajaxing
// Is also used when building the dyn_css or when firing sek_add_css_rules_for_spacing()
// @param id : mandatory
// @param collection : optional <= that's why if missing we must walk all collections : local and global
function sek_get_parent_level_model( $child_level_id = '', $collection = array(), $skope_id = '' ) {
$_parent_level_data = 'no_match';
if ( !is_string( $child_level_id ) || empty( $child_level_id ) ) {
sek_error_log( __FUNCTION__ . ' => missing or invalid child_level_id param.');
return $_parent_level_data;
}
// When no collection is provided, we must walk all collections, local and global.
if ( empty( $collection ) ) {
if ( empty( $skope_id ) ) {
if ( is_array( $_POST ) && !empty( $_POST['location_skope_id'] ) ) {
$skope_id = sanitize_text_field($_POST['location_skope_id']);
} else {
// When fired during an ajax 'customize_save' action, the skp_get_skope_id() is determined with $_POST['local_skope_id']
// @see add_filter( 'skp_get_skope_id', '\Nimble\sek_filter_skp_get_skope_id', 10, 2 );
$skope_id = skp_get_skope_id();
}
}
if ( empty( $skope_id ) || '_skope_not_set_' === $skope_id ) {
sek_error_log( __FUNCTION__ . ' => the skope_id should not be empty.');
}
$local_skope_settings = sek_get_skoped_seks( $skope_id );
$local_collection = ( is_array( $local_skope_settings ) && !empty( $local_skope_settings['collection'] ) ) ? $local_skope_settings['collection'] : array();
$global_skope_settings = sek_get_skoped_seks( NIMBLE_GLOBAL_SKOPE_ID );
$global_collection = ( is_array( $global_skope_settings ) && !empty( $global_skope_settings['collection'] ) ) ? $global_skope_settings['collection'] : array();
$collection = array_merge( $local_collection, $global_collection );
}
foreach ( $collection as $level_data ) {
// stop here and return if a match was recursively found
if ( 'no_match' !== $_parent_level_data )
break;
if ( array_key_exists( 'collection', $level_data ) && is_array( $level_data['collection'] ) ) {
foreach ( $level_data['collection'] as $child_level_data ) {
if ( array_key_exists( 'id', $child_level_data ) && $child_level_id == $child_level_data['id'] ) {
$_parent_level_data = $level_data;
//match found, break this loop
break;
} else {
$_parent_level_data = sek_get_parent_level_model( $child_level_id, $level_data['collection'], $skope_id );
}
}
}
}
return $_parent_level_data;
}
// Return the skope id in which a level will be rendered
// For that, walk the collections local and global to see if there's a match
// Fallback skope is local.
// used for example in the simple form module to print the hidden skope id, needed on submission.
// Recursive helper
// @param id : mandatory
// @param collection : optional <= that's why if missing we must walk all collections : local and global
function sek_get_level_skope_id( $level_id = '' ) {
$level_skope_id = skp_get_skope_id();
if ( !is_string( $level_id ) || empty( $level_id ) ) {
sek_error_log( __FUNCTION__ . ' => missing or invalid child_level_id param.');
return $level_skope_id;
}
$local_skope_settings = sek_get_skoped_seks( $level_skope_id );
$local_collection = ( is_array( $local_skope_settings ) && !empty( $local_skope_settings['collection'] ) ) ? $local_skope_settings['collection'] : array();
// if the level id has not been found in the local sections, we know it's a global level.
// In dev mode, always make sure that the level id is found in the global locations.
if ( 'no_match' === sek_get_level_model( $level_id, $local_collection ) ) {
$level_skope_id = NIMBLE_GLOBAL_SKOPE_ID;
if ( sek_is_dev_mode() ) {
$global_skope_settings = sek_get_skoped_seks( NIMBLE_GLOBAL_SKOPE_ID );
$global_collection = ( is_array( $global_skope_settings ) && !empty( $global_skope_settings['collection'] ) ) ? $global_skope_settings['collection'] : array();
if ( 'no_match' === sek_get_level_model( $level_id, $global_collection ) ) {
sek_error_log( __FUNCTION__ . ' => warning, a level id ( ' . $level_id .' ) was not found in local and global sections.');
}
}
}
return $level_skope_id;
}
?>
@@ -0,0 +1,130 @@
<?php
// return bool
// count the number of global section created, no matter if they are header footer or other global locations
// can be used to determine if we need to render Nimble Builder assets on front. See ::sek_enqueue_front_assets()
function sek_has_global_sections() {
if ( skp_is_customizing() )
return true;
if ( 'not_set' !== Nimble_Manager()->page_has_global_sections )
return Nimble_Manager()->page_has_global_sections;
$maybe_global_sek_post = sek_get_seks_post( NIMBLE_GLOBAL_SKOPE_ID, 'global' );
$nb_section_created = 0;
if ( is_object($maybe_global_sek_post) ) {
$seks_data = maybe_unserialize($maybe_global_sek_post->post_content);
$seks_data = is_array( $seks_data ) ? $seks_data : array();
$nb_section_created = sek_count_not_empty_sections_in_page( $seks_data );
}
// cache now
Nimble_Manager()->page_has_global_sections = $nb_section_created > 0;
return Nimble_Manager()->page_has_global_sections;
}
// @return bool
// added for https://github.com/presscustomizr/nimble-builder/issues/436
// initially used to determine if a post or a page has been customized with Nimble Builder => if so, we add an edit link in the post/page list
// when used in admin, the skope_id must be provided
// can be used to determine if we need to render Nimble Builder assets on front. See ::sek_enqueue_front_assets()
// March 2021 => fixed : function sek_local_skope_has_nimble_sections() => when customzing => seks_data param should be provided after being filtered with customized values
function sek_local_skope_has_nimble_sections( $skope_id = '', $seks_data = null ) {
$skope_id = empty( $skope_id ) ? skp_get_skope_id() : $skope_id;
if ( NIMBLE_GLOBAL_SKOPE_ID === $skope_id ) {
sek_error_log( __FUNCTION__ . ' => error => function should not be used with global skope id' );
return false;
}
if ( 'not_set' !== Nimble_Manager()->page_has_local_sections )
return Nimble_Manager()->page_has_local_sections;
$nb_section_created = 0;
// When the collection is provided use it otherwise get it
if ( is_null($seks_data) || !is_array($seks_data) ) {
$seks_data = sek_get_skoped_seks( $skope_id );
}
if ( is_array( $seks_data ) ) {
$nb_section_created = sek_count_not_empty_sections_in_page( $seks_data );
}
// cache now
Nimble_Manager()->page_has_local_sections = $nb_section_created > 0;
return Nimble_Manager()->page_has_local_sections;
}
// @return boolean
// Indicates if a section level contains at least on module
// Used in SEK_Front_Render::render() to maybe print a css class on the section level
function sek_section_has_modules( $model, $has_module = null ) {
$has_module = is_null( $has_module ) ? false : (bool)$has_module;
foreach ( $model as $level_data ) {
// stop here and return if a match was recursively found
if ( true === $has_module )
break;
if ( is_array( $level_data ) && array_key_exists( 'collection', $level_data ) && is_array( $level_data['collection'] ) ) {
foreach ( $level_data['collection'] as $child_level_data ) {
if ( 'module'== $child_level_data['level'] ) {
$has_module = true;
//match found, break this loop
break;
} else {
$has_module = sek_section_has_modules( $child_level_data, $has_module );
}
}
}
}
return $has_module;
}
/* ------------------------------------------------------------------------- *
* HAS USER STARTED CREATING SECTIONS ?
/* ------------------------------------------------------------------------- */
// @return a boolean
// Used to check if we should render the welcome notice in sek_render_welcome_notice()
function sek_site_has_nimble_sections_created() {
$sek_post_query_vars = array(
'post_type' => NIMBLE_CPT,
'post_status' => get_post_stati(),
//'name' => sanitize_title(),
'posts_per_page' => -1,
'no_found_rows' => true,
'cache_results' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'lazy_load_term_meta' => false,
);
$query = new \WP_Query( $sek_post_query_vars );
//sek_error_log('DO WE HAVE SECTIONS ?', $query );
return is_array( $query->posts ) && !empty( $query->posts );
}
// recursive helper to count the number of sections in a given set of sections data
function sek_count_not_empty_sections_in_page( $seks_data, $count = 0 ) {
if ( !is_array( $seks_data ) ) {
sek_error_log( __FUNCTION__ . ' => invalid seks_data param');
return $count;
}
foreach ( $seks_data as $key => $data ) {
if ( is_array( $data ) ) {
if ( !empty( $data['level'] ) && 'section' === $data['level'] ) {
if ( !empty( $data['collection'] ) ) {
$count++;
}
} else {
$count = sek_count_not_empty_sections_in_page( $data, $count );
}
}
}
return $count;
}
?>
@@ -0,0 +1,91 @@
<?php
// /* ------------------------------------------------------------------------- *
// * FEEDBACK NOTIF
// /* ------------------------------------------------------------------------- */
// Invoked when printing the review note in the plugin table, in the 'plugin_row_meta'
// Since this is a quite heavy check, NB stores it in a 7 days long transient
function sek_get_feedback_notif_status() {
if ( sek_feedback_notice_is_dismissed() )
return;
// Check if we already stored the status in a transient first
$transient_name = NIMBLE_FEEDBACK_STATUS_TRANSIENT_ID;
$transient_value = get_transient( $transient_name );
if ( false != $transient_value ) {
return $transient_value;
}
// If transient not set or expired, let's set it and return the feedback status
// $start_version = get_option( 'nimble_started_with_version', NIMBLE_VERSION );
// Bail if user started after v2.1.20, October 22nd 2020 ( set on November 23th 2020 )
// if ( !version_compare( $start_version, '3.1.12', '<=' ) )
// return;
$sek_post_query_vars = array(
'post_type' => NIMBLE_CPT,
'post_status' => get_post_stati(),
//'name' => sanitize_title(),
'posts_per_page' => -1,
'no_found_rows' => true,
'cache_results' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'lazy_load_term_meta' => false,
);
$query = new \WP_Query( $sek_post_query_vars );
if ( !is_array( $query->posts ) || empty( $query->posts ) )
return;
$customized_pages = 0;
$nb_section_created = 0;
// the global var is easier to handle for array when populated recursively
global $modules_used;
$module_used = array();
foreach ( $query->posts as $post_object ) {
$seks_data = maybe_unserialize($post_object->post_content);
$seks_data = is_array( $seks_data ) ? $seks_data : array();
$nb_section_created += sek_count_not_empty_sections_in_page( $seks_data );
sek_populate_list_of_modules_used( $seks_data );
$customized_pages++;
}
if ( !is_array( $modules_used ) || !is_numeric( $nb_section_created ) || !is_numeric($customized_pages) )
return;
$modules_used = array_unique($modules_used);
$transient_value = 'not_eligible';
// sek_error_log('$section_created ??', $nb_section_created );
// sek_error_log('$modules_used ?? ' . count($modules_used), $modules_used );
// sek_error_log('$customized_pages ??', $customized_pages );
//version_compare( $this->wp_version, '4.1', '>=' )
if ( $customized_pages > 1 && $nb_section_created > 1 && count($modules_used) > 1 ) {
$transient_value = 'eligible';
}
set_transient( $transient_name, $transient_value, 7 * DAY_IN_SECONDS );
return $transient_value;
}
// recursive helper to generate a list of module used in a given set of sections data
function sek_populate_list_of_modules_used( $seks_data ) {
global $modules_used;
if ( !is_array( $seks_data ) ) {
sek_error_log( __FUNCTION__ . ' => invalid seks_data param');
return $count;
}
foreach ( $seks_data as $key => $data ) {
if ( is_array( $data ) ) {
if ( !empty( $data['level'] ) && 'module' === $data['level'] && !empty( $data['module_type'] ) ) {
$modules_used[] = $data['module_type'];
} else {
//$modules_used = array_merge( $modules_used, sek_populate_list_of_modules_used( $data, $modules_used ) );
sek_populate_list_of_modules_used( $data, $modules_used );
}
}
}
}
?>
@@ -0,0 +1,78 @@
<?php
/* ------------------------------------------------------------------------- *
* reCAPTCHA HELPER
/* ------------------------------------------------------------------------- */
// @return boolean
// reCaptcha is enabled globally
// deactivated when customizing
function sek_is_recaptcha_globally_enabled() {
if ( did_action('nimble_front_classes_ready') && '_not_cached_yet_' !== Nimble_Manager()->recaptcha_enabled ) {
return Nimble_Manager()->recaptcha_enabled;
}
$recaptcha_enabled = false;
$glob_recaptcha_opts = sek_get_global_option_value( 'recaptcha' );
if ( !is_null( $glob_recaptcha_opts ) && is_array( $glob_recaptcha_opts ) && !empty( $glob_recaptcha_opts['enable'] ) ) {
$recaptcha_enabled = sek_booleanize_checkbox_val( $glob_recaptcha_opts['enable'] ) && !empty( $glob_recaptcha_opts['public_key'] ) && !empty($glob_recaptcha_opts['private_key'] );
}
// CACHE when not doing ajax
if ( !defined( 'DOING_AJAX') || true !== DOING_AJAX ) {
Nimble_Manager()->recaptcha_enabled = $recaptcha_enabled;
}
return $recaptcha_enabled;
}
// @return boolean
// reCaptcha is enabled globally
// deactivated when customizing
function sek_is_recaptcha_badge_globally_displayed() {
if ( did_action('nimble_front_classes_ready') && '_not_cached_yet_' !== Nimble_Manager()->recaptcha_badge_displayed ) {
return Nimble_Manager()->recaptcha_badge_displayed;
}
$display_badge = false;//disabled by default @see sek_get_module_params_for_sek_global_recaptcha()
$glob_recaptcha_opts = sek_get_global_option_value( 'recaptcha' );
if ( !is_null( $glob_recaptcha_opts ) && is_array( $glob_recaptcha_opts ) && !empty( $glob_recaptcha_opts['badge'] ) ) {
$display_badge = sek_booleanize_checkbox_val( $glob_recaptcha_opts['badge'] ) && sek_is_recaptcha_globally_enabled();
}
// CACHE when not doing ajax
if ( !defined( 'DOING_AJAX') || true !== DOING_AJAX ) {
Nimble_Manager()->recaptcha_badge_displayed = $display_badge;
}
return $display_badge;
}
// @return bool
// used to print reCaptcha js for the form module
function sek_front_sections_include_a_form( $bool = false, $recursive_data = null ) {
if ( !$bool ) {
if ( is_null( $recursive_data ) ) {
$local_skope_settings = sek_get_skoped_seks( skp_get_skope_id() );
$local_collection = ( is_array( $local_skope_settings ) && !empty( $local_skope_settings['collection'] ) ) ? $local_skope_settings['collection'] : array();
$global_skope_settings = sek_get_skoped_seks( NIMBLE_GLOBAL_SKOPE_ID );
$global_collection = ( is_array( $global_skope_settings ) && !empty( $global_skope_settings['collection'] ) ) ? $global_skope_settings['collection'] : array();
$recursive_data = array_merge( $local_collection, $global_collection );
}
foreach ($recursive_data as $key => $value) {
if ( is_array( $value ) && array_key_exists('module_type', $value) && 'czr_simple_form_module' === $value['module_type'] ) {
$bool = true;
break;
} else if ( is_array( $value ) ) {
$bool = sek_front_sections_include_a_form( $bool, $value );
}
}
}
return $bool;
}
?>
@@ -0,0 +1,375 @@
<?php
// /* ------------------------------------------------------------------------- *
// * NIMBLE API
// /* ------------------------------------------------------------------------- */
// Nimble api returns a set of value structured as follow
// return array(
// 'timestamp' => time(),
// 'library' => array(
// 'sections' => array(
// 'registration_params' => sek_get_sections_registration_params(),
// 'json_collection' => sek_get_json_collection()
// ),
// 'templates' => array()
// ),
// 'latest_posts' => $post_data,
// 'cta' => array( 'started_before' => $go_pro_if_started_before, 'html' => $go_pro_html )
// // 'testtest' => $_GET,
// // 'testreferer' => $_SERVER => to get the
// );
// @return array|false Info data, or false.
// api data is refreshed on plugin update and theme switch
// @$what param can be 'latest_posts_and_start_msg', 'templates', 'single_section'
function sek_get_nimble_api_data( $params ) {
$params = is_array($params) ? $params : [];
$params = wp_parse_args( $params, [
'what' => '',
'tmpl_name' => '',
'section_id' => '',
'force_update' => false
]);
$what = $params['what'];
$tmpl_name = $params['tmpl_name'];
$section_id = $params['section_id'];
$force_update = $params['force_update'];
$wp_cache_key = 'nimble_api_data_'. $what . $tmpl_name . $section_id;
// We must have a "what"
if ( is_null($what) || !is_string($what) ) {
sek_error_log( __FUNCTION__ . ' => error => $what param not set');
return false;
}
// If a single template is requested, a valid template name must be provided
if ( 'single_tmpl' === $what && ( empty($tmpl_name) || !is_string($tmpl_name) ) ) {
sek_error_log( __FUNCTION__ . ' => error => invalid $tmpl_name param');
return false;
}
// If a single section is requested, a valid section id must be provided
if ( 'single_section' === $what && ( empty($section_id) || !is_string($section_id) ) ) {
sek_error_log( __FUNCTION__ . ' => error => invalid $section_id param');
return false;
}
$cached_api_data = wp_cache_get( $wp_cache_key );
if ( $cached_api_data && is_array($cached_api_data) && !empty($cached_api_data) ) {
return $cached_api_data;
}
$transient_name = '';
$transient_duration = 7 * DAY_IN_SECONDS;
switch ( $what ) {
case 'latest_posts_and_start_msg':
$transient_name = 'nimble_api_posts';
$transient_duration = 7 * DAY_IN_SECONDS;
break;
case 'all_tmpl':
$transient_name = 'nimble_api_all_tmpl';
$transient_duration = 5 * DAY_IN_SECONDS;
break;
case 'single_tmpl':
$transient_name = 'nimble_api_tmpl_' . $tmpl_name;
$transient_duration = 2 * DAY_IN_SECONDS;
break;
case 'single_section':
$transient_name = 'nimble_api_section_' . $section_id;
break;
default:
sek_error_log( __FUNCTION__ . ' => error => invalid $what param => ' . $what );
break;
}
if ( empty( $transient_name ) ) {
return false;
}
$theme_slug = sek_get_parent_theme_slug();
$version_transient_value = get_transient( NIMBLE_API_CHECK_TRANSIENT_ID );
$expected_version_transient_value = NIMBLE_VERSION . '_' . $theme_slug;
$api_needs_update = $version_transient_value != $expected_version_transient_value;
$api_transient_data = maybe_unserialize( get_transient( $transient_name ) );
// set this constant in wp_config.php
$force_update = ( defined( 'NIMBLE_FORCE_UPDATE_API_DATA') && NIMBLE_FORCE_UPDATE_API_DATA ) ? true : $force_update;
if ( true === $force_update ) {
sek_error_log( __FUNCTION__ . ' API is in force update mode. API data requested => ' . $transient_name );
}
$api_data = $api_transient_data;
$invalid_transient_data = false;
// When requesting a single_section with sek_api_get_single_section_data, the expected returned data are formed like
// [
// [timestamp] => 1621256718
// [single_section] => []
// ]
// When requesting a single_tmpl with sek_get_single_tmpl_api_data, the expected returned data are formed like
// [
// [timestamp] => 1621256718
// [single_tmpl] => []
// ]
// If a problem occured when getting a pro section or template, single_section or single_tmpl is a string, not an array
// in this case, we need to re-connect to the api
// see https://github.com/presscustomizr/nimble-builder-pro/issues/193
if ( 'single_section' === $what && is_array( $api_data ) && array_key_exists('single_section', $api_data ) && !is_array($api_data['single_section'] ) ) {
$invalid_transient_data = true;
}
if ( 'single_tmpl' === $what && is_array( $api_data ) && array_key_exists('single_tmpl', $api_data ) && !is_array($api_data['single_tmpl'] ) ) {
$invalid_transient_data = true;
}
// Connect to remote NB api when :
// 1) api data transient is not set or has expired ( false === $api_transient_data )
// 2) force_update param is true
// 3) NB has been updated to a new version ( $api_needs_update case )
// 4) Theme has been changed ( $api_needs_update case )
// 5) API DATA is not an array ( for https://github.com/presscustomizr/nimble-builder-pro/issues/193 )
// 6) Invalid transient data ( for https://github.com/presscustomizr/nimble-builder-pro/issues/193 )
if ( $force_update || false === $api_data || !is_array($api_data) || $api_needs_update || $invalid_transient_data ) {
$query_params = apply_filters( 'nimble_api_query_params', [
'timeout' => ( $force_update ) ? 25 : 8,
'body' => [
'api_version' => NIMBLE_VERSION,
'site_lang' => get_bloginfo( 'language' ),
'what' => $what,// 'single_tmpl', 'all_tmpl', 'latest_posts_and_start_msg', 'single_section'
'tmpl_name' => $tmpl_name,
'section_id' => $section_id
]
] );
//sek_error_log('CALL TO REMOTE API NOW FOR DATA => ' . $transient_name . ' | ' . $force_update . ' | ' . $api_needs_update, $query_params );
$response = wp_remote_get( NIMBLE_DATA_API_URL_V2, $query_params );
if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
// set the transient to '_api_error_', so that we don't hammer the api if not reachable. next call will be done after transient expiration
$api_data = '_api_error_';
sek_error_log( __FUNCTION__ . ' error with api response');
}
$api_data = json_decode( wp_remote_retrieve_body( $response ), true );
if ( empty( $api_data ) || !is_array( $api_data ) ) {
sek_error_log( __FUNCTION__ . ' invalid api data after json decode', $api_data );
// set the transient to '_api_error_', so that we don't hammer the api if not reachable. next call will be done after transient expiration
$api_data = '_api_error_';
}
// When requesting a single_section with sek_api_get_single_section_data, the expected returned data are formed like
// [
// [timestamp] => 1621256718
// [single_section] => []
// ]
// When requesting a single_tmpl with sek_get_single_tmpl_api_data, the expected returned data are formed like
// [
// [timestamp] => 1621256718
// [single_tmpl] => []
// ]
// If a problem occured when getting a pro section or template, single_section or single_tmpl is a string, not an array
// in this case, we don't want to sage the api data like this as transient because user will need the transient to expire before getting the correct data ( see https://github.com/presscustomizr/nimble-builder-pro/issues/193 )
if ( 'single_section' === $what && array_key_exists('single_section', $api_data ) && !is_array($api_data['single_section'] ) ) {
sek_error_log( __FUNCTION__ . ' invalid single section api data', $api_data);
$api_data = '_api_error_';
}
if ( 'single_tmpl' === $what && array_key_exists('single_tmpl', $api_data ) && !is_array($api_data['single_tmpl'] ) ) {
sek_error_log( __FUNCTION__ . ' invalid single tmpl api data', $api_data);
$api_data = '_api_error_';
}
// if the api could not be reached, let's retry in 2 minutes with a short transient duration
set_transient( $transient_name, $api_data, '_api_error_' === $api_data ? 2 * MINUTE_IN_SECONDS : $transient_duration );
// The api data will be refreshed on next plugin update, or next theme switch. Or if $transient_name has expired.
// $expected_version_transient_value = NIMBLE_VERSION . '_' . $theme_slug;
set_transient( NIMBLE_API_CHECK_TRANSIENT_ID, $expected_version_transient_value, 100 * DAY_IN_SECONDS );
}//if ( $force_update || false === $api_data )
// if api_error a new api call will be done when the relevant transient will expire
if ( '_api_error_' === $api_data ) {
sek_error_log( __FUNCTION__ . ' API data value is _api_error_ for transient data : ' . $transient_name );
}
$api_data = '_api_error_' === $api_data ? null : $api_data;
wp_cache_set( $wp_cache_key, $api_data );
//sek_error_log('API DATA for ' . $transient_name, $api_data );
return $api_data;
}
//////////////////////////////////////////////////
/// TEMPLATE DATA
function sek_get_all_tmpl_api_data( $force_update = false ) {
// set this constant in wp_config.php
$force_update = ( defined( 'NIMBLE_FORCE_UPDATE_API_DATA') && NIMBLE_FORCE_UPDATE_API_DATA ) ? true : $force_update;
// To avoid a possible refresh, hence a reconnection to the api when opening the customizer
// Let's use the data saved as options
// Those data are updated on plugin install, plugin update( upgrader_process_complete ), theme switch
// @see https://github.com/presscustomizr/nimble-builder/issues/441
$api_data = sek_get_nimble_api_data([
'what' => 'all_tmpl',
'force_update' => $force_update
]);
$api_data = is_array( $api_data ) ? $api_data : [];
//sek_error_log('TMPL DATA ?', $tmpl_data);
if ( empty($api_data) || !array_key_exists('lib', $api_data) || !is_array($api_data['lib']) || empty($api_data['lib']['templates']) || !is_array($api_data['lib']['templates']) ) {
sek_error_log( __FUNCTION__ . ' => error => no json_collection' );
return array();
}
//return [];
return maybe_unserialize( $api_data['lib']['templates'] );
}
function sek_get_single_tmpl_api_data( $tmpl_name, $is_pro_tmpl = false, $force_update = false ) {
// set this constant in wp_config.php
$force_update = ( defined( 'NIMBLE_FORCE_UPDATE_API_DATA') && NIMBLE_FORCE_UPDATE_API_DATA ) ? true : $force_update;
// To avoid a possible refresh, hence a reconnection to the api when opening the customizer
// Let's use the data saved as options
// Those data are updated on plugin install, plugin update( upgrader_process_complete ), theme switch
// @see https://github.com/presscustomizr/nimble-builder/issues/441
$api_data = sek_get_nimble_api_data([
'what' => 'single_tmpl',
'tmpl_name' => $tmpl_name,
'force_update' => $force_update
]);
// The api should return an array
if ( !is_array( $api_data ) || !array_key_exists( 'single_tmpl', $api_data ) ) {
return __('Problem when fetching template');
}
// If the api returned a pro license key problem, bail now and return the api string message
if ( $is_pro_tmpl && is_string( $api_data['single_tmpl'] ) ) {
return $api_data['single_tmpl'];
}
$api_data = wp_parse_args( $api_data, [
'timestamp' => '',
'single_tmpl' => null
]);
//sek_error_log('TMPL DATA ?', $tmpl_data);
if ( empty($api_data['single_tmpl']) ) {
sek_error_log( __FUNCTION__ . ' => error => empty template for ' . $tmpl_name );
return array();
}
if ( !is_array( $api_data['single_tmpl'] ) ) {
sek_error_log( __FUNCTION__ . ' => invalid template for ' . $tmpl_name );
return array();
}
if ( !array_key_exists( 'data', $api_data['single_tmpl'] ) || !array_key_exists( 'metas',$api_data['single_tmpl'] ) ) {
sek_error_log( __FUNCTION__ . ' => error => invalid template data for ' . $tmpl_name );
return array();
}
//return [];
return maybe_unserialize( $api_data['single_tmpl'] );
}
//////////////////////////////////////////////////
/// SINGLE PRESET SECTION DATA
function sek_api_get_single_section_data( $api_section_id, $force_update = false ) {
// set this constant in wp_config.php
$force_update = ( defined( 'NIMBLE_FORCE_UPDATE_API_DATA') && NIMBLE_FORCE_UPDATE_API_DATA ) ? true : $force_update;
// To avoid a possible refresh, hence a reconnection to the api when opening the customizer
// Let's use the data saved as options
// Those data are updated on plugin install, plugin update( upgrader_process_complete ), theme switch
// @see https://github.com/presscustomizr/nimble-builder/issues/441
$api_data = sek_get_nimble_api_data([
'what' => 'single_section',
'section_id' => $api_section_id,
'force_update' => $force_update
]);
$api_data = is_array( $api_data ) ? $api_data : [];
$api_data = wp_parse_args( $api_data, [
'timestamp' => '',
'single_section' => null
]);
//sek_error_log('SECTION DATA ?', $api_data);
if ( empty($api_data['single_section']) ) {
sek_error_log( __FUNCTION__ . ' => error => empty section data for ' . $api_section_id );
return array();
}
// if ( !array_key_exists( 'data', $api_data['single_tmpl'] ) || !array_key_exists( 'metas',$api_data['single_tmpl'] ) ) {
// sek_error_log( __FUNCTION__ . ' => error => invalid section data for ' . $api_section_id );
// return array();
// }
//return [];
return maybe_unserialize( $api_data['single_section'] );
}
//////////////////////////////////////////////////
/// LATESTS POSTS
// @return array of posts
function sek_get_latest_posts_api_data( $force_update = false ) {
// set this constant in wp_config.php
$force_update = ( defined( 'NIMBLE_FORCE_UPDATE_API_DATA') && NIMBLE_FORCE_UPDATE_API_DATA ) ? true : $force_update;
$api_data = sek_get_nimble_api_data([
'what' => 'latest_posts_and_start_msg',
'force_update' => $force_update
]);
$api_data = is_array( $api_data ) ? $api_data : [];
$api_data = wp_parse_args( $api_data, [
'timestamp' => '',
'latest_posts' => null
]);
if ( !is_array( $api_data['latest_posts'] ) || empty( $api_data['latest_posts'] ) ) {
sek_error_log( __FUNCTION__ . ' => error => no latest_posts' );
return [];
}
return $api_data['latest_posts'];
}
// @return html string
function sek_start_msg_from_api( $theme_name, $force_update = false ) {
if ( !sek_is_presscustomizr_theme( $theme_name ) ) {
return '';
}
// set this constant in wp_config.php
$force_update = ( defined( 'NIMBLE_FORCE_UPDATE_API_DATA') && NIMBLE_FORCE_UPDATE_API_DATA ) ? true : $force_update;
$api_data = sek_get_nimble_api_data( [
'what' => 'latest_posts_and_start_msg',
'force_update' => $force_update
]);
$api_data = is_array( $api_data ) ? $api_data : [];
$api_data = wp_parse_args( $api_data, [
'timestamp' => '',
'start_msg' => null
]);
$msg = '';
$api_msg = isset( $api_data['start_msg'] ) ? $api_data['start_msg'] : null;
if ( !is_null($api_msg) && is_string($api_msg) ) {
$msg = $api_msg;
}
return $msg;
}
// Attempt to refresh the api template data => will store in a transient if not done yet, to make it faster to render in the customizer
// add_action( 'wp_head', '\Nimble\sek_maybe_refresh_nimble_api_tmpl_data');
// function sek_maybe_refresh_nimble_api_tmpl_data() {
// if ( skp_is_customizing() || false !== get_transient( 'nimble_api_all_tmpl' ) )
// return;
// sek_get_nimble_api_data(['what' => 'all_tmpl']);
// }
?>
@@ -0,0 +1,249 @@
<?php
// This file has been introduced on May 21st 2019 => back to the local data
// after problem was reported when fetching data remotely : https://github.com/presscustomizr/nimble-builder/issues/445
/////////////////////////////////////////////////////////////
// REGISTRATION PARAMS FOR PRESET SECTIONS
// @return array()
function sek_get_sections_registration_params( $force_update = false ) {
// JULY 2020 => not stored in a transient anymore. For https://github.com/presscustomizr/nimble-builder/issues/730
// + clean previously created transients
$bw_fixes_options = get_option( NIMBLE_OPT_NAME_FOR_BACKWARD_FIXES );
$bw_fixes_options = is_array( $bw_fixes_options ) ? $bw_fixes_options : array();
if ( !array_key_exists('clean_section_params_transient_0720', $bw_fixes_options ) || 'done' != $bw_fixes_options['clean_section_params_transient_0720'] ) {
sek_clean_transients_like( 'section_params_transient' );
$bw_fixes_options['clean_section_params_transient_0720'] = 'done';
// flag as done
update_option( NIMBLE_OPT_NAME_FOR_BACKWARD_FIXES, $bw_fixes_options );
}
// $section_params_transient_name = 'section_params_transient_' . NIMBLE_VERSION;
// $registration_params = get_transient( $section_params_transient_name );
// // Refresh every 30 days, unless force_update set to true
// if ( $force_update || false === $registration_params ) {
// $registration_params = sek_get_raw_section_registration_params();
// set_transient( $section_params_transient_name, $registration_params, 30 * DAY_IN_SECONDS );
// }
$registration_params = sek_get_raw_section_registration_params();
return $registration_params;
}
function sek_get_raw_section_registration_params() {
return apply_filters( 'sek_get_raw_section_registration_params', [
'sek_intro_sec_picker_module' => [
'name' => __('Sections for an introduction', 'text_doma'),
'section_collection' => array(
array(
'content-id' => 'intro_three',
'title' => __('1 columns, call to action, full-width background', 'text-domain' ),
'thumb' => 'intro_three.jpg',
'demo_url' => '#intro-one'
),
array(
'content-id' => 'intro_one',
'title' => __('1 column, full-width background', 'text-domain' ),
'thumb' => 'intro_one.jpg',
'demo_url' => '#intro-two'
),
array(
'content-id' => 'intro_two',
'title' => __('2 columns, call to action, full-width background', 'text-domain' ),
'thumb' => 'intro_two.jpg',
'demo_url' => '#intro-three'
),
array(
'content-id' => 'pro_intro_two',
'title' => __('3 columns, call to actions', 'text-domain' ),
'thumb' => 'pro_intro_two.jpg',
'active' => sek_is_pro(),
'is_pro' => true,
'demo_url' => 'https://nimblebuilder.com/special-image-demo?utm_source=usersite&utm_medium=link&utm_campaign=section_demos'
),
array(
'content-id' => 'pro_intro_one',
'title' => __('2 columns, call to actions, image carousel', 'text-domain' ),
'thumb' => 'pro_intro_one.jpg',
'active' => sek_is_pro(),
'is_pro' => true,
'demo_url' => '#intro-four'
)
)
],
'sek_post_grids_sec_picker_module' => [
'name' => __('Post lists sections', 'text_doma'),
'section_collection' => array(
array(
'content-id' => 'grid_one',
'title' => __('Simple post grid', 'text-domain' ),
'thumb' => 'grid_one.jpg',
'demo_url' => 'https://nimblebuilder.com/post-grid-sections?utm_source=usersite&utm_medium=link&utm_campaign=section_demos#grid-one'
//'height' => '188px'
),
array(
'content-id' => 'grid_two',
'title' => __('Posts on two columns', 'text-domain' ),
'thumb' => 'grid_two.jpg',
'demo_url' => 'https://nimblebuilder.com/post-grid-sections?utm_source=usersite&utm_medium=link&utm_campaign=section_demos#grid-two'
//'height' => '188px'
),
array(
'content-id' => 'pro_grid_one',
'title' => __('Masonry post grid', 'text-domain' ),
'thumb' => 'pro_grid_one.jpg',
'demo_url' => 'https://nimblebuilder.com/post-grid-sections?utm_source=usersite&utm_medium=link&utm_campaign=section_demos#pro-grid-one',
'active' => sek_is_pro(),
'is_pro' => true
//'height' => '188px'
)
)
],
'sek_features_sec_picker_module' => [
'name' => __('Sections for services and features', 'text_doma'),
'section_collection' => array(
array(
'content-id' => 'features_one',
'title' => __('3 columns with icon and call to action', 'text-domain' ),
'thumb' => 'features_one.jpg',
'demo_url' => '#service-one'
//'height' => '188px'
),
array(
'content-id' => 'features_two',
'title' => __('3 columns with icon', 'text-domain' ),
'thumb' => 'features_two.jpg',
'demo_url' => '#service-two'
//'height' => '188px'
)
)
],
'sek_about_sec_picker_module' => [
'name' => __('About us sections', 'text_doma'),
'section_collection' => array(
array(
'content-id' => 'about_one',
'title' => __('A simple about us section with 2 columns', 'text-domain' ),
'thumb' => 'about_one.jpg',
'demo_url' => '#about-one'
//'height' => '188px'
)
)
],
'sek_contact_sec_picker_module' => [
'name' => __('Contact-us sections', 'text_doma'),
'section_collection' => array(
array(
'content-id' => 'contact_one',
'title' => __('A contact form and a Google map', 'text-domain' ),
'thumb' => 'contact_one.jpg',
'demo_url' => '#contact-one'
//'height' => '188px'
),
array(
'content-id' => 'contact_two',
'title' => __('A contact form with an image background', 'text-domain' ),
'thumb' => 'contact_two.jpg',
'demo_url' => '#contact-two'
//'height' => '188px'
)
)
],
'sek_team_sec_picker_module' => [
'name' => __('Sections for teams', 'text_doma'),
'section_collection' => array(
array(
'content-id' => 'team_one',
'title' => __('4 column', 'text-domain' ),
'thumb' => 'team_one.jpg',
'demo_url' => '#team-one'
),
array(
'content-id' => 'team_two',
'title' => __('3 columns', 'text-domain' ),
'thumb' => 'team_two.jpg',
'height' => '180px',
'demo_url' => '#team-two'
),
array(
'content-id' => 'pro_team_one',
'title' => __('3 columns, call to action', 'text-domain' ),
'thumb' => 'pro_team_one.jpg',
'active' => sek_is_pro(),
'height' => '180px',
'is_pro' => true,
'demo_url' => '#team-three'
)
)
],
'sek_column_layouts_sec_picker_module' => [
'name' => __('Empty sections with columns layout', 'text_doma'),
'section_collection' => array(
array(
'content-id' => 'two_columns',
'title' => __('two columns layout', 'text-domain' ),
'thumb' => 'two_columns.jpg'
),
array(
'content-id' => 'three_columns',
'title' => __('three columns layout', 'text-domain' ),
'thumb' => 'three_columns.jpg'
),
array(
'content-id' => 'four_columns',
'title' => __('four columns layout', 'text-domain' ),
'thumb' => 'four_columns.jpg'
),
)
],
// pre-built sections for header and footer
'sek_header_sec_picker_module' => [
'name' => __('Header sections', 'text_doma'),
'section_collection' => array(
array(
'content-id' => 'header_one',
'title' => __('simple header with a logo on the left and a menu on the right', 'text-domain' ),
'thumb' => 'header_one.jpg',
'height' => '33px',
'section_type' => 'header'
),
array(
'content-id' => 'header_two',
'title' => __('simple header with a logo on the right and a menu on the left', 'text-domain' ),
'thumb' => 'header_two.jpg',
'height' => '33px',
'section_type' => 'header'
)
)
],
'sek_footer_sec_picker_module' => [
'name' => __('Footer sections', 'text_doma'),
'section_collection' => array(
array(
'content-id' => 'footer_pro_one',
'title' => __('simple 2 columns footer', 'text-domain' ),
'thumb' => 'footer_pro_one.jpg',
'section_type' => 'footer',
'height' => '75px',
'active' => sek_is_pro(),
'is_pro' => true
),
array(
'content-id' => 'footer_with_social_links_one',
'title' => __('footer with dynamic date, site title and social links', 'text-domain' ),
'thumb' => 'footer_with_social_links_one.jpg',
'section_type' => 'footer',
'height' => '51px'
),
array(
'content-id' => 'footer_one',
'title' => __('simple 3 columns footer', 'text-domain' ),
'thumb' => 'footer_one.jpg',
'section_type' => 'footer',
'height' => '75px'
)
)
]
]);
}
?>

Some files were not shown because too many files have changed in this diff Show More