File manager - Edit - /home/matthif/www/wp-content/languages/controls.tar
Back
simple_upsell_section.php 0000666 00000003205 15226760543 0011674 0 ustar 00 <?php /** * Simple upsell customizer section. * * @package Neve */ namespace Neve\Customizer\Controls; /** * Customizer section. * * @since 2.8.3 * @see WP_Customize_Section */ class Simple_Upsell_Section extends \WP_Customize_Section { /** * Type of this section. * * @var string */ public $type = 'nv_simple_upsell_section'; /** * Button text. * * @var string */ public $button_text = ''; /** * Button link. * * @var string */ public $link = ''; /** * List of features. * * @var string */ public $text = ''; /** * Screen reader text. * * @var string */ public $screen_reader = ''; /** * Gather the parameters passed to client JavaScript via JSON. * * @return array The array to be exported to the client as JSON. */ public function json() { $json = parent::json(); $json['button_text'] = $this->button_text; $json['link'] = $this->link; $json['text'] = $this->text; $json['screen_reader'] = __( '(opens in a new tab)', 'neve' ); return $json; } /** * Render template. */ protected function render_template() { ?> <li id="accordion-section-{{ data.id }}" class="control-section-{{ data.type }}"> <div class="nv-simple-upsell"> <# if( data.text ) { #> <p>{{data.text}}</p> <# } #> <# if( data.link && data.button_text ) { #> <a rel="external noreferrer noopener" target="_blank" href="{{data.link}}" class='button button-secondary'> {{data.button_text}} <span class="components-visually-hidden">{{data.screen_reader}}</span> </a> <# } #> </div> </li> <?php } } tabs.php 0000666 00000004153 15226760543 0006227 0 ustar 00 <?php /** * The tabs customize control extends the WP_Customize_Control class. This class allows * developers to create tabs and hide the sections' settings easily. * * @package Neve\Customizer\Controls * @since 1.1.45 * @author Andrei Baicus <andrei@themeisle.com> * @copyright Copyright (c) 2017, Themeisle * @link http://themeisle.com/ * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ namespace Neve\Customizer\Controls; /** * Radio image customize control. * * @since 1.1.45 * @access public */ class Tabs extends \WP_Customize_Control { /** * The type of customize control being rendered. * * @since 1.1.45 * @var string */ public $type = 'interface-tabs'; /** * The tabs with keys of the controls that are under each tab. * * @since 1.1.45 * @var array */ public $tabs; /** * Controls from tabs. * * @var array */ public $controls; /** * Add custom JSON parameters to use in the JS template. * * @return array */ public function json() { $json = parent::json(); $json['tabs'] = $this->tabs; $json['controls'] = $this->controls; return $json; } /** * Underscore JS template to handle the control's output. * * @return void */ public function content_template() { ?> <# if ( ! data.tabs ) { return; } #> <div class="neve-tabs-control" id=""> <# var i = 1; for( tab in data.tabs) { #> <# var allControlsInTabs = '' _.each( data.controls[tab], function( val, key ) { allControlsInTabs+= key + ' ' if(val){ var allvals = Object.keys(val).map(function(e) { return val[e] }); allvals = _.uniq(_.flatten(allvals)) allvals = allvals.join(' ') allControlsInTabs += allvals } }); #> <div class="neve-customizer-tab <# if( i === 1 ){#> active <#}#>" data-tab="{{tab}}"> <label class="{{allControlsInTabs}}"> <# if(data.tabs[tab]['icon']) { #> <i class="dashicons dashicons-{{data.tabs[tab]['icon']}}"></i> <# } #> {{data.tabs[tab]['label']}} </label> </div> <# i++;} #> </div> <?php } } ordering.php 0000666 00000006570 15226760543 0007114 0 ustar 00 <?php /** * Author: Andrei Baicus <andrei@themeisle.com> * Created on: 29/08/2018 * * @package Ordering.php */ namespace Neve\Customizer\Controls; /** * Class Ordering * * @package Neve\Customizer\Controls */ class Ordering extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'ordering'; /** * Orderable components. * * @var array */ private $components = array(); /** * Ordering constructor. * * @param \WP_Customize_Manager $manager Wp customize. * @param string $id control id. * @param array $args control args. */ public function __construct( \WP_Customize_Manager $manager, $id, array $args = array() ) { parent::__construct( $manager, $id, $args ); $this->components = $args['components'] ? $args['components'] : array(); $this->setup_components(); } /** * Get disabled components * Add them at the end of all components in the customizer */ private function setup_components() { $val = $this->value(); if ( ! is_string( $val ) ) { $val = '[]'; } $val = json_decode( $val, true ); if ( ! is_array( $val ) ) { $val = array(); } $enabled = array_combine( $val, $val ); $disabled = array_diff_assoc( $this->components, $enabled ); $this->components = array_merge( $enabled, $disabled ); } /** * Render content of control. */ public function render_content() { $this->render_control_label(); $this->render_sortable_list(); $this->render_collector_input(); } /** * Render title and description. * * @return void */ private function render_control_label() { if ( empty( $this->label ) && empty( $this->description ) ) { return; } echo '<label>'; if ( ! empty( $this->label ) ) { echo '<span class="customize-control-title">' . esc_html( $this->label ) . '</span>'; } if ( ! empty( $this->description ) ) { echo '<span class="description customize-control-description">' . wp_kses_post( $this->description ) . '</span>'; } echo '</label>'; } /** * Render sortable list. * * @return void */ private function render_sortable_list() { if ( empty( $this->components ) ) { return; } echo '<ul class="ti-order-sortable">'; foreach ( $this->components as $component => $name ) { if ( $component === $name ) { continue; } echo '<li class="ui-state-default order-component' . esc_attr( $this->get_component_status_class( $component ) ) . '" data-id="' . esc_attr( $component ) . '">'; echo '<span class="toggle-display"></span>'; echo '<p>' . esc_html( $name ) . '</p>'; echo '<span class="dashicons dashicons-menu drag"></span>'; echo '</li>'; } echo '</ul>'; } /** * Get the class for the component. (enabled/disabled) * * @param string $component the component to check. * * @return string */ private function get_component_status_class( $component ) { $value = $this->value(); if ( empty( $value ) ) { return ' enabled'; } $value = json_decode( $value, true ); if ( ! is_array( $value ) ) { $value = array(); } if ( ! in_array( $component, $value, true ) ) { return ''; } return ' enabled'; } /** * Render the collector input. * * @return void */ private function render_collector_input() { echo '<input type="hidden" class="ti-order-collector"' . wp_kses_post( $this->get_link() ) . '>'; } } button_group.php 0000666 00000003553 15226760543 0010030 0 ustar 00 <?php /** * Button group control. * * @package Neve\Customizer\Controls */ namespace Neve\Customizer\Controls; /** * Class Button_Group * * @package Neve\Customizer\Controls */ class Button_Group extends \WP_Customize_Control { /** * Render content for the control. */ public function render_content() { $this->render_control_header(); $name = 'nv_radio_' . $this->id; $input_id = 'nv_customize-input-' . $this->id; ?> <div class="nv-button-group"> <?php foreach ( $this->choices as $value => $icon_class ) { ?> <input id="<?php echo esc_attr( $input_id . '-radio-' . $value ); ?>" type="radio" value="<?php echo esc_attr( $value ); ?>" name="<?php echo esc_attr( $name ); ?>" <?php $this->link(); ?> <?php checked( $this->value(), $value ); ?> /> <label for="<?php echo esc_attr( $input_id . '-radio-' . $value ); ?>" class="button"> <i class="dashicons <?php echo esc_attr( $icon_class ); ?>"></i> </label> <?php } ?> </div> <?php } /** * Render control header. */ private function render_control_header() { if ( empty( $this->label ) && empty( $this->description ) ) { return; } ?> <div class="nv-button-group-header"> <?php if ( ! empty( $this->label ) ) { ?> <span class="customize-control-title"> <span><?php echo esc_html( $this->label ); ?></span> </span> <?php } if ( ! empty( $this->description ) ) { ?> <label class="nv-radio-description-info" for="<?php echo esc_attr( $this->id . '-description-toggle' ); ?>"> <i class="dashicons dashicons-info"></i> </label> <input id="<?php echo esc_attr( $this->id . '-description-toggle' ); ?>" type="checkbox" class="expand-description"> <span class="nv-radio-hidden-info"><?php echo esc_html( $this->description ); ?></span> <?php } ?> </div> <?php } } upsell_control.php 0000666 00000006430 15226760543 0010342 0 ustar 00 <?php /** * The upsell customize control extends the WP_Customize_Control class. * * @package Neve\Customizer\Controls * @since 2.3.10 * @copyright Copyright (c) 2017, Themeisle * @link http://themeisle.com/ * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ namespace Neve\Customizer\Controls; /** * Radio image customize control. * * @since 2.3.10 * @access public */ class Upsell_Control extends \WP_Customize_Control { /** * The type of customize control being rendered. * * @since 2.3.10 * @var string */ public $type = 'neve-control-upsell'; /** * Button text. * * @since 2.3.10 * @var string */ public $button_text = ''; /** * Button link. * * @since 2.3.10 * @var string */ public $button_url = ''; /** * List of features. * * @since 2.3.10 * @var array */ public $options = array(); /** * List of explained features. * * @since 2.3.10 * @var array */ public $explained_features = array(); /** * Label text for each feature. * * @since 2.3.10 * @var string */ public $pro_label = ''; /** * Screen reader text. * * @since 2.11.2 * @var string */ public $screen_reader = ''; /** * Boolean to check if the pro label is displayed or not. * * @since 2.3.10 * @var bool */ public $show_pro_label = true; /** * Constructor. * * @param \WP_Customize_Manager $manager Customizer manager. * @param string $id Control id. * @param array $args Argument. */ public function __construct( \WP_Customize_Manager $manager, $id, array $args ) { parent::__construct( $manager, $id, $args ); $this->pro_label = esc_html__( 'PRO', 'neve' ); } /** * Add custom JSON parameters to use in the JS template. * * @return array */ public function json() { $json = parent::json(); $json['button_text'] = $this->button_text; $json['button_url'] = $this->button_url; $json['options'] = $this->options; $json['explained_features'] = $this->explained_features; $json['show_pro_label'] = $this->show_pro_label; $json['pro_label'] = $this->pro_label; $json['screen_reader'] = $this->screen_reader; return $json; } /** * Underscore JS template to handle the control's output. * * @return void */ public function content_template() { ?> <div class="nv-upsell"> <# if ( data.options ) { #> <ul class="nv-upsell-features"> <# for (option in data.options) { #> <li> <# if( data.show_pro_label === true ) { #> <span class="upsell-pro-label">{{ data.pro_label }}</span> <# } #> {{ data.options[option] }} </li> <# } #> </ul> <# } #> <# if ( data.button_text && data.button_url ) { #> <a rel="external noreferrer noopener" target="_blank" href="{{ data.button_url }}" class="button button-primary">{{ data.button_text }} <span class="components-visually-hidden">{{ data.screen_reader }}</span> </a> <# } #> <# if ( data.explained_features.length > 0 ) { #> <hr> <ul class="nv-upsell-feature-list"> <# for (requirement in data.explained_features) { #> <li>* {{ data.explained_features[requirement] }}</li> <# } #> </ul> <# } #> </div> <?php } } react/upsell_section.php 0000666 00000002047 15226760543 0011424 0 ustar 00 <?php /** * Description Upsell Section * * Author: Bogdan Preda <bogdan.preda@themeisle.com> * Created on: 20-12-{2021} * * @package neve/neve-pro */ namespace Neve\Customizer\Controls\React; /** * Customizer section. * * @package WordPress * @subpackage Customize * @since 4.1.0 * @see WP_Customize_Section */ class Upsell_Section extends \WP_Customize_Section { /** * Type of this section. * * @var string */ public $type = 'neve_upsell'; /** * Upgrade URL. * * @var string */ public $url = ''; /** * Gather the parameters passed to client JavaScript via JSON. * * @return array The array to be exported to the client as JSON. * @since 4.1.0 */ public function json() { $json = parent::json(); $json['url'] = $this->url; return $json; } /** * Render template. */ protected function render_template() { ?> <li id="accordion-section-{{ data.id }}" data-slug="{{data.id}}" class="control-section control-section-{{ data.type }} neve-upsell"> </li> <?php } } react/conditional_selector.php 0000666 00000001753 15226760543 0012602 0 ustar 00 <?php /** * Color Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Button_Appearance * * @package Neve\Customizer\Controls\React */ class Conditional_Selector extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_context_conditional_selector'; /** * Additional arguments passed to JS. * * @var string */ public $default = ''; /** * Send to JS. */ public function json() { $json = parent::json(); $json['default'] = $this->default; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/button_appearance.php 0000666 00000002746 15226760543 0012074 0 ustar 00 <?php /** * Button_Appearance Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Button_Appearance * * @package Neve\Customizer\Controls\React */ class Button_Appearance extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_button_appearance'; /** * Additional arguments passed to JS. * Disables hover controls * * @var bool */ public $no_hover = false; /** * Additional arguments passed to JS. * Disables shadow controls * * @var bool */ public $no_shadow = false; /** * Additional arguments passed to JS. * Disables border radius, border width * * @var bool */ public $no_border = false; /** * Default values. * * @var array */ public $default_vals = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['no_hover'] = $this->no_hover; $json['no_shadow'] = $this->no_shadow; $json['no_border'] = $this->no_border; $json['defaultVals'] = $this->default_vals; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/ordering.php 0000666 00000002164 15226760543 0010205 0 ustar 00 <?php /** * Radio Image Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Ordering * * @package Neve\Customizer\Controls\React */ class Ordering extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_ordering_control'; /** * Additional arguments passed to JS. * * @var array */ public $components = []; /** * Additional arguments passed to JS. * * @var array */ public $default_order = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['components'] = $this->components; $json['defaultOrder'] = $this->default_order; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/nr_spacing.php 0000666 00000002411 15226760543 0010512 0 ustar 00 <?php /** * Non Responsive Spacing Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Spacing * * @package Neve\Customizer\Controls\React */ class Nr_Spacing extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_non_responsive_spacing'; /** * Min. * * @var int */ public $min = 0; /** * Max. * * @var int */ public $max = 300; /** * Units. * * @var array */ public $units = [ 'px', 'em', 'rem', '%' ]; /** * Default value. * * @var array */ public $default = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['min'] = $this->min; $json['max'] = $this->max; $json['units'] = $this->units; $json['defaultVal'] = $this->default; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/responsive_toggle.php 0000666 00000001774 15226760543 0012140 0 ustar 00 <?php /** * Responsive Toggle. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Button_Appearance * * @package Neve\Customizer\Controls\React */ class Responsive_Toggle extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_responsive_toggle_control'; /** * Additional arguments passed to JS. * * @var array */ public $excluded_devices = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['excluded'] = $this->excluded_devices; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/typography_extra_section.php 0000666 00000001114 15226760543 0013523 0 ustar 00 <?php /** * * @package Neve */ namespace Neve\Customizer\Controls\React; /** * Customizer section. * * @package WordPress * @subpackage Customize * @see WP_Customize_Section */ class Typography_Extra_Section extends \WP_Customize_Section { /** * Type of this section. * * @var string */ public $type = 'typography_extra_section'; /** * Render template. */ protected function render_template() { ?> <li id="accordion-section-{{ data.id }}" data-slug="{{data.id}}" class="control-section control-section-{{ data.type }}"> </li> <?php } } react/global_colors.php 0000666 00000002160 15226760543 0011211 0 ustar 00 <?php /** * Global_Colors Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Global_Colors * * @package Neve\Customizer\Controls\React */ class Global_Colors extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_global_colors'; /** * Default values. * * @var string */ public $default_values = ''; /** * Additional arguments passed to JS. * * @var array */ public $input_attrs = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['defaultValues'] = $this->default_values; $json['input_attrs'] = $this->input_attrs; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/form_token_field.php 0000666 00000001745 15226760543 0011706 0 ustar 00 <?php /** * Form Token Field Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Form_Token_Field * * @package Neve\Customizer\Controls\React */ class Form_Token_Field extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_form_token_field'; /** * Additional arguments passed to JS. * * @var array */ public $choices = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['choices'] = $this->choices; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/builder.php 0000666 00000002330 15226760543 0010015 0 ustar 00 <?php /** * Builders Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Customizer section. * * @package Neve\Customizer\Controls\React */ class Builder extends \WP_Customize_Control { /** * Type of this section. * * @var string */ public $type = 'neve_builder_control'; /** * Builder Type * * @var string */ public $builder_type = null; /** * Columns Layout * * @var boolean */ public $columns_layout = false; /** * Gather the parameters passed to client JavaScript via JSON. * * @return array The array to be exported to the client as JSON. */ public function json() { $json = parent::json(); $json['builderType'] = $this->builder_type; $json['columnsLayout'] = $this->columns_layout; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/background.php 0000666 00000001727 15226760543 0010517 0 ustar 00 <?php /** * Color Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Button_Appearance * * @package Neve\Customizer\Controls\React */ class Background extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_background_control'; /** * Additional arguments passed to JS. * * @var string */ public $default = ''; /** * Send to JS. */ public function json() { $json = parent::json(); $json['default'] = $this->default; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/multiselect.php 0000666 00000001726 15226760543 0010731 0 ustar 00 <?php /** * Multiselect Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Button_Appearance * * @package Neve\Customizer\Controls\React */ class Multiselect extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_multiselect'; /** * Additional arguments passed to JS. * * @var array */ public $choices = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['choices'] = $this->choices; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/builder_section.php 0000666 00000001752 15226760543 0011550 0 ustar 00 <?php /** * Header Footer Builder Section. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Customizer section. * * @package WordPress * @subpackage Customize * @since 4.1.0 * @see WP_Customize_Section */ class Builder_Section extends \WP_Customize_Section { /** * Type of this section. * * @var string */ public $type = 'neve_header_footer_builder_section'; /** * Default options schema. * * @var array */ public $default_options = [ 'setting' => '', 'builder_type' => '', // 'quickLinks' => [], ]; /** * Options passed to section. * * @var array */ public $options = []; /** * Gather the parameters passed to client JavaScript via JSON. * * @return array The array to be exported to the client as JSON. */ public function json() { $json = parent::json(); $json['options'] = wp_parse_args( $this->options, $this->default_options ); return $json; } } react/group_select.php 0000666 00000002124 15226760543 0011063 0 ustar 00 <?php /** * Group_Select Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Group_Select * * @package Neve\Customizer\Controls\React */ class Group_Select extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_group_select'; /** * Additional arguments passed to JS. * * @var array */ public $options = []; /** * Mark controls as disabled. * * @var bool */ public $disabled = false; /** * Send to JS. */ public function json() { $json = parent::json(); $json['options'] = $this->options; $json['disabled'] = $this->disabled; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/link_control.php 0000666 00000002652 15226760543 0011073 0 ustar 00 <?php /** * Author: Bogdan Preda <bogdan.preda@themeisle.com> * Created on: 2022-02-10 * * @package Neve */ namespace Neve\Customizer\Controls\React; /** * Customizer link control React. * * @package WordPress * @subpackage Customize * @since 4.1.0 * @see WP_Customize_Control */ class Link_Control extends \WP_Customize_Control { /** * Type of this control. * * @var string */ public $type = 'neve_link'; /** * Control URL for link. * * @var string */ public $url = '#'; /** * Control text for link. * * @var string */ public $label = 'Link'; /** * Control description for link. * * @var string */ public $description = ''; /** * Gather the parameters passed to client JavaScript via JSON. * * @since 4.1.0 * * @return array The array to be exported to the client as JSON. */ public function json() { $json = parent::json(); $json['url'] = $this->url; $json['label'] = $this->label; $json['description'] = $this->description; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/font_family.php 0000666 00000001756 15226760543 0010711 0 ustar 00 <?php /** * Font_Family Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Button_Appearance * * @package Neve\Customizer\Controls\React */ class Font_Family extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_font_family_control'; /** * Additional arguments passed to JS. * * @var array */ public $input_attrs = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['input_attrs'] = $this->input_attrs; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/textarea.php 0000666 00000001725 15226760543 0010213 0 ustar 00 <?php /** * Textarea Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Textarea * * @package Neve\Customizer\Controls\React */ class Textarea extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_textarea'; /** * Additional arguments passed to JS. * * @var array */ public $input_attrs = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['input_attrs'] = $this->input_attrs; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/heading.php 0000666 00000004632 15226760543 0007775 0 ustar 00 <?php /** * Heading Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Heading control for react */ class Heading extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_customizer_heading'; /** * Control class. * * @var string */ public $class = ''; /** * Should be accordion? * * @var bool */ public $accordion = false; /** * Initial state. * * @var bool */ public $expanded = true; /** * How many controls to wrap. * * @var int */ public $controls_to_wrap = 1; /** * Label before the accordion. * * @var string */ public $category_label = ''; /** * Send data to _s * * @return array */ public function json() { $json = parent::json(); $json['classes'] = $this->class; $json['accordion'] = $this->accordion; $json['categoryLabel'] = $this->category_label; if ( $this->accordion === true ) { $json['classes'] .= ' accordion'; } $json['style'] = $this->print_style(); return $json; } /** * Render the control. */ protected function render() { $id = 'customize-control-' . str_replace( array( '[', ']' ), array( '-', '' ), $this->id ); $class = 'customize-control customize-control-' . $this->type; $class .= ' ' . $this->class; if ( $this->accordion ) { $class .= ' accordion'; } if ( $this->expanded ) { $class .= ' expanded'; } echo '<li id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '">'; echo '</li>'; } /** * Print the style for the accordion. */ protected function print_style() { $style = ''; for ( $i = 1; $i <= $this->controls_to_wrap; $i ++ ) { $style .= '.accordion.' . $this->class . ':not(.expanded)'; for ( $j = 1; $j <= $i; $j ++ ) { $style .= ' + li'; } if ( $i !== $this->controls_to_wrap ) { $style .= ','; } } $style .= '{max-height: 0;opacity: 0;margin: 0; overflow: hidden; padding:0 !important;}'; return $style; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/typography.php 0000666 00000002527 15226760543 0010605 0 ustar 00 <?php /** * Typography control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Typography * * @package Neve\Customizer\Controls\React */ class Typography extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_typeface_control'; /** * Additional arguments passed to JS. * * @var array */ public $input_attrs = []; /** * Refresh on reset flag. * * @var bool */ public $refresh_on_reset = false; /** * The control that holds the font family used by this control * * @var string */ public $font_family_control = ''; /** * Send to JS. */ public function json() { $json = parent::json(); $json['input_attrs'] = wp_json_encode( $this->input_attrs ); $json['refresh_on_reset'] = $this->refresh_on_reset; $json['font_family_control'] = $this->font_family_control; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/responsive_radio_buttons.php 0000666 00000002006 15226760543 0013520 0 ustar 00 <?php /** * Responsive_Radio_Buttons Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Responsive_Range * * @package Neve\Customizer\Controls\React */ class Responsive_Radio_Buttons extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_responsive_radio_buttons_control'; /** * Additional arguments passed to JS. * * @var array */ public $choices = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['choices'] = $this->choices; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/documentation_section.php 0000666 00000002114 15226760543 0012764 0 ustar 00 <?php /** * A section control for documentation. * * Author: Bogdan Preda <bogdan.preda@themeisle.com> * Created on: 22-12-{2021} * * @package neve/neve-pro */ namespace Neve\Customizer\Controls\React; /** * Customizer section. * * @package WordPress * @subpackage Customize * @since 4.1.0 * @see WP_Customize_Section */ class Documentation_Section extends \WP_Customize_Section { /** * Type of this section. * * @var string */ public $type = 'neve_documentation'; /** * Documentation URL. * * @var string */ public $url = ''; /** * Gather the parameters passed to client JavaScript via JSON. * * @return array The array to be exported to the client as JSON. * @since 4.1.0 */ public function json() { $json = parent::json(); $json['url'] = $this->url; return $json; } /** * Render template. */ protected function render_template() { ?> <li id="accordion-section-{{ data.id }}" data-slug="{{data.id}}" class="control-section control-section-{{ data.type }} neve-documentation"> </li> <?php } } react/font_pairings.php 0000666 00000001760 15226760543 0011237 0 ustar 00 <?php /** * Font_Pairings Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Font_Pairings * * @package Neve\Customizer\Controls\React */ class Font_Pairings extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_font_pairings_control'; /** * Additional arguments passed to JS. * * @var array */ public $input_attrs = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['input_attrs'] = $this->input_attrs; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/upsell_banner.php 0000666 00000003555 15226760543 0011232 0 ustar 00 <?php /** * Description Upsell Section * * Author: Bogdan Preda <bogdan.preda@themeisle.com> * Created on: 20-12-{2021} * * @package neve/neve-pro */ namespace Neve\Customizer\Controls\React; /** * Customizer section. * * @package WordPress * @subpackage Customize * @since 4.1.0 * @see WP_Customize_Section */ class Upsell_Banner extends \WP_Customize_Control { /** * Type of this section. * * @var string */ public $type = 'neve_upsell_banner'; /** * Upgrade URL. * * @var string */ public $url = ''; /** * Nonce. * * @var string */ public $nonce = ''; /** * Upsell text. * * @var string */ public $text = ''; /** * Upsell button text. * * @var string */ public $button_text = ''; /** * Upsell logo path. * * @var string */ public $logo_path = ''; /** * Upsell use logo. * * @var boolean */ public $use_logo = false; /** * Gather the parameters passed to client JavaScript via JSON. * * @return array The array to be exported to the client as JSON. * @since 4.1.0 */ public function json() { $json = parent::json(); $json['url'] = $this->url; $json['nonce'] = $this->nonce; $json['text'] = $this->text; $json['buttonText'] = $this->button_text; $json['useLogo'] = $this->use_logo === true; $json['id'] = $this->id; $json['logoPath'] = ! empty( $this->logo_path ) ? $this->logo_path : get_template_directory_uri() . '/assets/img/dashboard/logo.svg'; return $json; } /** * Render template. */ protected function render() { ?> <li id="customize-control-<?php echo esc_attr( $this->id ); ?>" data-slug="<?php echo esc_attr( $this->id ); ?>" class="customize-control customize-control-<?php echo esc_attr( $this->id ); ?>-control neve-upsell-banner" style="background: none;"> </li> <?php } } react/radio_image.php 0000666 00000002166 15226760543 0010636 0 ustar 00 <?php /** * Radio Image Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Radio_Image * * @package Neve\Customizer\Controls\React */ class Radio_Image extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_radio_image_control'; /** * Additional arguments passed to JS. * * @var array */ public $choices = []; /** * Additional arguments passed to JS. * * @var array */ public $documentation = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['choices'] = $this->choices; $json['documentation'] = $this->documentation; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/instructions_control.php 0000666 00000002475 15226760543 0012705 0 ustar 00 <?php /** * Created on: 2020-08-12 * * @package Neve */ namespace Neve\Customizer\Controls\React; /** * Customizer section. * * @package WordPress * @subpackage Customize * @since 4.1.0 * @see WP_Customize_Section */ class Instructions_Control extends \WP_Customize_Control { /** * Type of this section. * * @var string */ public $type = 'hfg_instructions'; /** * Default options schema. * * @var array */ public $default_options = [ 'description' => '', 'image' => '', 'quickLinks' => [], ]; /** * Options passed to control. * * @var array */ public $options = []; /** * Gather the parameters passed to client JavaScript via JSON. * * @since 4.1.0 * * @return array The array to be exported to the client as JSON. */ public function json() { $json = parent::json(); $json['options'] = wp_parse_args( $this->options, $this->default_options ); return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/repeater.php 0000666 00000003373 15226760543 0010206 0 ustar 00 <?php /** * Repeater Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Repeater * * @package Neve\Customizer\Controls\React */ class Repeater extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_repeater_control'; /** * Additional arguments passed to JS. * * @var array */ public $fields = []; /** * Additional arguments passed to JS. * * @var object */ public $new_item_fields; /** * Additional arguments passed to JS. * * @var array */ public $components = []; /** * Additional arguments passed to JS. * * @var string */ public $allow_new_fields = 'yes'; /** * @param \WP_Customize_Manager $manager customize manager object. * @param String $id control ID. * @param array $args control args. */ public function __construct( $manager, $id, $args = array() ) { $this->new_item_fields = new \stdClass(); parent::__construct( $manager, $id, $args ); } /** * Send to JS. */ public function json() { $json = parent::json(); $json['fields'] = $this->fields; $json['new_item_fields'] = $this->new_item_fields; $json['allow_new_fields'] = $this->allow_new_fields; $json['components'] = $this->components; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/elFinderVolumeLocalFileSystem.class.php 0000666 00000136366 15226760543 0015414 0 ustar 00 <?php // Implement similar functionality in PHP 5.2 or 5.3 // http://php.net/manual/class.recursivecallbackfilteriterator.php#110974 if (!class_exists('RecursiveCallbackFilterIterator', false)) { class RecursiveCallbackFilterIterator extends RecursiveFilterIterator { private $callback; public function __construct(RecursiveIterator $iterator, $callback) { $this->callback = $callback; parent::__construct($iterator); } public function accept() { return call_user_func($this->callback, parent::current(), parent::key(), parent::getInnerIterator()); } public function getChildren() { return new self($this->getInnerIterator()->getChildren(), $this->callback); } } } /** * elFinder driver for local filesystem. * * @author Dmitry (dio) Levashov * @author Troex Nevelin **/ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver { /** * Driver id * Must be started from letter and contains [a-z0-9] * Used as part of volume id * * @var string **/ protected $driverId = 'l'; /** * Required to count total archive files size * * @var int **/ protected $archiveSize = 0; /** * Is checking stat owner * * @var boolean */ protected $statOwner = false; /** * Path to quarantine directory * * @var string */ private $quarantine; /** * Constructor * Extend options with required fields * * @author Dmitry (dio) Levashov */ public function __construct() { $this->options['alias'] = ''; // alias to replace root dir name $this->options['dirMode'] = 0755; // new dirs mode $this->options['fileMode'] = 0644; // new files mode $this->options['rootCssClass'] = 'elfinder-navbar-root-local'; $this->options['followSymLinks'] = true; $this->options['detectDirIcon'] = ''; // file name that is detected as a folder icon e.g. '.diricon.png' $this->options['keepTimestamp'] = array('copy', 'move'); // keep timestamp at inner filesystem allowed 'copy', 'move' and 'upload' $this->options['substituteImg'] = true; // support substitute image with dim command $this->options['statCorrector'] = null; // callable to correct stat data `function(&$stat, $path, $statOwner, $volumeDriveInstance){}` if (DIRECTORY_SEPARATOR === '/') { // Linux $this->options['acceptedName'] = '/^[^\.\/\x00][^\/\x00]*$/'; } else { // Windows $this->options['acceptedName'] = '/^[^\.\/\x00\\\:*?"<>|][^\/\x00\\\:*?"<>|]*$/'; } } /*********************************************************************/ /* INIT AND CONFIGURE */ /*********************************************************************/ /** * Prepare driver before mount volume. * Return true if volume is ready. * * @return bool **/ protected function init() { // Normalize directory separator for windows if (DIRECTORY_SEPARATOR !== '/') { foreach (array('path', 'tmbPath', 'tmpPath', 'quarantine') as $key) { if (!empty($this->options[$key])) { $this->options[$key] = str_replace('/', DIRECTORY_SEPARATOR, $this->options[$key]); } } // PHP >= 7.1 Supports UTF-8 path on Windows if (version_compare(PHP_VERSION, '7.1', '>=')) { $this->options['encoding'] = ''; $this->options['locale'] = ''; } } if (!$cwd = getcwd()) { return $this->setError('elFinder LocalVolumeDriver requires a result of getcwd().'); } // detect systemRoot if (!isset($this->options['systemRoot'])) { if ($cwd[0] === DIRECTORY_SEPARATOR || $this->root[0] === DIRECTORY_SEPARATOR) { $this->systemRoot = DIRECTORY_SEPARATOR; } else if (preg_match('/^([a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . ')/', $this->root, $m)) { $this->systemRoot = $m[1]; } else if (preg_match('/^([a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . ')/', $cwd, $m)) { $this->systemRoot = $m[1]; } } $this->root = $this->getFullPath($this->root, $cwd); if (!empty($this->options['startPath'])) { $this->options['startPath'] = $this->getFullPath($this->options['startPath'], $this->root); } if (is_null($this->options['syncChkAsTs'])) { $this->options['syncChkAsTs'] = true; } if (is_null($this->options['syncCheckFunc'])) { $this->options['syncCheckFunc'] = array($this, 'localFileSystemInotify'); } // check 'statCorrector' if (empty($this->options['statCorrector']) || !is_callable($this->options['statCorrector'])) { $this->options['statCorrector'] = null; } return true; } /** * Configure after successfull mount. * * @return void * @throws elFinderAbortException * @author Dmitry (dio) Levashov */ protected function configure() { $hiddens = array(); $root = $this->stat($this->root); // check thumbnails path if (!empty($this->options['tmbPath'])) { if (strpos($this->options['tmbPath'], DIRECTORY_SEPARATOR) === false) { $hiddens['tmb'] = $this->options['tmbPath']; $this->options['tmbPath'] = $this->_abspath($this->options['tmbPath']); } else { $this->options['tmbPath'] = $this->_normpath($this->options['tmbPath']); } } // check temp path if (!empty($this->options['tmpPath'])) { if (strpos($this->options['tmpPath'], DIRECTORY_SEPARATOR) === false) { $hiddens['temp'] = $this->options['tmpPath']; $this->options['tmpPath'] = $this->_abspath($this->options['tmpPath']); } else { $this->options['tmpPath'] = $this->_normpath($this->options['tmpPath']); } } // check quarantine path $_quarantine = ''; if (!empty($this->options['quarantine'])) { if (strpos($this->options['quarantine'], DIRECTORY_SEPARATOR) === false) { $_quarantine = $this->_abspath($this->options['quarantine']); $this->options['quarantine'] = ''; } else { $this->options['quarantine'] = $this->_normpath($this->options['quarantine']); } } else { $_quarantine = $this->_abspath('.quarantine'); } is_dir($_quarantine) && self::localRmdirRecursive($_quarantine); parent::configure(); // check tmbPath if (!$this->tmbPath && isset($hiddens['tmb'])) { unset($hiddens['tmb']); } // if no thumbnails url - try detect it if ($root['read'] && !$this->tmbURL && $this->URL) { if (strpos($this->tmbPath, $this->root) === 0) { $this->tmbURL = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($this->tmbPath, strlen($this->root) + 1)); if (preg_match("|[^/?&=]$|", $this->tmbURL)) { $this->tmbURL .= '/'; } } } // set $this->tmp by options['tmpPath'] $this->tmp = ''; if (!empty($this->options['tmpPath'])) { if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'], $this->options['dirMode'], true)) && is_writable($this->options['tmpPath'])) { $this->tmp = $this->options['tmpPath']; } else { if (isset($hiddens['temp'])) { unset($hiddens['temp']); } } } if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) { $this->tmp = $tmp; } // check quarantine dir $this->quarantine = ''; if (!empty($this->options['quarantine'])) { if ((is_dir($this->options['quarantine']) || mkdir($this->options['quarantine'], $this->options['dirMode'], true)) && is_writable($this->options['quarantine'])) { $this->quarantine = $this->options['quarantine']; } else { if (isset($hiddens['quarantine'])) { unset($hiddens['quarantine']); } } } else if ($_path = elFinder::getCommonTempPath()) { $this->quarantine = $_path; } if (!$this->quarantine) { if (!$this->tmp) { $this->archivers['extract'] = array(); $this->disabled[] = 'extract'; } else { $this->quarantine = $this->tmp; } } if ($hiddens) { foreach ($hiddens as $hidden) { $this->attributes[] = array( 'pattern' => '~^' . preg_quote(DIRECTORY_SEPARATOR . $hidden, '~') . '$~', 'read' => false, 'write' => false, 'locked' => true, 'hidden' => true ); } } if (!empty($this->options['keepTimestamp'])) { $this->options['keepTimestamp'] = array_flip($this->options['keepTimestamp']); } $this->statOwner = (!empty($this->options['statOwner'])); // enable WinRemoveTailDots plugin on Windows server if (DIRECTORY_SEPARATOR !== '/') { if (!isset($this->options['plugin'])) { $this->options['plugin'] = array(); } $this->options['plugin']['WinRemoveTailDots'] = array('enable' => true); } } /** * Long pooling sync checker * This function require server command `inotifywait` * If `inotifywait` need full path, Please add `define('ELFINER_INOTIFYWAIT_PATH', '/PATH_TO/inotifywait');` into connector.php * * @param string $path * @param int $standby * @param number $compare * * @return number|bool * @throws elFinderAbortException */ public function localFileSystemInotify($path, $standby, $compare) { if (isset($this->sessionCache['localFileSystemInotify_disable'])) { return false; } $path = realpath($path); $mtime = filemtime($path); if (!$mtime) { return false; } if ($mtime != $compare) { return $mtime; } $inotifywait = defined('ELFINER_INOTIFYWAIT_PATH') ? ELFINER_INOTIFYWAIT_PATH : 'inotifywait'; $standby = max(1, intval($standby)); $cmd = $inotifywait . ' ' . escapeshellarg($path) . ' -t ' . $standby . ' -e moved_to,moved_from,move,close_write,delete,delete_self'; $this->procExec($cmd, $o, $r); if ($r === 0) { // changed clearstatcache(); if (file_exists($path)) { $mtime = filemtime($path); // error on busy? return $mtime ? $mtime : time(); } else { // target was removed return 0; } } else if ($r === 2) { // not changed (timeout) return $compare; } // error // cache to $_SESSION $this->sessionCache['localFileSystemInotify_disable'] = true; $this->session->set($this->id, $this->sessionCache); return false; } /*********************************************************************/ /* FS API */ /*********************************************************************/ /*********************** paths/urls *************************/ /** * Return parent directory path * * @param string $path file path * * @return string * @author Dmitry (dio) Levashov **/ protected function _dirname($path) { return dirname($path); } /** * Return file name * * @param string $path file path * * @return string * @author Dmitry (dio) Levashov **/ protected function _basename($path) { return basename($path); } /** * Join dir name and file name and retur full path * * @param string $dir * @param string $name * * @return string * @author Dmitry (dio) Levashov **/ protected function _joinPath($dir, $name) { $dir = rtrim($dir, DIRECTORY_SEPARATOR); $path = realpath($dir . DIRECTORY_SEPARATOR . $name); // realpath() returns FALSE if the file does not exist if ($path === false || strpos($path, $this->root) !== 0) { if (DIRECTORY_SEPARATOR !== '/') { $dir = str_replace('/', DIRECTORY_SEPARATOR, $dir); $name = str_replace('/', DIRECTORY_SEPARATOR, $name); } // Directory traversal measures if (strpos($dir, '..' . DIRECTORY_SEPARATOR) !== false || substr($dir, -2) == '..') { $dir = $this->root; } if (strpos($name, '..' . DIRECTORY_SEPARATOR) !== false) { $name = basename($name); } $path = $dir . DIRECTORY_SEPARATOR . $name; } return $path; } /** * Return normalized path, this works the same as os.path.normpath() in Python * * @param string $path path * * @return string * @author Troex Nevelin **/ protected function _normpath($path) { if (empty($path)) { return '.'; } $changeSep = (DIRECTORY_SEPARATOR !== '/'); if ($changeSep) { $drive = ''; if (preg_match('/^([a-zA-Z]:)(.*)/', $path, $m)) { $drive = $m[1]; $path = $m[2] ? $m[2] : '/'; } $path = str_replace(DIRECTORY_SEPARATOR, '/', $path); } if (strpos($path, '/') === 0) { $initial_slashes = true; } else { $initial_slashes = false; } if (($initial_slashes) && (strpos($path, '//') === 0) && (strpos($path, '///') === false)) { $initial_slashes = 2; } $initial_slashes = (int)$initial_slashes; $comps = explode('/', $path); $new_comps = array(); foreach ($comps as $comp) { if (in_array($comp, array('', '.'))) { continue; } if (($comp != '..') || (!$initial_slashes && !$new_comps) || ($new_comps && (end($new_comps) == '..'))) { array_push($new_comps, $comp); } elseif ($new_comps) { array_pop($new_comps); } } $comps = $new_comps; $path = implode('/', $comps); if ($initial_slashes) { $path = str_repeat('/', $initial_slashes) . $path; } if ($changeSep) { $path = $drive . str_replace('/', DIRECTORY_SEPARATOR, $path); } return $path ? $path : '.'; } /** * Return file path related to root dir * * @param string $path file path * * @return string * @author Dmitry (dio) Levashov **/ protected function _relpath($path) { if ($path === $this->root) { return ''; } else { if (strpos($path, $this->root) === 0) { return ltrim(substr($path, strlen($this->root)), DIRECTORY_SEPARATOR); } else { // for link return $path; } } } /** * Convert path related to root dir into real path * * @param string $path file path * * @return string * @author Dmitry (dio) Levashov **/ protected function _abspath($path) { if ($path === DIRECTORY_SEPARATOR) { return $this->root; } else { $path = $this->_normpath($path); if (strpos($path, $this->systemRoot) === 0) { return $path; } else if (DIRECTORY_SEPARATOR !== '/' && preg_match('/^[a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . '/', $path)) { return $path; } else { return $this->_joinPath($this->root, $path); } } } /** * Return fake path started from root dir * * @param string $path file path * * @return string * @author Dmitry (dio) Levashov **/ protected function _path($path) { return $this->rootName . ($path == $this->root ? '' : $this->separator . $this->_relpath($path)); } /** * Return true if $path is children of $parent * * @param string $path path to check * @param string $parent parent path * * @return bool * @author Dmitry (dio) Levashov **/ protected function _inpath($path, $parent) { $cwd = getcwd(); $real_path = $this->getFullPath($path, $cwd); $real_parent = $this->getFullPath($parent, $cwd); if ($real_path && $real_parent) { return $real_path === $real_parent || strpos($real_path, rtrim($real_parent, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR) === 0; } return false; } /***************** file stat ********************/ /** * Return stat for given path. * Stat contains following fields: * - (int) size file size in b. required * - (int) ts file modification time in unix time. required * - (string) mime mimetype. required for folders, others - optionally * - (bool) read read permissions. required * - (bool) write write permissions. required * - (bool) locked is object locked. optionally * - (bool) hidden is object hidden. optionally * - (string) alias for symlinks - link target path relative to root path. optionally * - (string) target for symlinks - link target path. optionally * If file does not exists - returns empty array or false. * * @param string $path file path * * @return array|false * @author Dmitry (dio) Levashov **/ protected function _stat($path) { $stat = array(); if (!file_exists($path) && !is_link($path)) { return $stat; } //Verifies the given path is the root or is inside the root. Prevents directory traveral. if (!$this->_inpath($path, $this->root)) { return $stat; } $stat['isowner'] = false; $linkreadable = false; if ($path != $this->root && is_link($path)) { if (!$this->options['followSymLinks']) { return array(); } if (!($target = $this->readlink($path)) || $target == $path) { if (is_null($target)) { $stat = array(); return $stat; } else { $stat['mime'] = 'symlink-broken'; $target = readlink($path); $lstat = lstat($path); $ostat = $this->getOwnerStat($lstat['uid'], $lstat['gid']); $linkreadable = !empty($ostat['isowner']); } } $stat['alias'] = $this->_path($target); $stat['target'] = $target; } $readable = is_readable($path); if ($readable) { $size = sprintf('%u', filesize($path)); $stat['ts'] = filemtime($path); if ($this->statOwner) { $fstat = stat($path); $uid = $fstat['uid']; $gid = $fstat['gid']; $stat['perm'] = substr((string)decoct($fstat['mode']), -4); $stat = array_merge($stat, $this->getOwnerStat($uid, $gid)); } } if (($dir = is_dir($path)) && $this->options['detectDirIcon']) { $favicon = $path . DIRECTORY_SEPARATOR . $this->options['detectDirIcon']; if ($this->URL && file_exists($favicon)) { $stat['icon'] = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($favicon, strlen($this->root) + 1)); } } if (!isset($stat['mime'])) { $stat['mime'] = $dir ? 'directory' : $this->mimetype($path); } //logical rights first $stat['read'] = ($linkreadable || $readable) ? null : false; $stat['write'] = is_writable($path) ? null : false; if (is_null($stat['read'])) { if ($dir) { $stat['size'] = 0; } else if (isset($size)) { $stat['size'] = $size; } } if ($this->options['statCorrector']) { call_user_func_array($this->options['statCorrector'], array(&$stat, $path, $this->statOwner, $this)); } return $stat; } /** * Get stat `owner`, `group` and `isowner` by `uid` and `gid` * Sub-fuction of _stat() and _scandir() * * @param integer $uid * @param integer $gid * * @return array stat */ protected function getOwnerStat($uid, $gid) { static $names = null; static $phpuid = null; if (is_null($names)) { $names = array('uid' => array(), 'gid' => array()); } if (is_null($phpuid)) { if (is_callable('posix_getuid')) { $phpuid = posix_getuid(); } else { $phpuid = 0; } } $stat = array(); if ($uid) { $stat['isowner'] = ($phpuid == $uid); if (isset($names['uid'][$uid])) { $stat['owner'] = $names['uid'][$uid]; } else if (is_callable('posix_getpwuid')) { $pwuid = posix_getpwuid($uid); $stat['owner'] = $names['uid'][$uid] = $pwuid['name']; } else { $stat['owner'] = $names['uid'][$uid] = $uid; } } if ($gid) { if (isset($names['gid'][$gid])) { $stat['group'] = $names['gid'][$gid]; } else if (is_callable('posix_getgrgid')) { $grgid = posix_getgrgid($gid); $stat['group'] = $names['gid'][$gid] = $grgid['name']; } else { $stat['group'] = $names['gid'][$gid] = $gid; } } return $stat; } /** * Return true if path is dir and has at least one childs directory * * @param string $path dir path * * @return bool * @author Dmitry (dio) Levashov **/ protected function _subdirs($path) { $dirs = false; if (is_dir($path) && is_readable($path)) { if (class_exists('FilesystemIterator', false)) { $dirItr = new ParentIterator( new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS | FilesystemIterator::CURRENT_AS_SELF | (defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') ? RecursiveDirectoryIterator::FOLLOW_SYMLINKS : 0) ) ); $dirItr->rewind(); if ($dirItr->hasChildren()) { $dirs = true; $name = $dirItr->getSubPathName(); while ($dirItr->valid()) { if (!$this->attr($path . DIRECTORY_SEPARATOR . $name, 'read', null, true)) { $dirs = false; $dirItr->next(); $name = $dirItr->getSubPathName(); continue; } $dirs = true; break; } } } else { $path = strtr($path, array('[' => '\\[', ']' => '\\]', '*' => '\\*', '?' => '\\?')); return (bool)glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR); } } return $dirs; } /** * Return object width and height * Usualy used for images, but can be realize for video etc... * * @param string $path file path * @param string $mime file mime type * * @return string * @author Dmitry (dio) Levashov **/ protected function _dimensions($path, $mime) { clearstatcache(); return strpos($mime, 'image') === 0 && is_readable($path) && filesize($path) && ($s = getimagesize($path)) !== false ? $s[0] . 'x' . $s[1] : false; } /******************** file/dir content *********************/ /** * Return symlink target file * * @param string $path link path * * @return string * @author Dmitry (dio) Levashov **/ protected function readlink($path) { if (!($target = readlink($path))) { return null; } if (strpos($target, $this->systemRoot) !== 0) { $target = $this->_joinPath(dirname($path), $target); } if (!file_exists($target)) { return false; } return $target; } /** * Return files list in directory. * * @param string $path dir path * * @return array * @throws elFinderAbortException * @author Dmitry (dio) Levashov */ protected function _scandir($path) { elFinder::checkAborted(); $files = array(); $cache = array(); $dirWritable = is_writable($path); $dirItr = array(); $followSymLinks = $this->options['followSymLinks']; try { $dirItr = new DirectoryIterator($path); } catch (UnexpectedValueException $e) { } foreach ($dirItr as $file) { try { if ($file->isDot()) { continue; } $files[] = $fpath = $file->getPathname(); $br = false; $stat = array(); $stat['isowner'] = false; $linkreadable = false; if ($file->isLink()) { if (!$followSymLinks) { continue; } if (!($target = $this->readlink($fpath)) || $target == $fpath) { if (is_null($target)) { $stat = array(); $br = true; } else { $_path = $fpath; $stat['mime'] = 'symlink-broken'; $target = readlink($_path); $lstat = lstat($_path); $ostat = $this->getOwnerStat($lstat['uid'], $lstat['gid']); $linkreadable = !empty($ostat['isowner']); $dir = false; $stat['alias'] = $this->_path($target); $stat['target'] = $target; } } else { $dir = is_dir($target); $stat['alias'] = $this->_path($target); $stat['target'] = $target; $stat['mime'] = $dir ? 'directory' : $this->mimetype($stat['alias']); } } else { if (($dir = $file->isDir()) && $this->options['detectDirIcon']) { $path = $file->getPathname(); $favicon = $path . DIRECTORY_SEPARATOR . $this->options['detectDirIcon']; if ($this->URL && file_exists($favicon)) { $stat['icon'] = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($favicon, strlen($this->root) + 1)); } } $stat['mime'] = $dir ? 'directory' : $this->mimetype($fpath); } $size = sprintf('%u', $file->getSize()); $stat['ts'] = $file->getMTime(); if (!$br) { if ($this->statOwner && !$linkreadable) { $uid = $file->getOwner(); $gid = $file->getGroup(); $stat['perm'] = substr((string)decoct($file->getPerms()), -4); $stat = array_merge($stat, $this->getOwnerStat($uid, $gid)); } //logical rights first $stat['read'] = ($linkreadable || $file->isReadable()) ? null : false; $stat['write'] = $file->isWritable() ? null : false; $stat['locked'] = $dirWritable ? null : true; if (is_null($stat['read'])) { $stat['size'] = $dir ? 0 : $size; } if ($this->options['statCorrector']) { call_user_func_array($this->options['statCorrector'], array(&$stat, $fpath, $this->statOwner, $this)); } } $cache[] = array($fpath, $stat); } catch (RuntimeException $e) { continue; } } if ($cache) { $cache = $this->convEncOut($cache, false); foreach ($cache as $d) { $this->updateCache($d[0], $d[1]); } } return $files; } /** * Open file and return file pointer * * @param string $path file path * @param string $mode * * @return false|resource * @internal param bool $write open file for writing * @author Dmitry (dio) Levashov */ protected function _fopen($path, $mode = 'rb') { return fopen($path, $mode); } /** * Close opened file * * @param resource $fp file pointer * @param string $path * * @return bool * @author Dmitry (dio) Levashov */ protected function _fclose($fp, $path = '') { return (is_resource($fp) && fclose($fp)); } /******************** file/dir manipulations *************************/ /** * Create dir and return created dir path or false on failed * * @param string $path parent dir path * @param string $name new directory name * * @return string|bool * @author Dmitry (dio) Levashov **/ protected function _mkdir($path, $name) { $path = $this->_joinPath($path, $name); if (mkdir($path)) { chmod($path, $this->options['dirMode']); return $path; } return false; } /** * Create file and return it's path or false on failed * * @param string $path parent dir path * @param string $name new file name * * @return string|bool * @author Dmitry (dio) Levashov **/ protected function _mkfile($path, $name) { $path = $this->_joinPath($path, $name); if (($fp = fopen($path, 'w'))) { fclose($fp); chmod($path, $this->options['fileMode']); return $path; } return false; } /** * Create symlink * * @param string $source file to link to * @param string $targetDir folder to create link in * @param string $name symlink name * * @return bool * @author Dmitry (dio) Levashov **/ protected function _symlink($source, $targetDir, $name) { return $this->localFileSystemSymlink($source, $this->_joinPath($targetDir, $name)); } /** * Copy file into another file * * @param string $source source file path * @param string $targetDir target directory path * @param string $name new file name * * @return bool * @author Dmitry (dio) Levashov **/ protected function _copy($source, $targetDir, $name) { $mtime = filemtime($source); $target = $this->_joinPath($targetDir, $name); if ($ret = copy($source, $target)) { isset($this->options['keepTimestamp']['copy']) && $mtime && touch($target, $mtime); } return $ret; } /** * Move file into another parent dir. * Return new file path or false. * * @param string $source source file path * @param $targetDir * @param string $name file name * * @return bool|string * @internal param string $target target dir path * @author Dmitry (dio) Levashov */ protected function _move($source, $targetDir, $name) { $mtime = filemtime($source); $target = $this->_joinPath($targetDir, $name); if ($ret = rename($source, $target) ? $target : false) { isset($this->options['keepTimestamp']['move']) && $mtime && touch($target, $mtime); } return $ret; } /** * Remove file * * @param string $path file path * * @return bool * @author Dmitry (dio) Levashov **/ protected function _unlink($path) { return is_file($path) && unlink($path); } /** * Remove dir * * @param string $path dir path * * @return bool * @author Dmitry (dio) Levashov **/ protected function _rmdir($path) { return rmdir($path); } /** * Create new file and write into it from file pointer. * Return new file path or false on error. * * @param resource $fp file pointer * @param string $dir target dir path * @param string $name file name * @param array $stat file stat (required by some virtual fs) * * @return bool|string * @author Dmitry (dio) Levashov **/ protected function _save($fp, $dir, $name, $stat) { $path = $this->_joinPath($dir, $name); $meta = stream_get_meta_data($fp); $uri = isset($meta['uri']) ? $meta['uri'] : ''; if ($uri && !preg_match('#^[a-zA-Z0-9]+://#', $uri) && !is_link($uri)) { fclose($fp); $mtime = filemtime($uri); $isCmdPaste = ($this->ARGS['cmd'] === 'paste'); $isCmdCopy = ($isCmdPaste && empty($this->ARGS['cut'])); if (($isCmdCopy || !rename($uri, $path)) && !copy($uri, $path)) { return false; } // keep timestamp on upload if ($mtime && $this->ARGS['cmd'] === 'upload') { touch($path, isset($this->options['keepTimestamp']['upload']) ? $mtime : time()); } } else { if (file_put_contents($path, $fp, LOCK_EX) === false) { return false; } } chmod($path, $this->options['fileMode']); return $path; } /** * Get file contents * * @param string $path file path * * @return string|false * @author Dmitry (dio) Levashov **/ protected function _getContents($path) { return file_get_contents($path); } /** * Write a string to a file * * @param string $path file path * @param string $content new file content * * @return bool * @author Dmitry (dio) Levashov **/ protected function _filePutContents($path, $content) { return (file_put_contents($path, $content, LOCK_EX) !== false); } /** * Detect available archivers * * @return void * @throws elFinderAbortException */ protected function _checkArchivers() { $this->archivers = $this->getArchivers(); return; } /** * chmod availability * * @param string $path * @param string $mode * * @return bool */ protected function _chmod($path, $mode) { $modeOct = is_string($mode) ? octdec($mode) : octdec(sprintf("%04o", $mode)); return chmod($path, $modeOct); } /** * Recursive symlinks search * * @param string $path file/dir path * * @return bool * @throws Exception * @author Dmitry (dio) Levashov */ protected function _findSymlinks($path) { return self::localFindSymlinks($path); } /** * Extract files from archive * * @param string $path archive path * @param array $arc archiver command and arguments (same as in $this->archivers) * * @return array|string|boolean * @throws elFinderAbortException * @author Dmitry (dio) Levashov, * @author Alexey Sukhotin */ protected function _extract($path, $arc) { if ($this->quarantine) { $dir = $this->quarantine . DIRECTORY_SEPARATOR . md5(basename($path) . mt_rand()); $archive = (isset($arc['toSpec']) || $arc['cmd'] === 'phpfunction') ? '' : $dir . DIRECTORY_SEPARATOR . basename($path); if (!mkdir($dir)) { return false; } // insurance unexpected shutdown register_shutdown_function(array($this, 'rmdirRecursive'), realpath($dir)); chmod($dir, 0777); // copy in quarantine if (!is_readable($path) || ($archive && !copy($path, $archive))) { return false; } // extract in quarantine try { $this->unpackArchive($path, $arc, $archive ? true : $dir); } catch(Exception $e) { return $this->setError($e->getMessage()); } // get files list try { $ls = self::localScandir($dir); } catch (Exception $e) { return false; } // no files - extract error ? if (empty($ls)) { return false; } $this->archiveSize = 0; // find symlinks and check extracted items $checkRes = $this->checkExtractItems($dir); if ($checkRes['symlinks']) { self::localRmdirRecursive($dir); return $this->setError(array_merge($this->error, array(elFinder::ERROR_ARC_SYMLINKS))); } $this->archiveSize = $checkRes['totalSize']; if ($checkRes['rmNames']) { foreach ($checkRes['rmNames'] as $name) { $this->addError(elFinder::ERROR_SAVE, $name); } } // check max files size if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $this->archiveSize) { $this->delTree($dir); return $this->setError(elFinder::ERROR_ARC_MAXSIZE); } $extractTo = $this->extractToNewdir; // 'auto', ture or false // archive contains one item - extract in archive dir $name = ''; $src = $dir . DIRECTORY_SEPARATOR . $ls[0]; if (($extractTo === 'auto' || !$extractTo) && count($ls) === 1 && is_file($src)) { $name = $ls[0]; } else if ($extractTo === 'auto' || $extractTo) { // for several files - create new directory // create unique name for directory $src = $dir; $splits = elFinder::splitFileExtention(basename($path)); $name = $splits[0]; $test = dirname($path) . DIRECTORY_SEPARATOR . $name; if (file_exists($test) || is_link($test)) { $name = $this->uniqueName(dirname($path), $name, '-', false); } } if ($name !== '') { $result = dirname($path) . DIRECTORY_SEPARATOR . $name; if (!rename($src, $result)) { $this->delTree($dir); return false; } } else { $dstDir = dirname($path); $result = array(); foreach ($ls as $name) { $target = $dstDir . DIRECTORY_SEPARATOR . $name; if (self::localMoveRecursive($dir . DIRECTORY_SEPARATOR . $name, $target, true, $this->options['copyJoin'])) { $result[] = $target; } } if (!$result) { $this->delTree($dir); return false; } } is_dir($dir) && $this->delTree($dir); return (is_array($result) || file_exists($result)) ? $result : false; } //TODO: Add return statement here return false; } /** * Create archive and return its path * * @param string $dir target dir * @param array $files files names list * @param string $name archive name * @param array $arc archiver options * * @return string|bool * @throws elFinderAbortException * @author Dmitry (dio) Levashov, * @author Alexey Sukhotin */ protected function _archive($dir, $files, $name, $arc) { return $this->makeArchive($dir, $files, $name, $arc); } /******************** Over write functions *************************/ /** * File path of local server side work file path * * @param string $path * * @return string * @author Naoki Sawada */ protected function getWorkFile($path) { return $path; } /** * Delete dirctory trees * * @param string $localpath path need convert encoding to server encoding * * @return boolean * @throws elFinderAbortException * @author Naoki Sawada */ protected function delTree($localpath) { return $this->rmdirRecursive($localpath); } /** * Return fileinfo based on filename * For item ID based path file system * Please override if needed on each drivers * * @param string $path file cache * * @return array|boolean false */ protected function isNameExists($path) { $exists = file_exists($this->convEncIn($path)); // restore locale $this->convEncOut(); return $exists ? $this->stat($path) : false; } /******************** Over write (Optimized) functions *************************/ /** * Recursive files search * * @param string $path dir path * @param string $q search string * @param array $mimes * * @return array * @throws elFinderAbortException * @author Dmitry (dio) Levashov * @author Naoki Sawada */ protected function doSearch($path, $q, $mimes) { if (!empty($this->doSearchCurrentQuery['matchMethod']) || $this->encoding || !class_exists('FilesystemIterator', false)) { // has custom match method or non UTF-8, use elFinderVolumeDriver::doSearch() return parent::doSearch($path, $q, $mimes); } $result = array(); $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0; if ($timeout && $timeout < time()) { $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path))); return $result; } elFinder::extendTimeLimit($this->options['searchTimeout'] + 30); $match = array(); try { $iterator = new RecursiveIteratorIterator( new RecursiveCallbackFilterIterator( new RecursiveDirectoryIterator($path, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::SKIP_DOTS | ((defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') && $this->options['followSymLinks']) ? RecursiveDirectoryIterator::FOLLOW_SYMLINKS : 0) ), array($this, 'localFileSystemSearchIteratorFilter') ), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD ); foreach ($iterator as $key => $node) { if ($timeout && ($this->error || $timeout < time())) { !$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($node->getPath))); break; } if ($node->isDir()) { if ($this->stripos($node->getFilename(), $q) !== false) { $match[] = $key; } } else { $match[] = $key; } } } catch (Exception $e) { } if ($match) { foreach ($match as $p) { if ($timeout && ($this->error || $timeout < time())) { !$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode(dirname($p)))); break; } $stat = $this->stat($p); if (!$stat) { // invalid links continue; } if (!empty($stat['hidden']) || !$this->mimeAccepted($stat['mime'], $mimes)) { continue; } if ((!$mimes || $stat['mime'] !== 'directory')) { $stat['path'] = $this->path($stat['hash']); if ($this->URL && !isset($stat['url'])) { $_path = str_replace(DIRECTORY_SEPARATOR, '/', substr($p, strlen($this->root) + 1)); $stat['url'] = $this->URL . str_replace('%2F', '/', rawurlencode($_path)); } $result[] = $stat; } } } return $result; } /******************** Original local functions ************************ * * @param $file * @param $key * @param $iterator * * @return bool */ public function localFileSystemSearchIteratorFilter($file, $key, $iterator) { /* @var FilesystemIterator $file */ /* @var RecursiveDirectoryIterator $iterator */ $name = $file->getFilename(); if ($this->doSearchCurrentQuery['excludes']) { foreach ($this->doSearchCurrentQuery['excludes'] as $exclude) { if ($this->stripos($name, $exclude) !== false) { return false; } } } if ($iterator->hasChildren()) { if ($this->options['searchExDirReg'] && preg_match($this->options['searchExDirReg'], $key)) { return false; } return (bool)$this->attr($key, 'read', null, true); } return ($this->stripos($name, $this->doSearchCurrentQuery['q']) === false) ? false : true; } /** * Creates a symbolic link * * @param string $target The target * @param string $link The link * * @return boolean ( result of symlink() ) */ protected function localFileSystemSymlink($target, $link) { $res = false; if (function_exists('symlink') and is_callable('symlink')) { $errlev = error_reporting(); error_reporting($errlev ^ E_WARNING); if ($res = symlink(realpath($target), $link)) { $res = is_readable($link); } error_reporting($errlev); } return $res; } } // END class react/logo_palette.php 0000666 00000001755 15226760543 0011057 0 ustar 00 <?php /** * Logo_Palette Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Logo_Palette * * @package Neve\Customizer\Controls\React */ class Logo_Palette extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_logo_palette_control'; /** * Additional arguments passed to JS. * * @var array */ public $input_attrs = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['input_attrs'] = $this->input_attrs; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/builder_columns.php 0000666 00000151241 15226760543 0011563 0 ustar 00 <?php /** * Builder Columns Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Customizer section. * * @package Neve\Customizer\Controls\React */ class Builder_Columns extends \WP_Customize_Control { /** * Type of this section. * * @var string */ public $type = 'neve_builder_columns'; /** * Layout Choices. * * @var array */ public $choices = []; /** * Columns control slug. * * @var string|null */ public $columns_control = null; /** * Refresh the parameters passed to the JavaScript via JSON. */ public function json() { $json = parent::json(); $this->choices = [ 1 => [ 'equal' => [ 'url' => 'data:image/jpeg;base64,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', ], ], 2 => [ 'equal' => [ 'url' => 'data:image/jpeg;base64,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', ], 'right-third' => [ 'url' => 'data:image/jpeg;base64,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', ], 'left-third' => [ 'url' => 'data:image/jpeg;base64,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', ], ], 3 => [ 'equal' => [ 'url' => 'data:image/jpeg;base64,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', ], 'left-half' => [ 'url' => 'data:image/jpeg;base64,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', ], 'right-half' => [ 'url' => 'data:image/jpeg;base64,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', ], 'center-half' => [ 'url' => 'data:image/jpeg;base64,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', ], 'center-two-thirds' => [ 'url' => 'data:image/jpeg;base64,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', ], ], 4 => [ 'equal' => [ 'url' => 'data:image/jpeg;base64,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', ], 'left-half' => [ 'url' => 'data:image/jpeg;base64,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', ], 'right-half' => [ 'url' => 'data:image/jpeg;base64,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', ], ], 5 => [ 'equal' => [ 'url' => 'data:image/jpeg;base64,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', ], ], ]; $json['choices'] = $this->choices; $json['columnsControl'] = $this->columns_control; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/color.php 0000666 00000002526 15226760543 0007514 0 ustar 00 <?php /** * Color Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Button_Appearance * * @package Neve\Customizer\Controls\React */ class Color extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_color_control'; /** * Additional arguments passed to JS. * * @var string */ public $default = ''; /** * Disable Alpha in colorpicker. * * @var bool */ public $disable_alpha = false; /** * Allow gradient inside color picker. * * @var bool */ public $allow_gradient = false; /** * Send to JS. */ public function json() { $json = parent::json(); $json['default'] = $this->default; $json['disableAlpha'] = $this->disable_alpha; $json['allowGradient'] = isset( $this->input_attrs['allow_gradient'] ) ? $this->input_attrs['allow_gradient'] : $this->allow_gradient; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/upsell_banner_section.php 0000666 00000003465 15226760543 0012756 0 ustar 00 <?php /** * Description Upsell Section * * Author: Bogdan Preda <bogdan.preda@themeisle.com> * Created on: 20-12-{2021} * * @package neve/neve-pro */ namespace Neve\Customizer\Controls\React; /** * Customizer section. * * @package WordPress * @subpackage Customize * @since 4.1.0 * @see WP_Customize_Section */ class Upsell_Banner_Section extends \WP_Customize_Section { /** * Type of this section. * * @var string */ public $type = 'neve_upsell_banner_section'; /** * Upgrade URL. * * @var string */ public $url = ''; /** * Nonce. * * @var string */ public $nonce = ''; /** * Upsell text. * * @var string */ public $text = ''; /** * Upsell button text. * * @var string */ public $button_text = ''; /** * Upsell logo path. * * @var string */ public $logo_path = ''; /** * Upsell use logo. * * @var boolean */ public $use_logo = false; /** * Gather the parameters passed to client JavaScript via JSON. * * @return array The array to be exported to the client as JSON. * @since 4.1.0 */ public function json() { $json = parent::json(); $json['url'] = $this->url; $json['nonce'] = $this->nonce; $json['text'] = $this->text; $json['buttonText'] = $this->button_text; $json['useLogo'] = $this->use_logo === true; $json['logoPath'] = ! empty( $this->logo_path ) ? $this->logo_path : get_template_directory_uri() . '/assets/img/dashboard/logo.svg'; return $json; } /** * Render template. */ protected function render() { ?> <li id="acordion-section-<?php echo esc_attr( $this->id ); ?>" data-slug="<?php echo esc_attr( $this->id ); ?>" class="control-section control-section-<?php echo esc_attr( $this->type ); ?> neve-upsell-banner"> </li> <?php } } react/responsive_range.php 0000666 00000001775 15226760543 0011754 0 ustar 00 <?php /** * Responsive_Range Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Responsive_Range * * @package Neve\Customizer\Controls\React */ class Responsive_Range extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_responsive_range_control'; /** * Additional arguments passed to JS. * * @var array */ public $input_attrs = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['input_attrs'] = $this->input_attrs; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/global_custom_colors.php 0000666 00000002214 15226760543 0012603 0 ustar 00 <?php /** * Global_Custom_Colors Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Global_Custom_Colors * * @package Neve\Customizer\Controls\React */ class Global_Custom_Colors extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_global_custom_colors'; /** * Default values. * * @var string */ public $default_values = ''; /** * Additional arguments passed to JS. * * @var array */ public $input_attrs = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['defaultValues'] = $this->default_values; $json['input_attrs'] = $this->input_attrs; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/radio_buttons.php 0000666 00000003111 15226760543 0011241 0 ustar 00 <?php /** * Radio Buttons Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Spacing * * @package Neve\Customizer\Controls\React */ class Radio_Buttons extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_radio_buttons_control'; /** * Additional arguments passed to JS. * * @var array */ public $choices = []; /** * Send context to the control that will handle the choices differently. * * @var bool|string */ public $is_for = false; /** * Should have larger buttons. * * @var bool */ public $large_buttons = false; /** * Show the labels. * * @var bool */ public $show_labels = false; /** * Footer description. * * @var string */ public $footer_description = ''; /** * Send to JS. */ public function json() { $json = parent::json(); $json['choices'] = $this->choices; $json['is_for'] = $this->is_for; $json['large_buttons'] = $this->large_buttons; $json['showLabels'] = $this->show_labels; $json['footerDescription'] = $this->footer_description; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/inline_select.php 0000666 00000002424 15226760543 0011210 0 ustar 00 <?php /** * Inline Select Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Inline_Select * * @package Neve\Customizer\Controls\React */ class Inline_Select extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_inline_select'; /** * Options. * * @var array */ public $options = []; /** * Default. * * @var string|int */ public $default; /** * Link. * * @var array */ public $link; /** * Allows listening to other components. * * @var string */ public $changes_on; /** * Send to JS. */ public function json() { $json = parent::json(); $json['options'] = $this->options; $json['defaultVal'] = $this->default; $json['link'] = $this->link; $json['changesOn'] = $this->changes_on; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/range.php 0000666 00000001723 15226760543 0007470 0 ustar 00 <?php /** * Range Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Spacing * * @package Neve\Customizer\Controls\React */ class Range extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_range_control'; /** * Additional arguments passed to JS. * * @var array */ public $input_attrs = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['input_attrs'] = $this->input_attrs; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/presets_selector.php 0000666 00000002122 15226760543 0011753 0 ustar 00 <?php /** * Presets selector control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Spacing * * @package Neve\Customizer\Controls\React */ class Presets_Selector extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_presets_selector'; /** * Presets for the control. * * @var array */ public $presets = []; /** * Builder Setting Slug. * * @var string | null */ public $builder = null; /** * Send to JS. */ public function json() { $json = parent::json(); $json['presets'] = $this->presets; $json['builder'] = $this->builder; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/rich_text.php 0000666 00000002407 15226760543 0010365 0 ustar 00 <?php /** * Rich_Text Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Rich_Text * * @package Neve\Customizer\Controls\React */ class Rich_Text extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_rich_text'; /** * Send to JS. */ public function json() { $json = parent::json(); $json['toolbars'] = []; $json['allowedDynamicFields'] = []; if ( isset( $this->input_attrs['toolbars'] ) && ! empty( $this->input_attrs['toolbars'] ) ) { $json['toolbars'] = $this->input_attrs['toolbars']; } if ( isset( $this->input_attrs['allowedDynamicFields'] ) && ! empty( $this->input_attrs['allowedDynamicFields'] ) ) { $json['allowedDynamicFields'] = $this->input_attrs['allowedDynamicFields']; } return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/spacing.php 0000666 00000002102 15226760543 0010010 0 ustar 00 <?php /** * Spacing Control. Handles data passing from args to JS. * * @package Neve\Customizer\Controls\React */ namespace Neve\Customizer\Controls\React; /** * Class Spacing * * @package Neve\Customizer\Controls\React */ class Spacing extends \WP_Customize_Control { /** * Control type. * * @var string */ public $type = 'neve_spacing'; /** * Additional arguments passed to JS. * * @var array */ public $input_attrs = []; /** * Default value. * * @var array */ public $default = []; /** * Send to JS. */ public function json() { $json = parent::json(); $json['input_attrs'] = $this->input_attrs; $json['default'] = $this->default; return $json; } /** * This method overrides the default render * so that nothing is rendered. * Previously it would try to put an input element where the value was `esc_attr()` * This would trigger notices in PHP * It is not required to have a render as it is being handled by React. */ final public function render_content() { // this is rendered from React } } react/instructions_section.php 0000666 00000002432 15226760543 0012662 0 ustar 00 <?php /** * Author: Andrei Baicus <andrei@themeisle.com> * Created on: 2019-10-16 * * @package Neve */ namespace Neve\Customizer\Controls\React; /** * Customizer section. * * @package WordPress * @subpackage Customize * @since 4.1.0 * @see WP_Customize_Section */ class Instructions_Section extends \WP_Customize_Section { /** * Type of this section. * * @var string */ public $type = 'hfg_instructions'; /** * Default options schema. * * @var array */ public $default_options = [ 'description' => '', 'image' => '', 'quickLinks' => [], 'builderMigrated' => false, ]; /** * Options passed to control. * * @var array */ public $options = []; /** * Gather the parameters passed to client JavaScript via JSON. * * @return array The array to be exported to the client as JSON. * @since 4.1.0 */ public function json() { $json = parent::json(); $json['options'] = wp_parse_args( $this->options, $this->default_options ); return $json; } /** * Render template. */ protected function render_template() { ?> <li id="accordion-section-{{ data.id }}" data-slug="{{data.id}}" class="control-section control-section-{{ data.type }} neve-quick-links"> </li> <?php } } range.php 0000666 00000012375 15226760543 0006377 0 ustar 00 <?php /** * The range value customize control. * * @package Neve/Customizer/Controls * @soundtrack I Still Haven't Found What I'm Looking For - U2 ( manily the sense of _js ) */ namespace Neve\Customizer\Controls; /** * Class Customizer_Range_Value_Control * * @package Neve\Customizer\Controls */ class Range extends \WP_Customize_Control { /** * Control type * * @var string */ public $type = 'range-value'; /** * Enable media queries * * @var bool */ public $media_query = false; /** * Settings for range inputs. * * @var array */ public $input_attr = array(); /** * Step size. * * @var string */ public $step = ''; /** * Add/remove from fixed value flag * * @var bool */ public $sum_type = false; /** * Hide the responsive switches * * @var bool */ public $hide_responsive_switches = false; /** * Range constructor. * * @param \WP_Customize_Manager $manager Customize manager. * @param string $id Control id. * @param array $args Control arguments. */ public function __construct( $manager, $id, $args = array() ) { parent::__construct( $manager, $id, $args ); $this->args_to_props( $args ); } /** * Handles input value. * * @return array */ public function json() { $json = parent::json(); $json['value'] = json_decode( $this->value(), true ); $json['link'] = $this->get_link(); $json['media_query'] = $this->media_query; $json['step'] = $this->step; $json['sum_type'] = $this->sum_type; $json['inputAttr'] = $this->input_attr; $json['hide_responsive_switches'] = $this->hide_responsive_switches; return $json; } /** * Render the title for the control. */ private function render_title() { ?> <# if ( data.label ) { #> <span class="customize-control-title"> <span>{{ data.label }}</span> <# if ( data.description ) { #> <i class="dashicons dashicons-editor-help" style="vertical-align: text-bottom;" title="{{ data.description }}"></i> <# } #> </span> <# if( data.media_query === true && data.hide_responsive_switches === false ) { #> <?php $this->render_responsive_switches(); ?> <# } #> <# } #> <?php } /** * Render the responsive switches. */ private function render_responsive_switches() { ?> <ul class="responsive-switchers"> <li class="desktop"> <button type="button" class="preview-desktop active" data-device="desktop"> <i class="dashicons dashicons-desktop"></i> </button> </li> <li class="tablet"> <button type="button" class="preview-tablet" data-device="tablet"> <i class="dashicons dashicons-tablet"></i> </button> </li> <li class="mobile"> <button type="button" class="preview-mobile" data-device="mobile"> <i class="dashicons dashicons-smartphone"></i> </button> </li> </ul> <?php } /** * Render the input. */ private function render_input() { ?> <# var type = data.sum_type ? 'text' : 'number'; var value = data.value ? data.value[mediaQuery] : attr.default; if( ! data.media_query ) { value = data.value? data.value : attr.default } var active = mediaQuery === 'desktop' ? 'active' : ''; if( data.sum_type ) { value = '+' + value; } #> <div class="{{mediaQuery}} control-wrap {{active}}"> <input class="range-slider__range" type="range" min="{{attr.min}}" max="{{attr.max}}" step="{{data.step}}" data-query="{{mediaQuery}}" data-default="{{attr.default}}" value="{{ value }}" > <input <# if( data.sum_type ) { #> readonly <# } #> class="range-slider-value" type="{{type}}" title="{{data.label}}" min="{{attr.min}}" max="{{attr.max}}" step="{{data.step}}" value="{{ value }}" > <span class="range-reset-slider"><span class="dashicons dashicons-image-rotate"></span></span> </div> <?php } /** * Render the control's content. */ protected function content_template() { $this->render_title(); ?> <# var wrapClass = data.media_query ? 'has-media-queries' : ''; #> <div class="range-slider {{wrapClass}}"> <# if( data.media_query === true ) { #> <# _.each( data.inputAttr, function( attr, mediaQuery ) { #> <?php $this->render_input(); ?> <# } ) #> <# } else { var mediaQuery = 'desktop'; var attr = data.inputAttr; #> <?php $this->render_input(); ?> <# } #> <input type="hidden" class="range-collector" title="{{data.label}}" value="{{data.value}}" {{{data.link}}} <?php // phpcs:ignore WordPressVIPMinimum.Security.Mustache.OutputNotation ?> > <?php } /** * Transform arguments to object properties */ private function args_to_props( $args ) { if ( ! empty( $args['input_attr'] ) ) { $this->input_attr = $args['input_attr']; } if ( ! empty( $args['media_query'] ) ) { $this->media_query = (bool) $args['media_query']; } if ( ! isset( $this->input_attr['mobile'] ) || ! isset( $this->input_attr['tablet'] ) || ! isset( $this->input_attr['desktop'] ) ) { $this->media_query = false; } if ( ! empty( $args['sum_type'] ) ) { $this->sum_type = $args['sum_type']; } if ( ! empty( $args['step'] ) ) { $this->step = $args['step']; } } } simple_upsell.php 0000666 00000002411 15226760543 0010146 0 ustar 00 <?php /** * Simple upsell control. * * @package Neve */ namespace Neve\Customizer\Controls; /** * Simple Upsell Control. * * @since 2.8.3 * @access public */ class Simple_Upsell extends \WP_Customize_Control { /** * The type of customize control being rendered. * * @since 2.8.3 * @var string */ public $type = 'nv_simple_upsell'; /** * Button text. * * @since 2.8.3 * @var string */ public $button_text = ''; /** * Button link. * * @since 2.8.3 * @var string */ public $link = ''; /** * List of features. * * @since 2.8.3 * @var string */ public $text = ''; /** * Render Method * * @return void */ public function render_content() { ?> <div class="nv-simple-upsell"> <?php if ( ! empty( $this->text ) ) { ?> <p><?php echo esc_html( $this->text ); ?></p> <?php } ?> <?php if ( ! empty( $this->link ) && ! empty( $this->button_text ) ) { ?> <a target="_blank" rel="external noreferrer noopener" href="<?php echo esc_url( $this->link ); ?>" class='button button-secondary'> <?php echo esc_html( $this->button_text ); ?> <span class="components-visually-hidden"><?php echo esc_html__( '(opens in a new tab)', 'neve' ); ?></span> </a> <?php } ?> </div> <?php } } button.php 0000666 00000006010 15226760543 0006603 0 ustar 00 <?php /** * Customizer functionality for the Blog settings panel. * * @package Neve\Customizer\Controls * @since 1.0.0 */ namespace Neve\Customizer\Controls; /** * A customizer control to display text in customizer. * * @since 1.0.0 */ class Button extends \WP_Customize_Control { /** * Control id * * @var string $id Control id. */ public $id = ''; /** * Button class. * * @var mixed|string */ public $button_class = ''; /** * Icon class. * * @var mixed|string */ public $icon_class = ''; /** * Button text. * * @var mixed|string */ public $button_text = ''; /** * Text before. * * @var mixed|string */ public $text_before = ''; /** * Text after. * * @var mixed|string */ public $text_after = ''; /** * Is Button. * * @var bool */ public $is_button = true; /** * Control to focus. * * @var string */ public $control_to_focus = ''; /** * Shortcut. * * @var bool */ public $shortcut = false; /** * Constructor. * * @param \WP_Customize_Manager $manager Customizer manager. * @param string $id Control id. * @param array $args Argument. */ public function __construct( $manager, $id, $args = array() ) { parent::__construct( $manager, $id, $args ); $this->id = $id; } /** * Render content for the control. * * @since 1.0.0 */ public function render_content() { if ( empty( $this->button_text ) ) { return; } $control = $this->is_button ? '' : '<p>'; if ( ! empty( $this->text_before ) ) { $control .= wp_kses_post( $this->text_before ) . ' '; } $control .= $this->is_button ? '<button ' : '<a '; if ( $this->control_to_focus ) { $control .= 'data-control-to-focus="' . esc_attr( $this->control_to_focus ) . '"'; } $control .= ' class="' . esc_attr( $this->get_button_classes() ) . '"'; $control .= $this->is_button ? ' style="display: flex; align-items: center;"' : ' style="cursor:pointer;"'; $control .= '>'; $control .= $this->get_icon(); $control .= esc_html( $this->button_text ); $control .= $this->is_button ? '</button>' : '</a>'; if ( ! empty( $this->text_after ) ) { $control .= wp_kses_post( $this->text_after ); } if ( $this->is_button ) { $control .= '</p>'; } echo $control; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** * Get the icon. * * @return string */ private function get_icon() { if ( empty( $this->icon_class ) ) { return ''; } return '<i class="dashicons dashicons-' . esc_attr( $this->icon_class ) . '" style="margin-right: 10px"></i>'; } /** * Get the button classes. * * @return string */ private function get_button_classes() { $classes = ''; if ( $this->is_button ) { $classes .= 'button button-secondary'; } if ( $this->shortcut ) { $classes .= ' menu-shortcut '; } if ( $this->button_class ) { $classes .= $this->button_class; } if ( $this->control_to_focus ) { $classes .= ' neve-control-focus'; } return $classes; } } elFinderVolumeLocalFileSystem.class.php 0000666 00000136366 15226760543 0014316 0 ustar 00 <?php // Implement similar functionality in PHP 5.2 or 5.3 // http://php.net/manual/class.recursivecallbackfilteriterator.php#110974 if (!class_exists('RecursiveCallbackFilterIterator', false)) { class RecursiveCallbackFilterIterator extends RecursiveFilterIterator { private $callback; public function __construct(RecursiveIterator $iterator, $callback) { $this->callback = $callback; parent::__construct($iterator); } public function accept() { return call_user_func($this->callback, parent::current(), parent::key(), parent::getInnerIterator()); } public function getChildren() { return new self($this->getInnerIterator()->getChildren(), $this->callback); } } } /** * elFinder driver for local filesystem. * * @author Dmitry (dio) Levashov * @author Troex Nevelin **/ class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver { /** * Driver id * Must be started from letter and contains [a-z0-9] * Used as part of volume id * * @var string **/ protected $driverId = 'l'; /** * Required to count total archive files size * * @var int **/ protected $archiveSize = 0; /** * Is checking stat owner * * @var boolean */ protected $statOwner = false; /** * Path to quarantine directory * * @var string */ private $quarantine; /** * Constructor * Extend options with required fields * * @author Dmitry (dio) Levashov */ public function __construct() { $this->options['alias'] = ''; // alias to replace root dir name $this->options['dirMode'] = 0755; // new dirs mode $this->options['fileMode'] = 0644; // new files mode $this->options['rootCssClass'] = 'elfinder-navbar-root-local'; $this->options['followSymLinks'] = true; $this->options['detectDirIcon'] = ''; // file name that is detected as a folder icon e.g. '.diricon.png' $this->options['keepTimestamp'] = array('copy', 'move'); // keep timestamp at inner filesystem allowed 'copy', 'move' and 'upload' $this->options['substituteImg'] = true; // support substitute image with dim command $this->options['statCorrector'] = null; // callable to correct stat data `function(&$stat, $path, $statOwner, $volumeDriveInstance){}` if (DIRECTORY_SEPARATOR === '/') { // Linux $this->options['acceptedName'] = '/^[^\.\/\x00][^\/\x00]*$/'; } else { // Windows $this->options['acceptedName'] = '/^[^\.\/\x00\\\:*?"<>|][^\/\x00\\\:*?"<>|]*$/'; } } /*********************************************************************/ /* INIT AND CONFIGURE */ /*********************************************************************/ /** * Prepare driver before mount volume. * Return true if volume is ready. * * @return bool **/ protected function init() { // Normalize directory separator for windows if (DIRECTORY_SEPARATOR !== '/') { foreach (array('path', 'tmbPath', 'tmpPath', 'quarantine') as $key) { if (!empty($this->options[$key])) { $this->options[$key] = str_replace('/', DIRECTORY_SEPARATOR, $this->options[$key]); } } // PHP >= 7.1 Supports UTF-8 path on Windows if (version_compare(PHP_VERSION, '7.1', '>=')) { $this->options['encoding'] = ''; $this->options['locale'] = ''; } } if (!$cwd = getcwd()) { return $this->setError('elFinder LocalVolumeDriver requires a result of getcwd().'); } // detect systemRoot if (!isset($this->options['systemRoot'])) { if ($cwd[0] === DIRECTORY_SEPARATOR || $this->root[0] === DIRECTORY_SEPARATOR) { $this->systemRoot = DIRECTORY_SEPARATOR; } else if (preg_match('/^([a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . ')/', $this->root, $m)) { $this->systemRoot = $m[1]; } else if (preg_match('/^([a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . ')/', $cwd, $m)) { $this->systemRoot = $m[1]; } } $this->root = $this->getFullPath($this->root, $cwd); if (!empty($this->options['startPath'])) { $this->options['startPath'] = $this->getFullPath($this->options['startPath'], $this->root); } if (is_null($this->options['syncChkAsTs'])) { $this->options['syncChkAsTs'] = true; } if (is_null($this->options['syncCheckFunc'])) { $this->options['syncCheckFunc'] = array($this, 'localFileSystemInotify'); } // check 'statCorrector' if (empty($this->options['statCorrector']) || !is_callable($this->options['statCorrector'])) { $this->options['statCorrector'] = null; } return true; } /** * Configure after successfull mount. * * @return void * @throws elFinderAbortException * @author Dmitry (dio) Levashov */ protected function configure() { $hiddens = array(); $root = $this->stat($this->root); // check thumbnails path if (!empty($this->options['tmbPath'])) { if (strpos($this->options['tmbPath'], DIRECTORY_SEPARATOR) === false) { $hiddens['tmb'] = $this->options['tmbPath']; $this->options['tmbPath'] = $this->_abspath($this->options['tmbPath']); } else { $this->options['tmbPath'] = $this->_normpath($this->options['tmbPath']); } } // check temp path if (!empty($this->options['tmpPath'])) { if (strpos($this->options['tmpPath'], DIRECTORY_SEPARATOR) === false) { $hiddens['temp'] = $this->options['tmpPath']; $this->options['tmpPath'] = $this->_abspath($this->options['tmpPath']); } else { $this->options['tmpPath'] = $this->_normpath($this->options['tmpPath']); } } // check quarantine path $_quarantine = ''; if (!empty($this->options['quarantine'])) { if (strpos($this->options['quarantine'], DIRECTORY_SEPARATOR) === false) { $_quarantine = $this->_abspath($this->options['quarantine']); $this->options['quarantine'] = ''; } else { $this->options['quarantine'] = $this->_normpath($this->options['quarantine']); } } else { $_quarantine = $this->_abspath('.quarantine'); } is_dir($_quarantine) && self::localRmdirRecursive($_quarantine); parent::configure(); // check tmbPath if (!$this->tmbPath && isset($hiddens['tmb'])) { unset($hiddens['tmb']); } // if no thumbnails url - try detect it if ($root['read'] && !$this->tmbURL && $this->URL) { if (strpos($this->tmbPath, $this->root) === 0) { $this->tmbURL = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($this->tmbPath, strlen($this->root) + 1)); if (preg_match("|[^/?&=]$|", $this->tmbURL)) { $this->tmbURL .= '/'; } } } // set $this->tmp by options['tmpPath'] $this->tmp = ''; if (!empty($this->options['tmpPath'])) { if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'], $this->options['dirMode'], true)) && is_writable($this->options['tmpPath'])) { $this->tmp = $this->options['tmpPath']; } else { if (isset($hiddens['temp'])) { unset($hiddens['temp']); } } } if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) { $this->tmp = $tmp; } // check quarantine dir $this->quarantine = ''; if (!empty($this->options['quarantine'])) { if ((is_dir($this->options['quarantine']) || mkdir($this->options['quarantine'], $this->options['dirMode'], true)) && is_writable($this->options['quarantine'])) { $this->quarantine = $this->options['quarantine']; } else { if (isset($hiddens['quarantine'])) { unset($hiddens['quarantine']); } } } else if ($_path = elFinder::getCommonTempPath()) { $this->quarantine = $_path; } if (!$this->quarantine) { if (!$this->tmp) { $this->archivers['extract'] = array(); $this->disabled[] = 'extract'; } else { $this->quarantine = $this->tmp; } } if ($hiddens) { foreach ($hiddens as $hidden) { $this->attributes[] = array( 'pattern' => '~^' . preg_quote(DIRECTORY_SEPARATOR . $hidden, '~') . '$~', 'read' => false, 'write' => false, 'locked' => true, 'hidden' => true ); } } if (!empty($this->options['keepTimestamp'])) { $this->options['keepTimestamp'] = array_flip($this->options['keepTimestamp']); } $this->statOwner = (!empty($this->options['statOwner'])); // enable WinRemoveTailDots plugin on Windows server if (DIRECTORY_SEPARATOR !== '/') { if (!isset($this->options['plugin'])) { $this->options['plugin'] = array(); } $this->options['plugin']['WinRemoveTailDots'] = array('enable' => true); } } /** * Long pooling sync checker * This function require server command `inotifywait` * If `inotifywait` need full path, Please add `define('ELFINER_INOTIFYWAIT_PATH', '/PATH_TO/inotifywait');` into connector.php * * @param string $path * @param int $standby * @param number $compare * * @return number|bool * @throws elFinderAbortException */ public function localFileSystemInotify($path, $standby, $compare) { if (isset($this->sessionCache['localFileSystemInotify_disable'])) { return false; } $path = realpath($path); $mtime = filemtime($path); if (!$mtime) { return false; } if ($mtime != $compare) { return $mtime; } $inotifywait = defined('ELFINER_INOTIFYWAIT_PATH') ? ELFINER_INOTIFYWAIT_PATH : 'inotifywait'; $standby = max(1, intval($standby)); $cmd = $inotifywait . ' ' . escapeshellarg($path) . ' -t ' . $standby . ' -e moved_to,moved_from,move,close_write,delete,delete_self'; $this->procExec($cmd, $o, $r); if ($r === 0) { // changed clearstatcache(); if (file_exists($path)) { $mtime = filemtime($path); // error on busy? return $mtime ? $mtime : time(); } else { // target was removed return 0; } } else if ($r === 2) { // not changed (timeout) return $compare; } // error // cache to $_SESSION $this->sessionCache['localFileSystemInotify_disable'] = true; $this->session->set($this->id, $this->sessionCache); return false; } /*********************************************************************/ /* FS API */ /*********************************************************************/ /*********************** paths/urls *************************/ /** * Return parent directory path * * @param string $path file path * * @return string * @author Dmitry (dio) Levashov **/ protected function _dirname($path) { return dirname($path); } /** * Return file name * * @param string $path file path * * @return string * @author Dmitry (dio) Levashov **/ protected function _basename($path) { return basename($path); } /** * Join dir name and file name and retur full path * * @param string $dir * @param string $name * * @return string * @author Dmitry (dio) Levashov **/ protected function _joinPath($dir, $name) { $dir = rtrim($dir, DIRECTORY_SEPARATOR); $path = realpath($dir . DIRECTORY_SEPARATOR . $name); // realpath() returns FALSE if the file does not exist if ($path === false || strpos($path, $this->root) !== 0) { if (DIRECTORY_SEPARATOR !== '/') { $dir = str_replace('/', DIRECTORY_SEPARATOR, $dir); $name = str_replace('/', DIRECTORY_SEPARATOR, $name); } // Directory traversal measures if (strpos($dir, '..' . DIRECTORY_SEPARATOR) !== false || substr($dir, -2) == '..') { $dir = $this->root; } if (strpos($name, '..' . DIRECTORY_SEPARATOR) !== false) { $name = basename($name); } $path = $dir . DIRECTORY_SEPARATOR . $name; } return $path; } /** * Return normalized path, this works the same as os.path.normpath() in Python * * @param string $path path * * @return string * @author Troex Nevelin **/ protected function _normpath($path) { if (empty($path)) { return '.'; } $changeSep = (DIRECTORY_SEPARATOR !== '/'); if ($changeSep) { $drive = ''; if (preg_match('/^([a-zA-Z]:)(.*)/', $path, $m)) { $drive = $m[1]; $path = $m[2] ? $m[2] : '/'; } $path = str_replace(DIRECTORY_SEPARATOR, '/', $path); } if (strpos($path, '/') === 0) { $initial_slashes = true; } else { $initial_slashes = false; } if (($initial_slashes) && (strpos($path, '//') === 0) && (strpos($path, '///') === false)) { $initial_slashes = 2; } $initial_slashes = (int)$initial_slashes; $comps = explode('/', $path); $new_comps = array(); foreach ($comps as $comp) { if (in_array($comp, array('', '.'))) { continue; } if (($comp != '..') || (!$initial_slashes && !$new_comps) || ($new_comps && (end($new_comps) == '..'))) { array_push($new_comps, $comp); } elseif ($new_comps) { array_pop($new_comps); } } $comps = $new_comps; $path = implode('/', $comps); if ($initial_slashes) { $path = str_repeat('/', $initial_slashes) . $path; } if ($changeSep) { $path = $drive . str_replace('/', DIRECTORY_SEPARATOR, $path); } return $path ? $path : '.'; } /** * Return file path related to root dir * * @param string $path file path * * @return string * @author Dmitry (dio) Levashov **/ protected function _relpath($path) { if ($path === $this->root) { return ''; } else { if (strpos($path, $this->root) === 0) { return ltrim(substr($path, strlen($this->root)), DIRECTORY_SEPARATOR); } else { // for link return $path; } } } /** * Convert path related to root dir into real path * * @param string $path file path * * @return string * @author Dmitry (dio) Levashov **/ protected function _abspath($path) { if ($path === DIRECTORY_SEPARATOR) { return $this->root; } else { $path = $this->_normpath($path); if (strpos($path, $this->systemRoot) === 0) { return $path; } else if (DIRECTORY_SEPARATOR !== '/' && preg_match('/^[a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . '/', $path)) { return $path; } else { return $this->_joinPath($this->root, $path); } } } /** * Return fake path started from root dir * * @param string $path file path * * @return string * @author Dmitry (dio) Levashov **/ protected function _path($path) { return $this->rootName . ($path == $this->root ? '' : $this->separator . $this->_relpath($path)); } /** * Return true if $path is children of $parent * * @param string $path path to check * @param string $parent parent path * * @return bool * @author Dmitry (dio) Levashov **/ protected function _inpath($path, $parent) { $cwd = getcwd(); $real_path = $this->getFullPath($path, $cwd); $real_parent = $this->getFullPath($parent, $cwd); if ($real_path && $real_parent) { return $real_path === $real_parent || strpos($real_path, rtrim($real_parent, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR) === 0; } return false; } /***************** file stat ********************/ /** * Return stat for given path. * Stat contains following fields: * - (int) size file size in b. required * - (int) ts file modification time in unix time. required * - (string) mime mimetype. required for folders, others - optionally * - (bool) read read permissions. required * - (bool) write write permissions. required * - (bool) locked is object locked. optionally * - (bool) hidden is object hidden. optionally * - (string) alias for symlinks - link target path relative to root path. optionally * - (string) target for symlinks - link target path. optionally * If file does not exists - returns empty array or false. * * @param string $path file path * * @return array|false * @author Dmitry (dio) Levashov **/ protected function _stat($path) { $stat = array(); if (!file_exists($path) && !is_link($path)) { return $stat; } //Verifies the given path is the root or is inside the root. Prevents directory traveral. if (!$this->_inpath($path, $this->root)) { return $stat; } $stat['isowner'] = false; $linkreadable = false; if ($path != $this->root && is_link($path)) { if (!$this->options['followSymLinks']) { return array(); } if (!($target = $this->readlink($path)) || $target == $path) { if (is_null($target)) { $stat = array(); return $stat; } else { $stat['mime'] = 'symlink-broken'; $target = readlink($path); $lstat = lstat($path); $ostat = $this->getOwnerStat($lstat['uid'], $lstat['gid']); $linkreadable = !empty($ostat['isowner']); } } $stat['alias'] = $this->_path($target); $stat['target'] = $target; } $readable = is_readable($path); if ($readable) { $size = sprintf('%u', filesize($path)); $stat['ts'] = filemtime($path); if ($this->statOwner) { $fstat = stat($path); $uid = $fstat['uid']; $gid = $fstat['gid']; $stat['perm'] = substr((string)decoct($fstat['mode']), -4); $stat = array_merge($stat, $this->getOwnerStat($uid, $gid)); } } if (($dir = is_dir($path)) && $this->options['detectDirIcon']) { $favicon = $path . DIRECTORY_SEPARATOR . $this->options['detectDirIcon']; if ($this->URL && file_exists($favicon)) { $stat['icon'] = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($favicon, strlen($this->root) + 1)); } } if (!isset($stat['mime'])) { $stat['mime'] = $dir ? 'directory' : $this->mimetype($path); } //logical rights first $stat['read'] = ($linkreadable || $readable) ? null : false; $stat['write'] = is_writable($path) ? null : false; if (is_null($stat['read'])) { if ($dir) { $stat['size'] = 0; } else if (isset($size)) { $stat['size'] = $size; } } if ($this->options['statCorrector']) { call_user_func_array($this->options['statCorrector'], array(&$stat, $path, $this->statOwner, $this)); } return $stat; } /** * Get stat `owner`, `group` and `isowner` by `uid` and `gid` * Sub-fuction of _stat() and _scandir() * * @param integer $uid * @param integer $gid * * @return array stat */ protected function getOwnerStat($uid, $gid) { static $names = null; static $phpuid = null; if (is_null($names)) { $names = array('uid' => array(), 'gid' => array()); } if (is_null($phpuid)) { if (is_callable('posix_getuid')) { $phpuid = posix_getuid(); } else { $phpuid = 0; } } $stat = array(); if ($uid) { $stat['isowner'] = ($phpuid == $uid); if (isset($names['uid'][$uid])) { $stat['owner'] = $names['uid'][$uid]; } else if (is_callable('posix_getpwuid')) { $pwuid = posix_getpwuid($uid); $stat['owner'] = $names['uid'][$uid] = $pwuid['name']; } else { $stat['owner'] = $names['uid'][$uid] = $uid; } } if ($gid) { if (isset($names['gid'][$gid])) { $stat['group'] = $names['gid'][$gid]; } else if (is_callable('posix_getgrgid')) { $grgid = posix_getgrgid($gid); $stat['group'] = $names['gid'][$gid] = $grgid['name']; } else { $stat['group'] = $names['gid'][$gid] = $gid; } } return $stat; } /** * Return true if path is dir and has at least one childs directory * * @param string $path dir path * * @return bool * @author Dmitry (dio) Levashov **/ protected function _subdirs($path) { $dirs = false; if (is_dir($path) && is_readable($path)) { if (class_exists('FilesystemIterator', false)) { $dirItr = new ParentIterator( new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS | FilesystemIterator::CURRENT_AS_SELF | (defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') ? RecursiveDirectoryIterator::FOLLOW_SYMLINKS : 0) ) ); $dirItr->rewind(); if ($dirItr->hasChildren()) { $dirs = true; $name = $dirItr->getSubPathName(); while ($dirItr->valid()) { if (!$this->attr($path . DIRECTORY_SEPARATOR . $name, 'read', null, true)) { $dirs = false; $dirItr->next(); $name = $dirItr->getSubPathName(); continue; } $dirs = true; break; } } } else { $path = strtr($path, array('[' => '\\[', ']' => '\\]', '*' => '\\*', '?' => '\\?')); return (bool)glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR); } } return $dirs; } /** * Return object width and height * Usualy used for images, but can be realize for video etc... * * @param string $path file path * @param string $mime file mime type * * @return string * @author Dmitry (dio) Levashov **/ protected function _dimensions($path, $mime) { clearstatcache(); return strpos($mime, 'image') === 0 && is_readable($path) && filesize($path) && ($s = getimagesize($path)) !== false ? $s[0] . 'x' . $s[1] : false; } /******************** file/dir content *********************/ /** * Return symlink target file * * @param string $path link path * * @return string * @author Dmitry (dio) Levashov **/ protected function readlink($path) { if (!($target = readlink($path))) { return null; } if (strpos($target, $this->systemRoot) !== 0) { $target = $this->_joinPath(dirname($path), $target); } if (!file_exists($target)) { return false; } return $target; } /** * Return files list in directory. * * @param string $path dir path * * @return array * @throws elFinderAbortException * @author Dmitry (dio) Levashov */ protected function _scandir($path) { elFinder::checkAborted(); $files = array(); $cache = array(); $dirWritable = is_writable($path); $dirItr = array(); $followSymLinks = $this->options['followSymLinks']; try { $dirItr = new DirectoryIterator($path); } catch (UnexpectedValueException $e) { } foreach ($dirItr as $file) { try { if ($file->isDot()) { continue; } $files[] = $fpath = $file->getPathname(); $br = false; $stat = array(); $stat['isowner'] = false; $linkreadable = false; if ($file->isLink()) { if (!$followSymLinks) { continue; } if (!($target = $this->readlink($fpath)) || $target == $fpath) { if (is_null($target)) { $stat = array(); $br = true; } else { $_path = $fpath; $stat['mime'] = 'symlink-broken'; $target = readlink($_path); $lstat = lstat($_path); $ostat = $this->getOwnerStat($lstat['uid'], $lstat['gid']); $linkreadable = !empty($ostat['isowner']); $dir = false; $stat['alias'] = $this->_path($target); $stat['target'] = $target; } } else { $dir = is_dir($target); $stat['alias'] = $this->_path($target); $stat['target'] = $target; $stat['mime'] = $dir ? 'directory' : $this->mimetype($stat['alias']); } } else { if (($dir = $file->isDir()) && $this->options['detectDirIcon']) { $path = $file->getPathname(); $favicon = $path . DIRECTORY_SEPARATOR . $this->options['detectDirIcon']; if ($this->URL && file_exists($favicon)) { $stat['icon'] = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($favicon, strlen($this->root) + 1)); } } $stat['mime'] = $dir ? 'directory' : $this->mimetype($fpath); } $size = sprintf('%u', $file->getSize()); $stat['ts'] = $file->getMTime(); if (!$br) { if ($this->statOwner && !$linkreadable) { $uid = $file->getOwner(); $gid = $file->getGroup(); $stat['perm'] = substr((string)decoct($file->getPerms()), -4); $stat = array_merge($stat, $this->getOwnerStat($uid, $gid)); } //logical rights first $stat['read'] = ($linkreadable || $file->isReadable()) ? null : false; $stat['write'] = $file->isWritable() ? null : false; $stat['locked'] = $dirWritable ? null : true; if (is_null($stat['read'])) { $stat['size'] = $dir ? 0 : $size; } if ($this->options['statCorrector']) { call_user_func_array($this->options['statCorrector'], array(&$stat, $fpath, $this->statOwner, $this)); } } $cache[] = array($fpath, $stat); } catch (RuntimeException $e) { continue; } } if ($cache) { $cache = $this->convEncOut($cache, false); foreach ($cache as $d) { $this->updateCache($d[0], $d[1]); } } return $files; } /** * Open file and return file pointer * * @param string $path file path * @param string $mode * * @return false|resource * @internal param bool $write open file for writing * @author Dmitry (dio) Levashov */ protected function _fopen($path, $mode = 'rb') { return fopen($path, $mode); } /** * Close opened file * * @param resource $fp file pointer * @param string $path * * @return bool * @author Dmitry (dio) Levashov */ protected function _fclose($fp, $path = '') { return (is_resource($fp) && fclose($fp)); } /******************** file/dir manipulations *************************/ /** * Create dir and return created dir path or false on failed * * @param string $path parent dir path * @param string $name new directory name * * @return string|bool * @author Dmitry (dio) Levashov **/ protected function _mkdir($path, $name) { $path = $this->_joinPath($path, $name); if (mkdir($path)) { chmod($path, $this->options['dirMode']); return $path; } return false; } /** * Create file and return it's path or false on failed * * @param string $path parent dir path * @param string $name new file name * * @return string|bool * @author Dmitry (dio) Levashov **/ protected function _mkfile($path, $name) { $path = $this->_joinPath($path, $name); if (($fp = fopen($path, 'w'))) { fclose($fp); chmod($path, $this->options['fileMode']); return $path; } return false; } /** * Create symlink * * @param string $source file to link to * @param string $targetDir folder to create link in * @param string $name symlink name * * @return bool * @author Dmitry (dio) Levashov **/ protected function _symlink($source, $targetDir, $name) { return $this->localFileSystemSymlink($source, $this->_joinPath($targetDir, $name)); } /** * Copy file into another file * * @param string $source source file path * @param string $targetDir target directory path * @param string $name new file name * * @return bool * @author Dmitry (dio) Levashov **/ protected function _copy($source, $targetDir, $name) { $mtime = filemtime($source); $target = $this->_joinPath($targetDir, $name); if ($ret = copy($source, $target)) { isset($this->options['keepTimestamp']['copy']) && $mtime && touch($target, $mtime); } return $ret; } /** * Move file into another parent dir. * Return new file path or false. * * @param string $source source file path * @param $targetDir * @param string $name file name * * @return bool|string * @internal param string $target target dir path * @author Dmitry (dio) Levashov */ protected function _move($source, $targetDir, $name) { $mtime = filemtime($source); $target = $this->_joinPath($targetDir, $name); if ($ret = rename($source, $target) ? $target : false) { isset($this->options['keepTimestamp']['move']) && $mtime && touch($target, $mtime); } return $ret; } /** * Remove file * * @param string $path file path * * @return bool * @author Dmitry (dio) Levashov **/ protected function _unlink($path) { return is_file($path) && unlink($path); } /** * Remove dir * * @param string $path dir path * * @return bool * @author Dmitry (dio) Levashov **/ protected function _rmdir($path) { return rmdir($path); } /** * Create new file and write into it from file pointer. * Return new file path or false on error. * * @param resource $fp file pointer * @param string $dir target dir path * @param string $name file name * @param array $stat file stat (required by some virtual fs) * * @return bool|string * @author Dmitry (dio) Levashov **/ protected function _save($fp, $dir, $name, $stat) { $path = $this->_joinPath($dir, $name); $meta = stream_get_meta_data($fp); $uri = isset($meta['uri']) ? $meta['uri'] : ''; if ($uri && !preg_match('#^[a-zA-Z0-9]+://#', $uri) && !is_link($uri)) { fclose($fp); $mtime = filemtime($uri); $isCmdPaste = ($this->ARGS['cmd'] === 'paste'); $isCmdCopy = ($isCmdPaste && empty($this->ARGS['cut'])); if (($isCmdCopy || !rename($uri, $path)) && !copy($uri, $path)) { return false; } // keep timestamp on upload if ($mtime && $this->ARGS['cmd'] === 'upload') { touch($path, isset($this->options['keepTimestamp']['upload']) ? $mtime : time()); } } else { if (file_put_contents($path, $fp, LOCK_EX) === false) { return false; } } chmod($path, $this->options['fileMode']); return $path; } /** * Get file contents * * @param string $path file path * * @return string|false * @author Dmitry (dio) Levashov **/ protected function _getContents($path) { return file_get_contents($path); } /** * Write a string to a file * * @param string $path file path * @param string $content new file content * * @return bool * @author Dmitry (dio) Levashov **/ protected function _filePutContents($path, $content) { return (file_put_contents($path, $content, LOCK_EX) !== false); } /** * Detect available archivers * * @return void * @throws elFinderAbortException */ protected function _checkArchivers() { $this->archivers = $this->getArchivers(); return; } /** * chmod availability * * @param string $path * @param string $mode * * @return bool */ protected function _chmod($path, $mode) { $modeOct = is_string($mode) ? octdec($mode) : octdec(sprintf("%04o", $mode)); return chmod($path, $modeOct); } /** * Recursive symlinks search * * @param string $path file/dir path * * @return bool * @throws Exception * @author Dmitry (dio) Levashov */ protected function _findSymlinks($path) { return self::localFindSymlinks($path); } /** * Extract files from archive * * @param string $path archive path * @param array $arc archiver command and arguments (same as in $this->archivers) * * @return array|string|boolean * @throws elFinderAbortException * @author Dmitry (dio) Levashov, * @author Alexey Sukhotin */ protected function _extract($path, $arc) { if ($this->quarantine) { $dir = $this->quarantine . DIRECTORY_SEPARATOR . md5(basename($path) . mt_rand()); $archive = (isset($arc['toSpec']) || $arc['cmd'] === 'phpfunction') ? '' : $dir . DIRECTORY_SEPARATOR . basename($path); if (!mkdir($dir)) { return false; } // insurance unexpected shutdown register_shutdown_function(array($this, 'rmdirRecursive'), realpath($dir)); chmod($dir, 0777); // copy in quarantine if (!is_readable($path) || ($archive && !copy($path, $archive))) { return false; } // extract in quarantine try { $this->unpackArchive($path, $arc, $archive ? true : $dir); } catch(Exception $e) { return $this->setError($e->getMessage()); } // get files list try { $ls = self::localScandir($dir); } catch (Exception $e) { return false; } // no files - extract error ? if (empty($ls)) { return false; } $this->archiveSize = 0; // find symlinks and check extracted items $checkRes = $this->checkExtractItems($dir); if ($checkRes['symlinks']) { self::localRmdirRecursive($dir); return $this->setError(array_merge($this->error, array(elFinder::ERROR_ARC_SYMLINKS))); } $this->archiveSize = $checkRes['totalSize']; if ($checkRes['rmNames']) { foreach ($checkRes['rmNames'] as $name) { $this->addError(elFinder::ERROR_SAVE, $name); } } // check max files size if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $this->archiveSize) { $this->delTree($dir); return $this->setError(elFinder::ERROR_ARC_MAXSIZE); } $extractTo = $this->extractToNewdir; // 'auto', ture or false // archive contains one item - extract in archive dir $name = ''; $src = $dir . DIRECTORY_SEPARATOR . $ls[0]; if (($extractTo === 'auto' || !$extractTo) && count($ls) === 1 && is_file($src)) { $name = $ls[0]; } else if ($extractTo === 'auto' || $extractTo) { // for several files - create new directory // create unique name for directory $src = $dir; $splits = elFinder::splitFileExtention(basename($path)); $name = $splits[0]; $test = dirname($path) . DIRECTORY_SEPARATOR . $name; if (file_exists($test) || is_link($test)) { $name = $this->uniqueName(dirname($path), $name, '-', false); } } if ($name !== '') { $result = dirname($path) . DIRECTORY_SEPARATOR . $name; if (!rename($src, $result)) { $this->delTree($dir); return false; } } else { $dstDir = dirname($path); $result = array(); foreach ($ls as $name) { $target = $dstDir . DIRECTORY_SEPARATOR . $name; if (self::localMoveRecursive($dir . DIRECTORY_SEPARATOR . $name, $target, true, $this->options['copyJoin'])) { $result[] = $target; } } if (!$result) { $this->delTree($dir); return false; } } is_dir($dir) && $this->delTree($dir); return (is_array($result) || file_exists($result)) ? $result : false; } //TODO: Add return statement here return false; } /** * Create archive and return its path * * @param string $dir target dir * @param array $files files names list * @param string $name archive name * @param array $arc archiver options * * @return string|bool * @throws elFinderAbortException * @author Dmitry (dio) Levashov, * @author Alexey Sukhotin */ protected function _archive($dir, $files, $name, $arc) { return $this->makeArchive($dir, $files, $name, $arc); } /******************** Over write functions *************************/ /** * File path of local server side work file path * * @param string $path * * @return string * @author Naoki Sawada */ protected function getWorkFile($path) { return $path; } /** * Delete dirctory trees * * @param string $localpath path need convert encoding to server encoding * * @return boolean * @throws elFinderAbortException * @author Naoki Sawada */ protected function delTree($localpath) { return $this->rmdirRecursive($localpath); } /** * Return fileinfo based on filename * For item ID based path file system * Please override if needed on each drivers * * @param string $path file cache * * @return array|boolean false */ protected function isNameExists($path) { $exists = file_exists($this->convEncIn($path)); // restore locale $this->convEncOut(); return $exists ? $this->stat($path) : false; } /******************** Over write (Optimized) functions *************************/ /** * Recursive files search * * @param string $path dir path * @param string $q search string * @param array $mimes * * @return array * @throws elFinderAbortException * @author Dmitry (dio) Levashov * @author Naoki Sawada */ protected function doSearch($path, $q, $mimes) { if (!empty($this->doSearchCurrentQuery['matchMethod']) || $this->encoding || !class_exists('FilesystemIterator', false)) { // has custom match method or non UTF-8, use elFinderVolumeDriver::doSearch() return parent::doSearch($path, $q, $mimes); } $result = array(); $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0; if ($timeout && $timeout < time()) { $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path))); return $result; } elFinder::extendTimeLimit($this->options['searchTimeout'] + 30); $match = array(); try { $iterator = new RecursiveIteratorIterator( new RecursiveCallbackFilterIterator( new RecursiveDirectoryIterator($path, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::SKIP_DOTS | ((defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') && $this->options['followSymLinks']) ? RecursiveDirectoryIterator::FOLLOW_SYMLINKS : 0) ), array($this, 'localFileSystemSearchIteratorFilter') ), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD ); foreach ($iterator as $key => $node) { if ($timeout && ($this->error || $timeout < time())) { !$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($node->getPath))); break; } if ($node->isDir()) { if ($this->stripos($node->getFilename(), $q) !== false) { $match[] = $key; } } else { $match[] = $key; } } } catch (Exception $e) { } if ($match) { foreach ($match as $p) { if ($timeout && ($this->error || $timeout < time())) { !$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode(dirname($p)))); break; } $stat = $this->stat($p); if (!$stat) { // invalid links continue; } if (!empty($stat['hidden']) || !$this->mimeAccepted($stat['mime'], $mimes)) { continue; } if ((!$mimes || $stat['mime'] !== 'directory')) { $stat['path'] = $this->path($stat['hash']); if ($this->URL && !isset($stat['url'])) { $_path = str_replace(DIRECTORY_SEPARATOR, '/', substr($p, strlen($this->root) + 1)); $stat['url'] = $this->URL . str_replace('%2F', '/', rawurlencode($_path)); } $result[] = $stat; } } } return $result; } /******************** Original local functions ************************ * * @param $file * @param $key * @param $iterator * * @return bool */ public function localFileSystemSearchIteratorFilter($file, $key, $iterator) { /* @var FilesystemIterator $file */ /* @var RecursiveDirectoryIterator $iterator */ $name = $file->getFilename(); if ($this->doSearchCurrentQuery['excludes']) { foreach ($this->doSearchCurrentQuery['excludes'] as $exclude) { if ($this->stripos($name, $exclude) !== false) { return false; } } } if ($iterator->hasChildren()) { if ($this->options['searchExDirReg'] && preg_match($this->options['searchExDirReg'], $key)) { return false; } return (bool)$this->attr($key, 'read', null, true); } return ($this->stripos($name, $this->doSearchCurrentQuery['q']) === false) ? false : true; } /** * Creates a symbolic link * * @param string $target The target * @param string $link The link * * @return boolean ( result of symlink() ) */ protected function localFileSystemSymlink($target, $link) { $res = false; if (function_exists('symlink') and is_callable('symlink')) { $errlev = error_reporting(); error_reporting($errlev ^ E_WARNING); if ($res = symlink(realpath($target), $link)) { $res = is_readable($link); } error_reporting($errlev); } return $res; } } // END class responsive_number.php 0000666 00000012450 15226760543 0011042 0 ustar 00 <?php /** * Responsive number input control. * * @package Neve\Customizer\Controls */ namespace Neve\Customizer\Controls; /** * A text control with validation for CSS units. */ class Responsive_Number extends \WP_Customize_Control { /** * Control type. * * @access public * @var string */ public $type = 'responsive-number'; /** * Responsive flag. * * @access public * @var bool */ public $responsive = true; /** * Allowed Units. * * @access public * @var array */ public $units = array(); /** * Settings for input. * * @var array */ public $input_attr = array(); /** * Responsive_Number constructor. * * @param \WP_Customize_Manager $manager Customize manager. * @param string $id Control id. * @param array $args Control arguments. */ public function __construct( $manager, $id, $args = array() ) { parent::__construct( $manager, $id, $args ); $this->args_to_props( $args ); } /** * Send the parameters via JSON. */ public function json() { $json = parent::json(); $json['default'] = $this->setting->default; if ( isset( $this->default ) ) { $json['default'] = $this->default; } $json['value'] = json_decode( $this->value(), true ); $json['link'] = $this->get_link(); $json['id'] = $this->id; $json['label'] = esc_html( $this->label ); $json['units'] = $this->units; $json['responsive'] = $this->responsive; $json['inputAttr'] = $this->input_attr; return $json; } /** * Render the control * * @access protected */ protected function content_template() { $this->render_title(); ?> <# var wrapClass = data.responsive ? 'has-media-queries' : ''; #> <# wrapClass += data.units.length ? '' : 'no-units'; #> <div class="responsive-number {{wrapClass}}"> <div class="controls--wrap"> <# if( data.responsive === true ) { #> <# _.each( data.inputAttr, function( attr, mediaQuery ) { #> <?php $this->render_input(); ?> <# } ) #> <# } else { var mediaQuery = 'desktop'; var attr = data.inputAttr; #> <?php $this->render_input(); ?> <# } #> <span class="reset-number-input"><span class="dashicons dashicons-image-rotate"></span></span> </div> <input type="hidden" class="responsive-number-collector" title="{{data.label}}" value="{{data.value}}" {{{data.link}}} <?php // phpcs:ignore WordPressVIPMinimum.Security.Mustache.OutputNotation ?> > </div> <?php } /** * Render the input. */ private function render_input() { ?> <# var value = data.value ? data.value[mediaQuery] : attr.default; var suffix = ''; if( data.value ) { suffix = data.value.suffix ? data.value.suffix[mediaQuery] : attr.default_unit; } if( ! data.responsive ) { value = data.value? data.value : attr.default } var active = mediaQuery === 'desktop' ? 'active' : ''; #> <div class="{{mediaQuery}} control-wrap {{active}}"> <input class="responsive-number--input <# if( ! data.units ){ #>no-units<# } #>" type="number" <# if( attr.min ) { #> min="{{attr.min}}" <# } if ( attr.max ) { #> max="{{attr.max}}" <# } #> data-query="{{mediaQuery}}" data-default="{{attr.default}}" value="{{ value }}" /> <# if( data.units.length ) { var disabled = data.units.length === 1 ? 'disabled' : ''; #> <select class="responsive-number--select" {{disabled}} data-default="{{attr.default_unit}}"> <# _.each( data.units, function( val ) { var defaultUnit = val === suffix ? 'selected="selected"' : ''; #> <option value="{{val}}" {{defaultUnit}}>{{val}}</option> <# } ) #> </select> <# } #> </div> <?php } /** * Render the title for the control. */ private function render_title() { ?> <# if ( data.label ) { #> <span class="customize-control-title" style="display: inline-block;"> <span>{{ data.label }}</span> <# if ( data.description ) { #> <i class="dashicons dashicons-editor-help" style="vertical-align: text-bottom;" title="{{ data.description }}"></i> <# } #> </span> <# if( data.responsive === true ) { #> <?php $this->render_responsive_switches(); ?> <# } #> <# } #> <?php } /** * Render the responsive switches. */ private function render_responsive_switches() { ?> <ul class="responsive-switchers"> <li class="desktop"> <button type="button" class="preview-desktop active" data-device="desktop"> <i class="dashicons dashicons-desktop"></i> </button> </li> <li class="tablet"> <button type="button" class="preview-tablet" data-device="tablet"> <i class="dashicons dashicons-tablet"></i> </button> </li> <li class="mobile"> <button type="button" class="preview-mobile" data-device="mobile"> <i class="dashicons dashicons-smartphone"></i> </button> </li> </ul> <?php } /** * Transform arguments to object properties */ private function args_to_props( $args ) { if ( ! empty( $args['input_attr'] ) ) { $this->input_attr = $args['input_attr']; } if ( ! empty( $args['media_query'] ) ) { $this->responsive = (bool) $args['responsive']; } if ( ! isset( $this->input_attr['mobile'] ) || ! isset( $this->input_attr['tablet'] ) || ! isset( $this->input_attr['desktop'] ) ) { $this->responsive = false; } } } checkbox.php 0000666 00000001530 15226760543 0007060 0 ustar 00 <?php /** * Customizer Heading. * * @since 1.0.0 * @package Neve\Customizer\Controls */ namespace Neve\Customizer\Controls; /** * Checkbox control */ class Checkbox extends \WP_Customize_Control { /** * The control type. * * @access public * @var string */ public $type = 'checkbox-toggle'; /** * Send to _js json. * * @return array */ public function json() { $json = parent::json(); $json['id'] = $this->id; $json['link'] = $this->get_link(); return $json; } /** * Render control. */ protected function content_template() { ?> <div class="checkbox-toggle-wrap"> <span>{{data.label}}</span> <input {{{data.link}}} type="checkbox" id="{{data.id}}"/><label for="{{data.id}}"></label> <?php // phpcs:ignore WordPressVIPMinimum.Security.Mustache.OutputNotation ?> </div> <?php } } radio_image.php 0000666 00000010776 15226760543 0007546 0 ustar 00 <?php /** * Radio image controls. * * Note, the `$choices` array is slightly different than normal and should be in the form of * `array( * $value => array( 'url' => $image_url, 'label' => $text_label ), * $value => array( 'url' => $image_url, 'label' => $text_label ), * )` * * @package Neve\Customizer\Controls */ namespace Neve\Customizer\Controls; /** * Class Radio_Image */ class Radio_Image extends \WP_Customize_Control { /** * The type of customize control being rendered. * * @since 1.0.0 * @access public * @var string */ public $type = 'radio-image'; /** * Flag to tell that this control is a tab * * @since 1.1.72 * @var bool */ public $is_tab = false; /** * Flag to tell that this control is a sub-tab in a tab * * @since 1.1.72 * @var bool */ public $is_subtab = false; /** * Controls in tabs. * * @since 1.1.72 * @var array */ public $controls; /** * Control data (tabs, names, icons, images) * * @since 1.1.72 * @var array */ public $choices; /** * Radio_Image constructor. * * @param \WP_Customize_Manager $manager Customizer manager object. * @param string $id Control id. * @param array $args Control arguments. */ public function __construct( \WP_Customize_Manager $manager, $id, array $args = array() ) { parent::__construct( $manager, $id, apply_filters( $id . '_filter_args', $args ) ); if ( ! empty( $args['is_tab'] ) && $args['is_tab'] === true ) { $this->is_tab = $args['is_tab']; if ( ! empty( $args['is_subtab'] ) && $args['is_subtab'] === true ) { $this->is_subtab = $args['is_subtab']; } if ( ! empty( $this->choices ) ) { foreach ( $this->choices as $value => $args ) { $this->controls[ $value ] = $args['controls']; } } } } /** * Loads the jQuery UI Button script and custom scripts/styles. * * @return void * @since 1.0.0 * @access public */ public function enqueue() { wp_enqueue_script( 'jquery-ui-button' ); } /** * Add custom JSON parameters to use in the JS template. * * @return array * @since 1.0.0 * @access public */ public function json() { $json = parent::json(); $json['is_tab'] = $this->is_tab; $json['is_subtab'] = $this->is_subtab; if ( $json['is_tab'] === true ) { $json['controls'] = $this->controls; } // We need to make sure we have the correct image URL. $json['choices'] = $this->choices; $json['width'] = 100; if ( ! empty( $this->choices ) ) { $json['width'] = number_format( 100 / count( $this->choices ), 2 ); } $json['id'] = $this->id; $json['link'] = $this->get_link(); $json['value'] = $this->value(); return $json; } /** * Underscore JS template to handle the control's output. * * @return void * @since 1.0.0 * @access public */ public function content_template() { ?> <# if ( ! data.choices ) { return; } #> <# if( !data.is_tab) {#> <# if ( data.label ) { #> <span class="customize-control-title">{{ data.label }}</span> <# } #> <# if ( data.description ) { #> <span class="description customize-control-description">{{{ data.description }}}</span> <?php // phpcs:ignore WordPressVIPMinimum.Security.Mustache.OutputNotation ?> <# } #> <#}#> <div class="buttonset <# if( data.is_tab) {#>customizer-tab <#}#> <# if( data.is_subtab) {#>customizer-subtab <#}#>"> <# for ( key in data.choices ) { #> <input <# if( data.is_tab) {#>data-controls="{{data.controls[key]}}"<#}#> type="radio" value="{{ key }}" name="_customize-{{ data.type }}-{{ data.id }}" id="{{ data.id }}-{{ key }}" <# if ( key === data.value && ( !data.is_tab || data.is_subtab) ) { #> checked="checked" <# } #> {{{ data.link }}} /> <?php // phpcs:ignore WordPressVIPMinimum.Security.Mustache.OutputNotation ?> <label for="{{ data.id }}-{{ key }}" style="width:{{data.width}}%"> <# if( !data.is_tab) {#> <span class="screen-reader-text">{{ data.choices[ key ]['label'] }}</span> <img src="{{ data.choices[ key ]['url'] }}" alt="{{ data.choices[ key ]['label'] }}"/> <# } else { #> <# if( data.choices[ key ]['icon'] ){ #> <i class="fa fa-{{ data.choices[ key ]['icon'] }}"></i> <# } if( data.choices[ key ]['url'] ){ #> <img src="{{ data.choices[ key ]['url'] }}" alt="{{ data.choices[ key ]['label'] }}"/> <# } if(data.choices[ key ]['label']){ #> <span class="tab-label">{{ data.choices[ key ]['label'] }}</span> <# } #> <# } #> </label> <# } #> </div> <?php } } heading.php 0000666 00000005571 15226760543 0006702 0 ustar 00 <?php /** * Customizer Heading. * * @since 1.0.0 * @package Neve\Customizer\Controls */ namespace Neve\Customizer\Controls; /** * Heading control */ class Heading extends \WP_Customize_Control { /** * The control type. * * @access public * @var string */ public $type = 'customizer-heading'; /** * Control class. * * @var string */ public $class = ''; /** * Should be accordion? * * @var bool */ public $accordion = false; /** * Initial state. * * @var bool */ public $expanded = true; /** * How many controls to wrap. * * @var int */ public $controls_to_wrap = 1; /** * Label before the accordion. * * @var string */ public $category_label = ''; /** * Send data to _s * * @return array */ public function json() { $json = parent::json(); $json['classes'] = $this->class; $json['accordion'] = $this->accordion; $json['category_label'] = $this->category_label; if ( $this->accordion === true ) { $json['classes'] .= ' accordion'; } $json['style'] = $this->print_style(); return $json; } /** * Render the control. */ protected function render() { $id = 'customize-control-' . str_replace( array( '[', ']' ), array( '-', '' ), $this->id ); $class = 'customize-control customize-control-' . $this->type; $class .= ' ' . $this->class; if ( $this->accordion ) { $class .= ' accordion'; } if ( $this->expanded ) { $class .= ' expanded'; } echo '<li id="' . esc_attr( $id ) . '" class="' . esc_attr( $class ) . '">'; echo '</li>'; } /** * An Underscore (JS) template for this control's content (but not its container). * * Class variables for this control class are available in the `data` JS object; * export custom variables by overriding {@see WP_Customize_Control::to_json()}. * * @see WP_Customize_Control::print_template() * * @access protected */ protected function content_template() { ?> <# if(data.category_label) {#> <span class="customize-control-title">{{data.category_label}}</span> <# }#> <div class="neve-customizer-heading"> <span class="accordion-heading">{{ data.label }}</span> <# if(data.accordion) { #> <span class="accordion-expand-button"></span> <# } #> </div> {{{data.style}}} <?php // phpcs:ignore WordPressVIPMinimum.Security.Mustache.OutputNotation ?> <?php } /** * Print the style for the accordion. */ protected function print_style() { $style = ''; $style .= '<style>'; for ( $i = 1; $i <= $this->controls_to_wrap; $i ++ ) { $style .= '.accordion.' . $this->class . ':not(.expanded)'; for ( $j = 1; $j <= $i; $j ++ ) { $style .= ' + li'; } if ( $i !== $this->controls_to_wrap ) { $style .= ','; } } $style .= '{max-height: 0;opacity: 0;margin: 0; overflow: hidden; padding:0 !important;}'; $style .= '</style>'; return $style; } }
| ver. 1.4 |
Github
|
.
| PHP 5.4.45 | Generation time: 0 |
proxy
|
phpinfo
|
Settings