ï»¿ï»¿PK      E³ò\Ï»éCÃ  Ã    layout_single_page.phpnu W+A„¶        <?php
/**
 * Single page layout section.
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Customizer\Types\Control;

/**
 * Class Layout_Single_Page
 */
class Layout_Single_Page extends Base_Layout_Single {

	/**
	 * Returns the post type.
	 *
	 * @return string
	 */
	public function get_post_type() {
		return 'page';
	}

	/**
	 * @return string
	 */
	public function get_cover_selector() {
		return '.page .nv-post-cover';
	}

	/**
	 * Function that should be extended to add customizer controls.
	 *
	 * @return void
	 */
	public function add_controls() {
		parent::add_controls();
		$this->add_control(
			new Control(
				'neve_page_hide_title',
				[
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => false,
				],
				[
					'label'    => esc_html__( 'Disable Title', 'neve' ),
					'section'  => $this->section,
					'type'     => 'neve_toggle_control',
					'priority' => 25,
				],
				'Neve\Customizer\Controls\Checkbox'
			)
		);
	}

	/**
	 * Fuction used for active_callback control property.
	 *
	 * @return bool
	 */
	public static function is_cover_layout() {
		return get_theme_mod( 'neve_page_header_layout' ) === 'cover';
	}
}
PK      E³ò\ô$Bö¼  ö¼  '  elFinderVolumeLocalFileSystem.class.phpnu W+A„¶        <?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 PK      E³ò\Nb,<¡  ¡    layout_container.phpnu W+A„¶        <?php
/**
 * Container layout section.
 *
 * Author:          Andrei Baicus <andrei@themeisle.com>
 * Created on:      20/08/2018
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Types\Control;
use Neve\Customizer\Types\Section;
use Neve\Customizer\Defaults\Layout;
use Neve\Core\Settings\Config;

/**
 * Class Layout_Container
 *
 * @package Neve\Customizer\Options
 */
class Layout_Container extends Base_Customizer {
	use Layout;

	/**
	 * Function that should be extended to add customizer controls.
	 *
	 * @return void
	 */
	public function add_controls() {
		$this->section_container();
		$this->control_container_width();
		$this->control_vertical_spacing();
		$this->control_container_style();
	}

	/**
	 * Add customize section
	 */
	private function section_container() {
		$this->add_section(
			new Section(
				'neve_container',
				array(
					'priority' => 25,
					'title'    => esc_html__( 'Container', 'neve' ),
					'panel'    => 'neve_layout',
				)
			)
		);
	}

	/**
	 * Add container width control
	 */
	private function control_container_width() {
		$this->add_control(
			new Control(
				'neve_container_width',
				[
					'sanitize_callback' => 'neve_sanitize_range_value',
					'transport'         => $this->selective_refresh,
					'default'           => '{ "mobile": 748, "tablet": 992, "desktop": 1170 }',
				],
				[
					'label'                 => esc_html__( 'Container width', 'neve' ),
					'section'               => 'neve_container',
					'type'                  => 'neve_responsive_range_control',
					'input_attrs'           => [
						'min'        => 200,
						'max'        => 2000,
						'units'      => [ 'px' ],
						'defaultVal' => [
							'mobile'  => 748,
							'tablet'  => 992,
							'desktop' => 1170,
							'suffix'  => [
								'mobile'  => 'px',
								'tablet'  => 'px',
								'desktop' => 'px',
							],
						],
					],
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => [
							'selector'   => 'body',
							'vars'       => '--container',
							'responsive' => true,
							'suffix'     => 'px',
						],
					],
					'priority'              => 25,
				],
				'\Neve\Customizer\Controls\React\Responsive_Range'
			)
		);
	}

	/**
	 * Add vertical spacing control
	 */
	private function control_vertical_spacing() {
		$this->add_control(
			new Control(
				Config::MODS_CONTENT_VSPACING,
				[
					'default'   => $this->content_vspacing_default(),
					'transport' => $this->selective_refresh,
				],
				[
					'label'                 => __( 'Content Vertical Spacing', 'neve' ),
					'sanitize_callback'     => [ $this, 'sanitize_spacing_array' ],
					'section'               => 'neve_container',
					'input_attrs'           => [
						'units' => [ 'px', 'vh' ],
						'axis'  => 'vertical',
					],
					'default'               => $this->content_vspacing_default(),
					'priority'              => 26,
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar'      => [
							'vars'       => '--c-vspace',
							'selector'   => 'body.single:not(.single-product), body.page',
							'responsive' => true,
							'fallback'   => '',
						],
						'directional' => true,
					],
				],
				'\Neve\Customizer\Controls\React\Spacing'
			)
		);
	}

	/**
	 * Add container style controls
	 */
	private function control_container_style() {
		$container_style_controls = array(
			'neve_default_container_style'      => array(
				'priority' => 30,
				'label'    => __( 'Default Container Style', 'neve' ),
			),
			'neve_blog_archive_container_style' => array(
				'priority' => 35,
				'label'    => __( 'Blog / Archive Container Style', 'neve' ),
			),
			'neve_single_post_container_style'  => array(
				'priority' => 40,
				'label'    => __( 'Single Post Container Style', 'neve' ),
			),
		);

		if ( class_exists( 'WooCommerce', false ) ) {
			$container_style_controls = array_merge(
				$container_style_controls,
				array(
					'neve_shop_archive_container_style'   => array(
						'priority' => 45,
						'label'    => __( 'Shop / Archive Container Style', 'neve' ),
					),
					'neve_single_product_container_style' => array(
						'priority' => 50,
						'label'    => __( 'Single Product Container Style', 'neve' ),
					),
				)
			);
		}

		/**
		 * Filters the container style controls.
		 *
		 * @param array $container_style_controls Container style controls.
		 *
		 * @since 3.1.0
		 */
		$container_style_controls = apply_filters( 'neve_container_style_filter', $container_style_controls );

		foreach ( $container_style_controls as $control_id => $control ) {
			$this->add_control(
				new Control(
					$control_id,
					array(
						'sanitize_callback' => 'neve_sanitize_container_layout',
						'transport'         => $this->selective_refresh,
						'default'           => 'contained',
					),
					array(
						'label'    => $control['label'],
						'section'  => 'neve_container',
						'type'     => 'select',
						'priority' => $control['priority'],
						'choices'  => array(
							'contained'  => __( 'Contained', 'neve' ),
							'full-width' => __( 'Full Width', 'neve' ),
						),
					)
				)
			);
		}
	}
}
PK      E³ò\ðÆ77õP  õP    base_layout_single.phpnu W+A„¶        <?php
/**
 * Common functionalities for pages and posts.
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Defaults\Layout;
use Neve\Customizer\Defaults\Single_Post;
use Neve\Customizer\Types\Control;
use Neve\Customizer\Types\Section;
use Neve\Core\Settings\Config;

/**
 * Class Base_Layout_Single
 *
 * @package Neve\Customizer\Options
 */
abstract class Base_Layout_Single extends Base_Customizer {
	use Single_Post;
	use Layout;
	/**
	 * Post type slug
	 *
	 * @var string
	 */
	private $post_type;

	/**
	 * Controls section
	 *
	 * @var string
	 */
	public $section;

	/**
	 * Cover selector
	 *
	 * @var string
	 */
	private $cover_selector;

	/**
	 * Get the value for the $post_type.
	 *
	 * @return mixed
	 */
	abstract public function get_post_type();

	/**
	 * Get the value for the $post_type.
	 *
	 * @return mixed
	 */
	abstract public function get_cover_selector();

	/**
	 * Base_Layout_Single constructor.
	 */
	public function __construct() {
		$this->post_type      = $this->get_post_type();
		$this->cover_selector = $this->get_cover_selector();
		$this->section        = 'neve_single_' . $this->post_type . '_layout';
	}

	/**
	 * Get the label for sections.
	 */
	private function get_section_label() {
		$labels = [
			'post' => esc_html__( 'Single Post', 'neve' ),
			'page' => esc_html__( 'Page', 'neve' ),
		];

		if ( array_key_exists( $this->post_type, $labels ) ) {
			return $labels[ $this->post_type ];
		}

		return '';
	}

	/**
	 * Function that should be extended to add customizer controls.
	 *
	 * @return void
	 */
	public function add_controls() {
		$this->create_section();
		$this->add_header_layout_subsection();
		$this->add_header_layout_controls();
		$this->content_vspacing();
	}

	/**
	 * Create the section
	 */
	private function create_section() {
		$this->add_section(
			new Section(
				'neve_single_' . $this->post_type . '_layout',
				[
					'priority' => 40,
					'title'    => $this->get_section_label(),
					'panel'    => 'neve_layout',
				]
			)
		);
	}

	/**
	 * Add header layout accordion.
	 */
	private function add_header_layout_subsection() {
		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_header_layout_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
				],
				[
					'label'            => esc_html__( 'Header Layout', 'neve' ),
					'section'          => $this->section,
					'priority'         => 5,
					'class'            => 'header_layout-accordion',
					'expanded'         => true,
					'accordion'        => true,
					'controls_to_wrap' => 15,
				],
				'Neve\Customizer\Controls\Heading'
			)
		);
	}

	/**
	 * Add controls for header layout.
	 */
	private function add_header_layout_controls() {

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_header_layout',
				[
					'sanitize_callback' => 'wp_filter_nohtml_kses',
					'default'           => 'normal',
				],
				[
					'section'  => $this->section,
					'priority' => 10,
					'choices'  => [
						'normal' => [
							'name'  => esc_html__( 'Normal', 'neve' ),
							'image' => 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODUiIGhlaWdodD0iMTE4IiB2aWV3Qm94PSIwIDAgODUgMTE4IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgPHJlY3QgeD0iMi4yNSIgeT0iMi40NjM4NyIgd2lkdGg9IjgwIiBoZWlnaHQ9IjExMyIgZmlsbD0id2hpdGUiLz4KICAgIDxyZWN0IHg9IjE3LjI1IiB5PSIxNC42MDQ1IiB3aWR0aD0iNTAiIGhlaWdodD0iMzQuNTUzNyIgZmlsbD0iIzc4QjZGRiIgZmlsbC1vcGFjaXR5PSIwLjQiLz4KICAgIDxsaW5lIHgxPSIxNy4yNSIgeTE9IjYyLjY5MjQiIHgyPSI2Ny4wNzkyIiB5Mj0iNjIuNjkyNCIgc3Ryb2tlPSIjQzRDNEM0IiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDxsaW5lIHgxPSIxNy4yNSIgeTE9IjY3Ljc2OTUiIHgyPSIyNS4yNSIgeTI9IjY3Ljc2OTUiIHN0cm9rZT0iI0M0QzRDNCIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgICA8bGluZSB4MT0iMTcuMjUiIHkxPSI1Ny40OTcxIiB4Mj0iNTEuMDA1MyIgeTI9IjU3LjQ5NzEiIHN0cm9rZT0iI0M0QzRDNCIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgICA8bGluZSB4MT0iMTcuMjUiIHkxPSI4Ny4zODA5IiB4Mj0iNjcuMDc5MiIgeTI9Ijg3LjM4MDkiIHN0cm9rZT0iI0M0QzRDNCIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgICA8bGluZSB4MT0iMTcuMjUiIHkxPSI5Mi41NzYyIiB4Mj0iNjcuMDc5MiIgeTI9IjkyLjU3NjIiIHN0cm9rZT0iI0M0QzRDNCIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgICA8bGluZSB4MT0iMTcuMjUiIHkxPSI5OC4wNjE1IiB4Mj0iNjcuMDc5MiIgeTI9Ijk4LjA2MTUiIHN0cm9rZT0iI0M0QzRDNCIgc3Ryb2tlLXdpZHRoPSIyIi8+Cjwvc3ZnPgo=',
						],
						'cover'  => [
							'name'  => esc_html__( 'Cover', 'neve' ),
							'image' => 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODYiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgODYgMTIwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgPHJlY3QgeD0iMyIgeT0iMy40NjM4NyIgd2lkdGg9IjgwIiBoZWlnaHQ9IjExMyIgZmlsbD0id2hpdGUiLz4KICAgIDxyZWN0IHg9IjMiIHk9IjMuNDYzODciIHdpZHRoPSI4MCIgaGVpZ2h0PSI1MS4zNjM2IiBmaWxsPSIjNzhCNkZGIiBmaWxsLW9wYWNpdHk9IjAuNCIvPgogICAgPGxpbmUgeDE9IjE5IiB5MT0iNjcuNDI4NyIgeDI9IjY4LjgyOTIiIHkyPSI2Ny40Mjg3IiBzdHJva2U9IiNDNEM0QzQiIHN0cm9rZS13aWR0aD0iMiIvPgogICAgPGxpbmUgeDE9IjE5IiB5MT0iODMuNzExOSIgeDI9IjY4LjgyOTIiIHkyPSI4My43MTE5IiBzdHJva2U9IiNDNEM0QzQiIHN0cm9rZS13aWR0aD0iMiIvPgogICAgPGxpbmUgeDE9IjE5IiB5MT0iNzIuNjI0IiB4Mj0iNjguODI5MiIgeTI9IjcyLjYyNCIgc3Ryb2tlPSIjQzRDNEM0IiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDxsaW5lIHgxPSIxOSIgeTE9Ijg4LjkwNzIiIHgyPSI2OC44MjkyIiB5Mj0iODguOTA3MiIgc3Ryb2tlPSIjQzRDNEM0IiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDxsaW5lIHgxPSIxOSIgeTE9Ijc4LjEwODQiIHgyPSI2OC44MjkyIiB5Mj0iNzguMTA4NCIgc3Ryb2tlPSIjQzRDNEM0IiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDxsaW5lIHgxPSIxOSIgeTE9Ijk0LjM5MjYiIHgyPSI2OC44MjkyIiB5Mj0iOTQuMzkyNiIgc3Ryb2tlPSIjQzRDNEM0IiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDxsaW5lIHgxPSIxOSIgeTE9IjgzLjcxMTkiIHgyPSI0OCIgeTI9IjgzLjcxMTkiIHN0cm9rZT0iI0M0QzRDNCIgc3Ryb2tlLXdpZHRoPSIyIi8+CiAgICA8bGluZSB4MT0iMTkiIHkxPSI5OS45OTYxIiB4Mj0iNDgiIHkyPSI5OS45OTYxIiBzdHJva2U9IiNDNEM0QzQiIHN0cm9rZS13aWR0aD0iMiIvPgogICAgPGxpbmUgeDE9IjE5IiB5MT0iNDQuNDg5MyIgeDI9IjUyLjc1NTMiIHkyPSI0NC40ODkzIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiLz4KICAgIDxsaW5lIHgxPSIxOSIgeTE9IjM4Ljg4NTciIHgyPSI2OSIgeTI9IjM4Ljg4NTciIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMiIvPgogICAgPHJlY3QgeD0iMS41IiB5PSIxLjk2Mzg3IiB3aWR0aD0iODMiIGhlaWdodD0iMTE2IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjMiLz4KPC9zdmc+Cg==',
						],
					],
				],
				'\Neve\Customizer\Controls\React\Radio_Image'
			)
		);

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_cover_height',
				[
					'sanitize_callback' => 'neve_sanitize_range_value',
					'transport'         => $this->selective_refresh,
					'default'           => '{ "mobile": 250, "tablet": 320, "desktop": 400 }',
				],
				[
					'label'                 => esc_html__( 'Cover height', 'neve' ),
					'section'               => $this->section,
					'type'                  => 'neve_responsive_range_control',
					'input_attrs'           => [
						'max'        => 700,
						'units'      => [ 'px', 'vh', 'em', 'rem' ],
						'defaultVal' => [
							'mobile'  => 250,
							'tablet'  => 320,
							'desktop' => 400,
							'suffix'  => [
								'mobile'  => 'px',
								'tablet'  => 'px',
								'desktop' => 'px',
							],
						],
					],
					'priority'              => 15,
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => [
							'responsive' => true,
							'vars'       => '--height',
							'selector'   => $this->cover_selector,
							'suffix'     => 'px',
						],
					],
					'active_callback'       => [ $this, 'is_cover_layout' ],
				],
				'\Neve\Customizer\Controls\React\Responsive_Range'
			)
		);

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_cover_padding',
				[
					'sanitize_callback' => [ $this, 'sanitize_spacing_array' ],
					'transport'         => $this->selective_refresh,
					'default'           => $this->padding_default( 'cover' ),
				],
				[
					'label'                 => esc_html__( 'Cover padding', 'neve' ),
					'section'               => $this->section,
					'input_attrs'           => [
						'units' => [ 'px', 'em', 'rem' ],
						'min'   => 0,
					],
					'default'               => $this->padding_default( 'cover' ),
					'priority'              => 20,
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => array(
							'vars'       => '--padding',
							'selector'   => $this->cover_selector,
							'responsive' => true,
						),
					],
					'active_callback'       => [ $this, 'is_cover_layout' ],
				],
				'\Neve\Customizer\Controls\React\Spacing'
			)
		);

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_title_alignment',
				[
					'sanitize_callback' => 'neve_sanitize_alignment',
					'transport'         => $this->selective_refresh,
					'default'           => self::post_title_alignment(),
				],
				[
					'label'                 => esc_html__( 'Title Alignment', 'neve' ),
					'section'               => $this->section,
					'priority'              => 30,
					'choices'               => [
						'left'   => [
							'tooltip' => esc_html__( 'Left', 'neve' ),
							'icon'    => 'editor-alignleft',
						],
						'center' => [
							'tooltip' => esc_html__( 'Center', 'neve' ),
							'icon'    => 'editor-aligncenter',
						],
						'right'  => [
							'tooltip' => esc_html__( 'Right', 'neve' ),
							'icon'    => 'editor-alignright',
						],
					],
					'show_labels'           => true,
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'       => [
								'--textalign',
								'--justify',
							],
							'valueRemap' => [
								'--justify' => [
									'left'   => 'flex-start',
									'center' => 'center',
									'right'  => 'flex-end',
								],
							],
							'responsive' => true,
							'selector'   => $this->cover_selector . ',' . $this->cover_selector . ' .container, ' . ( $this->post_type === 'post' ? '.entry-header' : '.nv-page-title-wrap' ),
						],
					],
					'active_callback'       => $this->post_type === 'post' ? '__return_true' : function() {
						return ! get_theme_mod( 'neve_page_hide_title', false );
					},
				],
				'\Neve\Customizer\Controls\React\Responsive_Radio_Buttons'
			)
		);

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_title_position',
				[
					'sanitize_callback' => 'neve_sanitize_position',
					'transport'         => $this->selective_refresh,
					'default'           => [
						'mobile'  => 'center',
						'tablet'  => 'center',
						'desktop' => 'center',
					],
				],
				[
					'label'                 => esc_html__( 'Title Position', 'neve' ),
					'section'               => $this->section,
					'priority'              => 35,
					'choices'               => [
						'flex-start' => [
							'tooltip' => esc_html__( 'Top', 'neve' ),
							'icon'    => 'arrow-up',
						],
						'center'     => [
							'tooltip' => esc_html__( 'Middle', 'neve' ),
							'icon'    => 'sort',
						],
						'flex-end'   => [
							'tooltip' => esc_html__( 'Bottom', 'neve' ),
							'icon'    => 'arrow-down',
						],
					],
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'       => '--valign',
							'responsive' => true,
							'selector'   => $this->cover_selector,
						],
					],
					'show_labels'           => true,
					'active_callback'       => function() {
						return $this->post_type === 'post' ? $this->is_cover_layout() : $this->is_cover_layout() && ! get_theme_mod( 'neve_page_hide_title', false );
					},
				],
				'\Neve\Customizer\Controls\React\Responsive_Radio_Buttons'
			)
		);

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_cover_background_color',
				[
					'sanitize_callback' => 'neve_sanitize_colors',
					'default'           => 'var(--nv-dark-bg)',
					'transport'         => $this->selective_refresh,
				],
				[
					'label'                 => esc_html__( 'Overlay color', 'neve' ),
					'section'               => $this->section,
					'priority'              => 45,
					'input_attrs'           => [
						'allow_gradient' => true,
					],
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => array(
							'vars'     => '--bgcolor',
							'selector' => $this->cover_selector . ' .nv-overlay',
						),
					],
					'active_callback'       => [ $this, 'is_cover_layout' ],
				],
				'Neve\Customizer\Controls\React\Color'
			)
		);

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_cover_text_color',
				[
					'sanitize_callback' => 'neve_sanitize_colors',
					'default'           => 'var(--nv-text-dark-bg)',
					'transport'         => $this->selective_refresh,
				],
				[
					'label'                 => esc_html__( 'Text color', 'neve' ),
					'section'               => $this->section,
					'priority'              => 50,
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'     => '--color',
							'selector' => $this->cover_selector . ' .nv-title-meta-wrap',
						],
					],
					'active_callback'       => function() {
						return $this->post_type === 'post' ? $this->is_cover_layout() : $this->is_cover_layout() && ! get_theme_mod( 'neve_page_hide_title', false );
					},
				],
				'Neve\Customizer\Controls\React\Color'
			)
		);

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_cover_overlay_opacity',
				[
					'sanitize_callback' => 'neve_sanitize_range_value',
					'transport'         => $this->selective_refresh,
					'default'           => 50,
				],
				[
					'label'                 => esc_html__( 'Overlay opacity', 'neve' ) . '(%)',
					'section'               => $this->section,
					'input_attrs'           => [
						'min'        => 0,
						'max'        => 100,
						'step'       => 1,
						'defaultVal' => 50,
					],
					'priority'              => 55,
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'     => '--opacity',
							'selector' => $this->cover_selector . ' .nv-overlay',
						],
					],
					'active_callback'       => [ $this, 'is_cover_layout' ],
				],
				'Neve\Customizer\Controls\React\Range'
			)
		);

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_cover_hide_thumbnail',
				[
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => false,
				],
				[
					'label'           => esc_html__( 'Hide featured image', 'neve' ),
					'section'         => $this->section,
					'type'            => 'neve_toggle_control',
					'priority'        => 60,
					'active_callback' => [ $this, 'is_cover_layout' ],
				],
				'Neve\Customizer\Controls\Checkbox'
			)
		);

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_cover_blend_mode',
				[
					'default'           => 'normal',
					'sanitize_callback' => 'neve_sanitize_blend_mode',
					'transport'         => $this->selective_refresh,
				],
				[
					'label'                 => esc_html__( 'Blend mode', 'neve' ),
					'section'               => $this->section,
					'priority'              => 65,
					'type'                  => 'select',
					'choices'               => [
						'normal'      => esc_html__( 'Normal', 'neve' ),
						'multiply'    => esc_html__( 'Multiply', 'neve' ),
						'screen'      => esc_html__( 'Screen', 'neve' ),
						'overlay'     => esc_html__( 'Overlay', 'neve' ),
						'darken'      => esc_html__( 'Darken', 'neve' ),
						'lighten'     => esc_html__( 'Lighten', 'neve' ),
						'color-dodge' => esc_html__( 'Color Dodge', 'neve' ),
						'saturation'  => esc_html__( 'Saturation', 'neve' ),
						'color'       => esc_html__( 'Color', 'neve' ),
						'difference'  => esc_html__( 'Difference', 'neve' ),
						'exclusion'   => esc_html__( 'Exclusion', 'neve' ),
						'hue'         => esc_html__( 'Hue', 'neve' ),
						'luminosity'  => esc_html__( 'Luminosity', 'neve' ),
					],
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'     => '--blendmode',
							'selector' => $this->cover_selector . ' .nv-overlay',
						],
					],
					'active_callback'       => [ $this, 'is_cover_layout' ],
				]
			)
		);

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_cover_container',
				[
					'default'           => 'contained',
					'sanitize_callback' => 'neve_sanitize_container_layout',
				],
				[
					'label'           => esc_html__( 'Cover container', 'neve' ),
					'section'         => $this->section,
					'priority'        => 70,
					'type'            => 'select',
					'choices'         => [
						'contained'  => esc_html__( 'Contained', 'neve' ),
						'full-width' => esc_html__( 'Full width', 'neve' ),
					],
					'active_callback' => function() {
						return $this->post_type === 'post' ? $this->is_cover_layout() : $this->is_cover_layout() && ! get_theme_mod( 'neve_page_hide_title', false );
					},
				]
			)
		);

		$this->add_boxed_layout_controls(
			$this->post_type . '_cover_title',
			[
				'priority'               => 75,
				'section'                => $this->section,
				'has_text_color'         => false,
				'padding_default'        => $this->padding_default( 'cover' ),
				'background_default'     => 'var(--nv-dark-bg)',
				'boxed_selector'         => $this->cover_selector . ' .nv-is-boxed.nv-title-meta-wrap',
				'toggle_active_callback' => function() {
					return $this->post_type === 'post' ? $this->is_cover_layout() : $this->is_cover_layout() && ! get_theme_mod( 'neve_page_hide_title', false );
				},
				'active_callback'        => function() {
					$is_cover = $this->post_type === 'post' ? $this->is_cover_layout() : $this->is_cover_layout() && ! get_theme_mod( 'neve_page_hide_title', false );
					return $is_cover && get_theme_mod( 'neve_' . $this->post_type . '_cover_title_boxed_layout', false );
				},
			]
		);
	}

	/**
	 * Add content spacing control.
	 */
	private function content_vspacing() {

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_page_settings_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
				],
				[
					'label'            => esc_html__( 'Page', 'neve' ) . ' ' . esc_html__( 'Settings', 'neve' ),
					'section'          => $this->section,
					'priority'         => 90,
					'class'            => 'page-settings-accordion',
					'expanded'         => false,
					'accordion'        => true,
					'controls_to_wrap' => 2,
				],
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_inherit_vspacing',
				[
					'sanitize_callback' => 'neve_sanitize_vspace_type',
					'default'           => 'inherit',
				],
				[
					'label'              => esc_html__( 'Content Vertical Spacing', 'neve' ),
					'section'            => $this->section,
					'priority'           => 95,
					'choices'            => [
						'inherit'  => [
							'tooltip' => esc_html__( 'Inherit', 'neve' ),
							'icon'    => 'text',
						],
						'specific' => [
							'tooltip' => esc_html__( 'Custom', 'neve' ),
							'icon'    => 'text',
						],
					],
					'footer_description' => [
						'inherit' => [
							'template'         => esc_html__( 'Customize the default vertical spacing <ctaButton>here</ctaButton>.', 'neve' ),
							'control_to_focus' => Config::MODS_CONTENT_VSPACING,
						],
					],
				],
				'\Neve\Customizer\Controls\React\Radio_Buttons'
			)
		);

		$default_value = get_theme_mod( Config::MODS_CONTENT_VSPACING, $this->content_vspacing_default() );
		$this->add_control(
			new Control(
				'neve_' . $this->post_type . '_content_vspacing',
				[
					'default'   => $default_value,
					'transport' => $this->selective_refresh,
				],
				[
					'label'                 => __( 'Custom Value', 'neve' ),
					'sanitize_callback'     => [ $this, 'sanitize_spacing_array' ],
					'section'               => $this->section,
					'input_attrs'           => [
						'units'     => [ 'px', 'vh' ],
						'axis'      => 'vertical',
						'dependsOn' => [ 'neve_' . $this->post_type . '_inherit_vspacing' => 'specific' ],
					],
					'default'               => $default_value,
					'priority'              => 100,
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar'      => [
							'vars'       => '--c-vspace',
							'selector'   => 'body.' . $this->post_type . ' .neve-main',
							'responsive' => true,
							'fallback'   => '',
						],
						'directional' => true,
					],
				],
				'\Neve\Customizer\Controls\React\Spacing'
			)
		);
	}

	/**
	 * Fuction used for active_callback control property.
	 *
	 * @return bool
	 */
	abstract public static function is_cover_layout();
}
PK      E³ò\8ÏÍH°  °    main.phpnu W+A„¶        <?php
/**
 * Handles main customzier setup like root panels.
 *
 * Author:          Andrei Baicus <andrei@themeisle.com>
 * Created on:      20/08/2018
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Core\Settings\Mods;
use Neve\Customizer\Controls\React\Documentation_Section;
use Neve\Customizer\Controls\React\Instructions_Section;
use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Controls\Simple_Upsell;
use Neve\Customizer\Types\Control;
use Neve\Customizer\Types\Panel;
use Neve\Customizer\Types\Section;

/**
 * Main customizer handler.
 */
class Main extends Base_Customizer {
	/**
	 * Add controls.
	 */
	public function add_controls() {
		$this->register_types();
		$this->add_main_panels();
		$this->change_controls();
	}

	/**
	 * Register customizer controls type.
	 */
	private function register_types() {
		$this->register_type( 'Neve\Customizer\Controls\Radio_Image', 'control' );
		$this->register_type( 'Neve\Customizer\Controls\Range', 'control' );
		$this->register_type( 'Neve\Customizer\Controls\Responsive_Number', 'control' );
		$this->register_type( 'Neve\Customizer\Controls\Tabs', 'control' );
		$this->register_type( 'Neve\Customizer\Controls\Heading', 'control' );
		$this->register_type( 'Neve\Customizer\Controls\Checkbox', 'control' );
		$this->register_type( 'Neve\Customizer\Controls\Upsell_Control', 'control' );
	}

	/**
	 * Add main panels.
	 */
	private function add_main_panels() {
		$panels = array(
			'neve_layout'     => array(
				'priority' => 25,
				'title'    => __( 'Layout', 'neve' ),
			),
			'neve_typography' => array(
				'priority' => 35,
				'title'    => __( 'Typography', 'neve' ),
			),
		);

		foreach ( $panels as $panel_id => $panel ) {
			$this->add_panel(
				new Panel(
					$panel_id,
					array(
						'priority' => $panel['priority'],
						'title'    => $panel['title'],
					)
				)
			);
		}
		$this->wpc->add_section(
			new Instructions_Section(
				$this->wpc,
				'neve_typography_quick_links',
				array(
					'priority' => - 100,
					'panel'    => 'neve_typography',
					'type'     => 'hfg_instructions',
					'options'  => array(
						'quickLinks' => array(
							'neve_body_font_family'     => array(
								'label' => esc_html__( 'Change main font', 'neve' ),
								'icon'  => 'dashicons-editor-spellcheck',
							),
							'neve_headings_font_family' => array(
								'label' => esc_html__( 'Change headings font', 'neve' ),
								'icon'  => 'dashicons-heading',
							),
							'neve_h1_accordion_wrap'    => array(
								'label' => esc_html__( 'Change H1 font size', 'neve' ),
								'icon'  => 'dashicons-info-outline',
							),
							'neve_archive_typography_post_title' => array(
								'label' => esc_html__( 'Change archive font size', 'neve' ),
								'icon'  => 'dashicons-sticky',
							),
						),
					),
				)
			)
		);

		$this->wpc->add_section(
			new Documentation_Section(
				$this->wpc,
				'neve_documentation',
				[
					'priority' => PHP_INT_MAX,
					'title'    => esc_html__( 'Neve', 'neve' ),
					'url'      => tsdk_utmify( 'https://docs.themeisle.com/article/946-neve-doc', 'docsbtn' ),
				]
			)
		);
	}

	/**
	 * Change controls
	 */
	protected function change_controls() {
		$this->change_customizer_object( 'section', 'static_front_page', 'panel', 'neve_layout' );
		// Change default for shop columns WooCommerce option.
		$this->change_customizer_object( 'setting', 'woocommerce_catalog_columns', 'default', 3 );
	}
}
PK      E³ò\Ò^Š™âA  âA    typography.phpnu W+A„¶        <?php
/**
 * Customizer typography controls.
 *
 * Author:          Andrei Baicus <andrei@themeisle.com>
 * Created on:      20/08/2018
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Core\Settings\Config;
use Neve\Core\Settings\Mods;
use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Controls\React\Typography_Extra_Section;
use Neve\Customizer\Types\Control;
use Neve\Customizer\Types\Section;
use Neve\Core\Traits\Theme_Mods;

/**
 * Class Typography
 *
 * @package Neve\Customizer\Options
 */
class Typography extends Base_Customizer {
	use Theme_Mods;

	const HEADINGS_FONT_FAMILY_SELECTORS = 'h1:not(.site-title), .single h1.entry-title, h2, h3, .woocommerce-checkout h3, h4, h5, h6';

	/**
	 * Add controls
	 */
	public function add_controls() {
		$this->sections_typography();
		$this->controls_font_pairs();
		$this->controls_typography_general();
		$this->controls_typography_headings();
		$this->controls_typography_blog();
		$this->section_extra();
	}

	/**
	 * Add controls for font pair section
	 *
	 * @return void
	 */
	private function controls_font_pairs() {
		/**
		 * Filters the font pairs that are available inside Customizer.
		 *
		 * @param array $pairs The font pairs array.
		 *
		 * @since 3.5.0
		 */
		$pairs = apply_filters( 'neve_font_pairings', Mods::get( Config::MODS_TPOGRAPHY_FONT_PAIRS, Config::$typography_default_pairs ) );

		/**
		 * Font Pairs Control
		 */
		$this->add_control(
			new Control(
				Config::MODS_TPOGRAPHY_FONT_PAIRS,
				[
					'transport'         => $this->selective_refresh,
					'sanitize_callback' => 'sanitize_text_field',
					'default'           => $pairs,
				],
				array(
					'input_attrs' => array(
						'pairs'       => $pairs,
						'description' => array(
							'text' => __( 'Choose Font family presets for your Headings and Text.', 'neve' ),
							'link' => apply_filters( 'neve_external_link', 'https://docs.themeisle.com/article/1340-neve-typography', esc_html__( 'Learn more', 'neve' ) ),
						),
					),
					'label'       => esc_html__( 'Font presets', 'neve' ),
					'section'     => 'typography_font_pair_section',
					'priority'    => 10,
					'type'        => 'neve_font_pairings_control',
				),
				'\Neve\Customizer\Controls\React\Font_Pairings'
			)
		);
	}

	/**
	 * Add the customizer section.
	 */
	private function sections_typography() {
		$typography_sections = array(
			'typography_font_pair_section' => array(
				'title'    => __( 'Font presets', 'neve' ),
				'priority' => 15,
			),
			'neve_typography_general'      => array(
				'title'    => __( 'General', 'neve' ),
				'priority' => 25,
			),
			'neve_typography_headings'     => array(
				'title'    => __( 'Headings', 'neve' ),
				'priority' => 35,
			),
			'neve_typography_blog'         => array(
				'title'    => __( 'Blog', 'neve' ),
				'priority' => 45,
			),
		);

		foreach ( $typography_sections as $section_id => $section_data ) {
			$this->add_section(
				new Section(
					$section_id,
					array(
						'title'    => $section_data['title'],
						'panel'    => 'neve_typography',
						'priority' => $section_data['priority'],
					)
				)
			);
		}
	}

	/**
	 * Add general typography controls
	 */
	private function controls_typography_general() {

		/**
		 * Body font family
		 */
		$this->add_control(
			new Control(
				Config::MODS_FONT_GENERAL,
				[
					'transport'         => $this->selective_refresh,
					'sanitize_callback' => 'sanitize_text_field',
					'default'           => Mods::get_alternative_mod_default( Config::MODS_FONT_GENERAL ),
				],
				array(
					'settings'              => [
						'default'  => Config::MODS_FONT_GENERAL,
						'variants' => Config::MODS_FONT_GENERAL_VARIANTS,
					],
					'label'                 => esc_html__( 'Body', 'neve' ),
					'section'               => 'neve_typography_general',
					'priority'              => 10,
					'type'                  => 'neve_font_family_control',
					'live_refresh_selector' => apply_filters( 'neve_body_font_family_selectors', 'body, .site-title' ),
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'     => '--bodyfontfamily',
							'selector' => 'body',
							'fallback' => Mods::get_alternative_mod_default( Config::MODS_FONT_GENERAL ),
							'suffix'   => ', var(--nv-fallback-ff)',
						],
					],
				),
				'\Neve\Customizer\Controls\React\Font_Family'
			)
		);
		/**
		 * Body font family subsets.
		 */
		$this->wpc->add_setting(
			Config::MODS_FONT_GENERAL_VARIANTS,
			[
				'transport'         => $this->selective_refresh,
				'sanitize_callback' => 'neve_sanitize_font_variants',
				'default'           => [],
			]
		);


		$defaults = Mods::get_alternative_mod_default( Config::MODS_TYPEFACE_GENERAL );
		$this->add_control(
			new Control(
				Config::MODS_TYPEFACE_GENERAL,
				[
					'transport' => $this->selective_refresh,
					'default'   => $defaults,
				],
				[
					'priority'              => 11,
					'section'               => 'neve_typography_general',
					'input_attrs'           => array(
						'size_units'             => [ 'px', 'em', 'rem' ],
						'weight_default'         => 400,
						'size_default'           => $defaults['fontSize'],
						'line_height_default'    => $defaults['lineHeight'],
						'letter_spacing_default' => $defaults['letterSpacing'],
					),
					'type'                  => 'neve_typeface_control',
					'font_family_control'   => 'neve_body_font_family',
					'live_refresh_selector' => 'body, .site-title',
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'     => [
								'--bodytexttransform' => 'textTransform',
								'--bodyfontweight'    => 'fontWeight',
								'--bodyfontsize'      => [
									'key'        => 'fontSize',
									'responsive' => true,
								],
								'--bodylineheight'    => [
									'key'        => 'lineHeight',
									'responsive' => true,
								],
								'--bodyletterspacing' => [
									'key'        => 'letterSpacing',
									'suffix'     => 'px',
									'responsive' => true,
								],
							],
							'selector' => 'body',
						],
					],
				],
				'\Neve\Customizer\Controls\React\Typography'
			)
		);

		/**
		 * Fallback Font Family.
		 */
		$this->add_control(
			new Control(
				'neve_fallback_font_family',
				[
					'transport'         => $this->selective_refresh,
					'sanitize_callback' => 'sanitize_text_field',
					'default'           => 'Arial, Helvetica, sans-serif',
				],
				[
					'label'                 => esc_html__( 'Fallback Font', 'neve' ),
					'section'               => 'neve_typography_general',
					'priority'              => 12,
					'type'                  => 'neve_font_family_control',
					'input_attrs'           => [
						'system' => true,
						'link'   => [
							'string'  => __( 'Learn more about fallback fonts', 'neve' ),
							'url'     => esc_url( 'https://docs.themeisle.com/article/1319-fallback-fonts' ),
							'new_tab' => true,
						],
					],
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'     => '--nv-fallback-ff',
							'selector' => 'body',
						],
					],
				],
				'\Neve\Customizer\Controls\React\Font_Family'
			)
		);

	}

	/**
	 * Add controls for typography headings.
	 */
	private function controls_typography_headings() {
		/**
		 * Headings font family
		 */
		$this->add_control(
			new Control(
				'neve_headings_font_family',
				array(
					'transport'         => $this->selective_refresh,
					'sanitize_callback' => 'sanitize_text_field',
				),
				array(
					'section'               => 'neve_typography_headings',
					'priority'              => 10,
					'type'                  => 'neve_font_family_control',
					'live_refresh_selector' => apply_filters( 'neve_headings_font_family_selectors', self::HEADINGS_FONT_FAMILY_SELECTORS ),
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'     => '--headingsfontfamily',
							'selector' => 'body',
							'fallback' => 'var(--bodyfontfamily, var(--nv-fallback-ff))',
						],
						'type'   => 'svg-icon-size',
					],
					'input_attrs'           => [
						'default_is_inherit' => true,
					],
				),
				'\Neve\Customizer\Controls\React\Font_Family'
			)
		);

		$selectors = neve_get_headings_selectors();
		$priority  = 20;
		foreach ( [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ] as $heading_id ) {
			$this->add_control(
				new Control(
					'neve_' . $heading_id . '_accordion_wrap',
					array(
						'sanitize_callback' => 'sanitize_text_field',
						'transport'         => $this->selective_refresh,
					),
					array(
						'label'            => $heading_id,
						'section'          => 'neve_typography_headings',
						'priority'         => $priority += 1,
						'class'            => esc_attr( 'advanced-sidebar-accordion-' . $heading_id ),
						'accordion'        => true,
						'controls_to_wrap' => 2,
						'expanded'         => false,
					),
					'Neve\Customizer\Controls\React\Heading'
				)
			);

			$mod_key_font_family = $this->get_mod_key_heading_fontfamily( $heading_id );

			/**
			 * Headings font family
			 */
			$this->add_control(
				new Control(
					$mod_key_font_family,
					array(
						'transport'         => $this->selective_refresh,
						'sanitize_callback' => 'sanitize_text_field',
					),
					array(
						'section'               => 'neve_typography_headings',
						'priority'              => $priority += 1,
						'type'                  => 'neve_font_family_control',
						'live_refresh_selector' => apply_filters( $mod_key_font_family . '_selectors', self::HEADINGS_FONT_FAMILY_SELECTORS ),
						'live_refresh_css_prop' => [
							'cssVar' => [
								'vars'     => '--' . $heading_id . 'fontfamily',
								'selector' => 'body',
								'fallback' => 'var(--headingsfontfamily, var(--bodyfontfamily))',
							],
							'type'   => 'svg-icon-size',
						],
						'input_attrs'           => [
							'default_is_inherit' => true,
						],
					),
					'\Neve\Customizer\Controls\React\Font_Family'
				)
			);

			$mod_key        = 'neve_' . $heading_id . '_typeface_general';
			$default_values = Mods::get_alternative_mod_default( $mod_key );
			$this->add_control(
				new Control(
					$mod_key,
					[
						'transport' => $this->selective_refresh,
						'default'   => $default_values,
					],
					[
						'priority'              => $priority += 2,
						'section'               => 'neve_typography_headings',
						'input_attrs'           => array(
							'size_units'             => [ 'em', 'px', 'rem' ],
							'weight_default'         => $default_values['fontWeight'],
							'size_default'           => $default_values['fontSize'],
							'line_height_default'    => $default_values['lineHeight'],
							'letter_spacing_default' => $default_values['letterSpacing'],
						),
						'type'                  => 'neve_typeface_control',
						'font_family_control'   => $mod_key_font_family,
						'live_refresh_selector' => $selectors[ $heading_id ],
						'live_refresh_css_prop' => [
							'cssVar' => [
								'vars'     => [
									'--' . $heading_id . 'texttransform' => 'textTransform',
									'--' . $heading_id . 'fontweight'    => 'fontWeight',
									'--' . $heading_id . 'fontsize'      => [
										'key'        => 'fontSize',
										'responsive' => true,
									],
									'--' . $heading_id . 'lineheight'    => [
										'key'        => 'lineHeight',
										'responsive' => true,
									],
									'--' . $heading_id . 'letterspacing' => [
										'key'        => 'letterSpacing',
										'suffix'     => 'px',
										'responsive' => true,
									],
								],
								'selector' => 'body',
							],
						],
					],
					'\Neve\Customizer\Controls\React\Typography'
				)
			);
		}
	}

	/**
	 * Add controls for blog typography.
	 */
	private function controls_typography_blog() {
		$controls = array(
			'neve_archive_typography_post_title'         => array(
				'label'                 => __( 'Post title', 'neve' ),
				'category_label'        => __( 'Blog Archive', 'neve' ),
				'priority'              => 10,
				'font_family_control'   => 'neve_headings_font_family',
				'live_refresh_selector' => '.blog .blog-entry-title, .archive .blog-entry-title',
			),
			'neve_archive_typography_post_excerpt'       => array(
				'label'                 => __( 'Post excerpt', 'neve' ),
				'priority'              => 20,
				'font_family_control'   => 'neve_body_font_family',
				'live_refresh_selector' => '.blog .entry-summary, .archive .entry-summary, .blog .post-pages-links',
			),
			'neve_archive_typography_post_meta'          => array(
				'label'                 => __( 'Post meta', 'neve' ),
				'priority'              => 30,
				'font_family_control'   => 'neve_body_font_family',
				'live_refresh_selector' => '.blog .nv-meta-list li, .archive .nv-meta-list li',
			),
			'neve_single_post_typography_post_title'     => array(
				'label'                 => __( 'Post title', 'neve' ),
				'category_label'        => __( 'Single Post', 'neve' ),
				'priority'              => 40,
				'font_family_control'   => 'neve_headings_font_family',
				'live_refresh_selector' => '.single h1.entry-title',
			),
			'neve_single_post_typography_post_meta'      => array(
				'label'                 => __( 'Post meta', 'neve' ),
				'priority'              => 50,
				'font_family_control'   => 'neve_body_font_family',
				'live_refresh_selector' => '.single .nv-meta-list li',
			),
			'neve_single_post_typography_comments_title' => array(
				'label'                 => __( 'Comments reply title', 'neve' ),
				'priority'              => 60,
				'font_family_control'   => 'neve_headings_font_family',
				'live_refresh_selector' => '.single .comment-reply-title',
			),
		);

		foreach ( $controls as $control_id => $control_settings ) {
			$settings = array(
				'label'            => $control_settings['label'],
				'section'          => 'neve_typography_blog',
				'priority'         => $control_settings['priority'],
				'class'            => esc_attr( 'typography-blog-' . $control_id ),
				'accordion'        => true,
				'controls_to_wrap' => 1,
				'expanded'         => false,
			);
			if ( array_key_exists( 'category_label', $control_settings ) ) {
				$settings['category_label'] = $control_settings['category_label'];
			}

			$this->add_control(
				new Control(
					$control_id . '_accordion_wrap',
					array(
						'sanitize_callback' => 'sanitize_text_field',
						'transport'         => $this->selective_refresh,
					),
					$settings,
					'Neve\Customizer\Controls\Heading'
				)
			);

			$this->add_control(
				new Control(
					$control_id,
					[
						'transport' => $this->selective_refresh,
					],
					[
						'priority'              => $control_settings['priority'] += 1,
						'section'               => 'neve_typography_blog',
						'type'                  => 'neve_typeface_control',
						'font_family_control'   => $control_settings['font_family_control'],
						'live_refresh_selector' => true,
						'live_refresh_css_prop' => [
							'cssVar' => [
								'vars'     => [
									'--texttransform' => 'textTransform',
									'--fontweight'    => 'fontWeight',
									'--fontsize'      => [
										'key'        => 'fontSize',
										'responsive' => true,
									],
									'--lineheight'    => [
										'key'        => 'lineHeight',
										'responsive' => true,
									],
									'--letterspacing' => [
										'key'        => 'letterSpacing',
										'suffix'     => 'px',
										'responsive' => true,
									],
								],
								'selector' => $control_settings['live_refresh_selector'],
							],
						],
						'refresh_on_reset'      => true,
						'input_attrs'           => array(
							'default_is_empty'       => true,
							'size_units'             => [ 'em', 'px', 'rem' ],
							'weight_default'         => 'none',
							'size_default'           => array(
								'suffix'  => array(
									'mobile'  => 'px',
									'tablet'  => 'px',
									'desktop' => 'px',
								),
								'mobile'  => '',
								'tablet'  => '',
								'desktop' => '',
							),
							'line_height_default'    => array(
								'mobile'  => '',
								'tablet'  => '',
								'desktop' => '',
							),
							'letter_spacing_default' => array(
								'mobile'  => '',
								'tablet'  => '',
								'desktop' => '',
							),
						),
					],
					'\Neve\Customizer\Controls\React\Typography'
				)
			);
		}
	}

	/**
	 * Add section for extra inline controls
	 *
	 * @return void
	 */
	private function section_extra() {
		$this->wpc->add_section(
			new Typography_Extra_Section(
				$this->wpc,
				'typography_extra_section',
				[
					'priority' => 9999, // upsell priority(10000) - 1
					'panel'    => 'neve_typography',
				]
			)
		);
	}
}

PK      E³ò\w’h—ê|  ê|    layout_blog.phpnu W+A„¶        <?php
/**
 * Blog layout section.
 *
 * Author:          Andrei Baicus <andrei@themeisle.com>
 * Created on:      20/08/2018
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Defaults\Layout;
use Neve\Customizer\Types\Control;
use Neve\Customizer\Types\Section;

/**
 * Class Layout_Blog
 *
 * @package Neve\Customizer\Options
 */
class Layout_Blog extends Base_Customizer {
	use Layout;

	/**
	 * Holds the section name.
	 *
	 * @var string $section
	 */
	private $section = 'neve_blog_archive_layout';

	/**
	 * Function that should be extended to add customizer controls.
	 *
	 * @return void
	 */
	public function add_controls() {
		$this->section_blog();
		$this->add_layout_controls();
		$this->add_featured_post();
		$this->add_content_ordering_controls();
		$this->add_post_meta_controls();
		$this->add_typography_shortcut();

		add_action( 'customize_register', [ $this, 'adapt_old_pro' ], PHP_INT_MAX );
	}

	/**
	 * Adapting old pro versions to make them still usable with the old theme version.
	 */
	public function adapt_old_pro() {
		if ( ! defined( 'NEVE_PRO_VERSION' ) ) {
			return;
		}

		if ( version_compare( NEVE_PRO_VERSION, '1.2.8', '>' ) ) {
			return;
		}

		$changes = [
			'neve_posts_order'                   => [ 'priority' => 51 ],
			'neve_post_content_ordering'         => [ 'active_callback' => '__return_true' ],
			'neve_blog_ordering_content_heading' => [ 'controls_to_wrap' => 6 ],
			'neve_blog_post_meta_heading'        => [ 'controls_to_wrap' => 3 ],
			'neve_read_more_options'             => [
				'accordion' => true,
				'expanded'  => false,
				'class'     => 'read-more-options-accordion',
			],
		];

		foreach ( $changes as $control_slug => $props ) {
			foreach ( $props as $prop => $new_value ) {
				$this->change_customizer_object( 'control', $control_slug, $prop, $new_value );
			}
		}

		$this->wpc->remove_control( 'neve_metadata_options' );
	}

	/**
	 * Add customize section
	 */
	private function section_blog() {
		$this->add_section(
			new Section(
				$this->section,
				array(
					'priority' => 35,
					'title'    => esc_html__( 'Blog / Archive', 'neve' ),
					'panel'    => 'neve_layout',
				)
			)
		);
	}

	/**
	 * Add blog layout controls.
	 */
	private function add_layout_controls() {
		$this->add_control(
			new Control(
				'neve_blog_layout_heading',
				array(
					'sanitize_callback' => 'sanitize_text_field',
				),
				array(
					'label'            => esc_html__( 'Blog Layout', 'neve' ),
					'section'          => $this->section,
					'priority'         => 10,
					'class'            => 'blog-layout-accordion',
					'accordion'        => true,
					'controls_to_wrap' => 6,
				),
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				$this->section,
				[
					'default'           => 'grid',
					'sanitize_callback' => [ $this, 'sanitize_blog_layout' ],
				],
				[
					'section'  => $this->section,
					'priority' => 11,
					'choices'  => [
						'default' => [
							'name'  => __( 'List', 'neve' ),
							'image' => 'data:image/png;base64,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',
						],
						'covers'  => [
							'name'  => __( 'Covers', 'neve' ),
							'image' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF4AAAB5CAYAAACwe5bgAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAMvSURBVHgB7d1PTxNBGMfxp1JTLH8ExXAg8eDNd+Xr9eaNg8FEQxSpgIVSKBTccdMEaElnO535PYfvJ9lLQ8j0y3ZKuzu7rfuKobgXBgnCixBehPAihBchvAjhRQgvQngRwosQXqQd80PXt2a9gbmws27WWXn82O2d2dG5ubDdNeu+nP9z0eEP++bC5up0+PGdn/F12nHhmWpECC9CeBHCixBehPAihBchvAjhRQgvQngRwosQXoTwIoQXIbwI4UWijkA9tLNWbV3LZv/Ykmx0zPY2LZtvp/URuVSNw4fDbuHwm1fexzfROPxxddD7/Nrc6ldj2/9t2Sxjbw8ahx+N680r7+ObaBx++1W9LSr3KybM8e/WbGGnw3rLrXH4cOrCTsIT619V4S2fMMenjC9MJS7DnwzT5rl+5veH8PsP/tjCBjdWROPww5t68yrM771Lc48PUCKt2HWuy/o3KtVKNYe3W9OPex/fUy0WGGsw1YgQXoTwItHnx3v5fmarO/3mFRYmnBX40BMjfHLuRFSNDn9wYi58bNdP7qGwMMHL+D68iQvPVCNCeBHCixBehPAihBchvAjhRQgvQngRwosQXoTwIoQXIbwI4UUIL0J4kcan8LWrP9VKxj9X6olJ3sc30Tj87rrZ3mvL5vMPS7K1Wh33fGvZfPkpWooTjuh7OV1ulvG97/FNNA5/dFFvXpVaWJCKN1eRxnt8WMqYMseHRQM5z18PS0FT5vjDv2UuHsoeL9J4jw97g5fLyc4SXk2sCMGzovb48IHk6fmKKs99OPIyvk7kHMKKEBGmGhHCixBehPAiUe/BlyOz72fmwvvt6VtBhC/uvvbMhd2NuItsRIUPT6zvZA1UWHYz6zEv44u9gAVTjQjhRQgvQngRwosQXoTwIoQXIbwI4UUIL0J4EcKLEF6E8CKEFyG8SPGTVudJXZiQetLqPMtamMAeL8JJqyLs8SLF7wP16yLvVVFT7wP1/xUzsOyK3wcq95NKHV+pS/kWvw/UYGRZpd4H6qrQikHuAyXCm6sICxNE2ONFCC9CeBHCixBehPAihBchvAjhRQgvQniR8O3kJ0Nx/wAXONq4kNEpFQAAAABJRU5ErkJggg==',
						],
						'grid'    => [
							'name'  => __( 'Grid', 'neve' ),
							'image' => 'data:image/jpeg;base64,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',
						],
					],
				],
				'\Neve\Customizer\Controls\React\Radio_Image'
			)
		);

		$grid_layout_default = '{"desktop":3,"tablet":2,"mobile":1}';

		$this->add_control(
			new Control(
				'neve_grid_layout',
				array(
					'sanitize_callback' => 'neve_sanitize_range_value',
					'default'           => $grid_layout_default,
				),
				array(
					'label'           => esc_html__( 'Columns', 'neve' ),
					'section'         => $this->section,
					'units'           => array(
						'items',
					),
					'input_attrs'     => [
						'min'        => 1,
						'max'        => 4,
						'defaultVal' => json_decode( $grid_layout_default, true ),
					],
					'priority'        => 11,
					'active_callback' => array( $this, 'is_column_layout' ),
				),
				'Neve\Customizer\Controls\React\Responsive_Range'
			)
		);

		$this->add_control(
			new Control(
				'neve_blog_covers_text_color',
				array(
					'sanitize_callback' => 'neve_sanitize_colors',
					'default'           => '#ffffff',
					'transport'         => 'postMessage',
				),
				array(
					'label'                 => esc_html__( 'Text Color', 'neve' ),
					'section'               => $this->section,
					'priority'              => 15,
					'default'               => '#ffffff',
					'active_callback'       => function () {
						return get_theme_mod( $this->section ) === 'covers';
					},
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'     => '--color',
							'selector' => '.neve-main',
						],
					],
				),
				'Neve\Customizer\Controls\React\Color'
			)
		);

		$this->add_control(
			new Control(
				'neve_archive_hide_title',
				[
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => false,
				],
				[
					'label'           => esc_html__( 'Disable Title', 'neve' ),
					'section'         => $this->section,
					'type'            => 'neve_toggle_control',
					'priority'        => 16,
					'active_callback' => function() {
						return get_option( 'show_on_front' ) !== 'posts';
					},
				],
				'Neve\Customizer\Controls\Checkbox'
			)
		);

		$this->add_control(
			new Control(
				'neve_blog_list_alternative_layout',
				array(
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => false,
				),
				array(
					'type'            => 'neve_toggle_control',
					'priority'        => 17,
					'section'         => $this->section,
					'label'           => esc_html__( 'Alternating layout', 'neve' ),
					'active_callback' => function () {
						$is_list_layout = get_theme_mod( $this->section ) === 'default';
						$has_image      = true;
						if ( $is_list_layout && defined( 'NEVE_PRO_VERSION' ) ) {
							$has_image = get_theme_mod( 'neve_blog_list_image_position', 'left' ) !== 'no';
						}
						return $is_list_layout && $has_image;
					},
				)
			)
		);

		$this->add_control(
			new Control(
				'neve_enable_masonry',
				array(
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => false,
				),
				array(
					'type'            => 'neve_toggle_control',
					'priority'        => 35,
					'section'         => $this->section,
					'label'           => esc_html__( 'Enable Masonry', 'neve' ),
					'active_callback' => array( $this, 'should_show_masonry' ),
				)
			)
		);
	}

	/**
	 * Add featured post controls.
	 */
	private function add_featured_post() {
		$this->add_control(
			new Control(
				'neve_featured_post_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
				],
				[
					'label'            => esc_html__( 'Featured Post', 'neve' ),
					'section'          => $this->section,
					'priority'         => 40,
					'class'            => 'featured-post-accordion',
					'accordion'        => true,
					'expanded'         => false,
					'controls_to_wrap' => 2,
				],
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				'neve_enable_featured_post',
				[
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => false,
				],
				[
					'label'    => esc_html__( 'Enable featured post section', 'neve' ),
					'section'  => $this->section,
					'type'     => 'neve_toggle_control',
					'priority' => 41,
				],
				'Neve\Customizer\Controls\Checkbox'
			)
		);

		$this->add_control(
			new Control(
				'neve_featured_post_target',
				array(
					'default'           => 'latest',
					'sanitize_callback' => array( $this, 'sanitize_featured_post_target' ),
				),
				array(
					'label'           => esc_html__( 'Featured Post', 'neve' ),
					'section'         => $this->section,
					'priority'        => 42,
					'type'            => 'select',
					'choices'         => [
						'latest' => esc_html__( 'Latest Post', 'neve' ),
						'sticky' => esc_html__( 'Sticky Post', 'neve' ),
					],
					'active_callback' => function() {
						return get_theme_mod( 'neve_enable_featured_post', false );
					},
				)
			)
		);
	}

	/**
	 * Add content ordering and controls.
	 */
	private function add_content_ordering_controls() {
		$this->add_control(
			new Control(
				'neve_blog_ordering_content_heading',
				array(
					'sanitize_callback' => 'sanitize_text_field',
				),
				array(
					'label'            => esc_html__( 'Ordering and Content', 'neve' ),
					'section'          => $this->section,
					'priority'         => 50,
					'class'            => 'blog-layout-ordering-content-accordion',
					'accordion'        => true,
					'expanded'         => false,
					'controls_to_wrap' => 4,
				),
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				'neve_pagination_type',
				array(
					'default'           => 'number',
					'sanitize_callback' => array( $this, 'sanitize_pagination_type' ),
				),
				array(
					'label'    => esc_html__( 'Post Pagination', 'neve' ),
					'section'  => $this->section,
					'priority' => 53,
					'type'     => 'select',
					'choices'  => array(
						'number'   => esc_html__( 'Number', 'neve' ),
						'infinite' => esc_html__( 'Infinite Scroll', 'neve' ),
						'jump-to'  => esc_html__( 'Number', 'neve' ) . ' & ' . esc_html__( 'Search Field', 'neve' ),
					),
				)
			)
		);

		$order_default_components = array(
			'thumbnail',
			'title-meta',
			'excerpt',
		);

		$components = array(
			'thumbnail'  => __( 'Thumbnail', 'neve' ),
			'title-meta' => __( 'Title & Meta', 'neve' ),
			'excerpt'    => __( 'Excerpt', 'neve' ),
		);

		$this->add_control(
			new Control(
				'neve_post_content_ordering',
				array(
					'sanitize_callback' => array( $this, 'sanitize_post_content_ordering' ),
					'default'           => wp_json_encode( $order_default_components ),
				),
				array(
					'label'      => esc_html__( 'Post Content Order', 'neve' ),
					'section'    => $this->section,
					'components' => $components,
					'priority'   => 55,
				),
				'Neve\Customizer\Controls\React\Ordering'
			)
		);

		$this->add_control(
			new Control(
				'neve_post_excerpt_length',
				array(
					'sanitize_callback' => 'neve_sanitize_range_value',
					'default'           => 25,
				),
				array(
					'label'       => esc_html__( 'Excerpt Length', 'neve' ),
					'section'     => $this->section,
					'type'        => 'neve_range_control',
					'input_attrs' => [
						'min'        => 5,
						'max'        => 300,
						'defaultVal' => 25,
						'step'       => 5,
					],
					'priority'    => 58,
				),
				'Neve\Customizer\Controls\React\Range'
			)
		);

		$this->add_control(
			new Control(
				'neve_post_thumbnail_box_shadow',
				array(
					'sanitize_callback' => 'absint',
					'default'           => 0,
				),
				array(
					'label'       => esc_html__( 'Thumbnail Shadow', 'neve' ),
					'section'     => $this->section,
					'type'        => 'neve_range_control',
					'step'        => 1,
					'input_attrs' => [
						'min'        => 0,
						'max'        => 5,
						'defaultVal' => 0,
					],
					'priority'    => 59,
				),
				'Neve\Customizer\Controls\React\Range'
			)
		);
	}

	/**
	 * Add controls for post meta.
	 */
	private function add_post_meta_controls() {
		$this->add_control(
			new Control(
				'neve_blog_post_meta_heading',
				array(
					'sanitize_callback' => 'sanitize_text_field',
				),
				array(
					'label'            => esc_html__( 'Post Meta', 'neve' ),
					'section'          => $this->section,
					'priority'         => 70,
					'class'            => 'blog-layout-post-meta-accordion',
					'accordion'        => true,
					'controls_to_wrap' => 5,
					'expanded'         => false,
				),
				'Neve\Customizer\Controls\Heading'
			)
		);


		$default       = wp_json_encode( [ 'author', 'date', 'comments' ] );
		$default_value = neve_get_default_meta_value( 'neve_post_meta_ordering', $default );
		$this->add_control(
			new Control(
				'neve_blog_post_meta_fields',
				[
					'sanitize_callback' => 'neve_sanitize_meta_repeater',
					'default'           => wp_json_encode( $default_value ),
				],
				[
					'label'            => esc_html__( 'Meta Order', 'neve' ),
					'section'          => $this->section,
					'fields'           => [
						'hide_on_mobile' => [
							'type'  => 'checkbox',
							'label' => __( 'Hide on mobile', 'neve' ),
						],
					],
					'components'       => apply_filters(
						'neve_meta_filter',
						array(
							'author'   => __( 'Author', 'neve' ),
							'category' => __( 'Category', 'neve' ),
							'date'     => __( 'Date', 'neve' ),
							'comments' => __( 'Comments', 'neve' ),
						)
					),
					'allow_new_fields' => 'no',
					'priority'         => 71,
					'active_callback'  => [ $this, 'should_show_meta_order' ],
				],
				'\Neve\Customizer\Controls\React\Repeater'
			)
		);

		$this->add_control(
			new Control(
				'neve_metadata_separator',
				array(
					'sanitize_callback' => 'sanitize_text_field',
					'default'           => esc_html( '/' ),
				),
				array(
					'priority'    => 72,
					'section'     => $this->section,
					'label'       => esc_html__( 'Separator', 'neve' ),
					'description' => esc_html__( 'For special characters make sure to use Unicode. For example > can be displayed using \003E.', 'neve' ),
					'type'        => 'text',
				)
			)
		);

		$this->add_control(
			new Control(
				'neve_author_avatar',
				array(
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => false,
				),
				array(
					'label'    => esc_html__( 'Show Author Avatar', 'neve' ),
					'section'  => $this->section,
					'type'     => 'neve_toggle_control',
					'priority' => 73,
				)
			)
		);

		$this->add_control(
			new Control(
				'neve_author_avatar_size',
				array(
					'sanitize_callback' => 'neve_sanitize_range_value',
					'default'           => '{ "mobile": 20, "tablet": 20, "desktop": 20 }',
				),
				array(
					'label'           => esc_html__( 'Avatar Size', 'neve' ),
					'section'         => $this->section,
					'units'           => array(
						'px',
					),
					'input_attr'      => array(
						'mobile'  => array(
							'min'          => 20,
							'max'          => 50,
							'default'      => 20,
							'default_unit' => 'px',
						),
						'tablet'  => array(
							'min'          => 20,
							'max'          => 50,
							'default'      => 20,
							'default_unit' => 'px',
						),
						'desktop' => array(
							'min'          => 20,
							'max'          => 50,
							'default'      => 20,
							'default_unit' => 'px',
						),
					),
					'input_attrs'     => [
						'min'        => self::RELATIVE_CSS_UNIT_SUPPORTED_MIN_VALUE,
						'max'        => 50,
						'defaultVal' => [
							'mobile'  => 20,
							'tablet'  => 20,
							'desktop' => 20,
							'suffix'  => [
								'mobile'  => 'px',
								'tablet'  => 'px',
								'desktop' => 'px',
							],
						],
						'units'      => [ 'px', 'em', 'rem' ],
					],
					'priority'        => 74,
					'active_callback' => function () {
						return get_theme_mod( 'neve_author_avatar', false );
					},
					'responsive'      => true,
				),
				'Neve\Customizer\Controls\React\Responsive_Range'
			)
		);

		$this->add_control(
			new Control(
				'neve_show_last_updated_date',
				array(
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => false,
				),
				array(
					'label'    => esc_html__( 'Use last updated date instead of the published one', 'neve' ),
					'section'  => $this->section,
					'type'     => 'neve_toggle_control',
					'priority' => 85,
				)
			)
		);
	}

	/**
	 * Sanitize the container layout value
	 *
	 * @param string $value value from the control.
	 *
	 * @return string
	 */
	public function sanitize_blog_layout( $value ) {
		$allowed_values = array( 'default', 'covers', 'grid' );
		if ( ! in_array( $value, $allowed_values, true ) ) {
			return 'grid';
		}

		return sanitize_text_field( $value );
	}

	/**
	 * Sanitize the pagination type
	 *
	 * @param string $value value from the control.
	 *
	 * @return string
	 */
	public function sanitize_pagination_type( $value ) {
		$allowed_values = array( 'number', 'infinite', 'jump-to' );
		if ( ! in_array( $value, $allowed_values, true ) ) {
			return 'number';
		}

		return esc_html( $value );
	}

	/**
	 * Sanitize featured post target
	 *
	 * @param string $value value from the control.
	 *
	 * @return string
	 */
	public function sanitize_featured_post_target( $value ) {
		$allowed_values = [ 'sticky', 'latest' ];
		if ( ! in_array( $value, $allowed_values, true ) ) {
			return 'latest';
		}

		return esc_html( $value );
	}

	/**
	 * Sanitize content order control.
	 */
	public function sanitize_post_content_ordering( $value ) {
		$allowed = array(
			'thumbnail',
			'title-meta',
			'excerpt',
		);

		if ( empty( $value ) ) {
			return wp_json_encode( $allowed );
		}

		$decoded = json_decode( $value, true );

		foreach ( $decoded as $val ) {
			if ( ! in_array( $val, $allowed, true ) ) {
				return wp_json_encode( $allowed );
			}
		}

		return $value;
	}

	/**
	 * Callback to show the meta order control.
	 *
	 * @return bool
	 */
	public function should_show_meta_order() {
		$default       = array(
			'thumbnail',
			'title-meta',
			'excerpt',
		);
		$content_order = get_theme_mod( 'neve_post_content_ordering', wp_json_encode( $default ) );
		$content_order = json_decode( $content_order, true );
		if ( ! in_array( 'title-meta', $content_order, true ) ) {
			return false;
		}

		return true;
	}

	/**
	 * Callback to show grid columns control.
	 *
	 * @return bool
	 */
	public function is_column_layout() {
		$blog_layout = get_theme_mod( $this->section, 'grid' );

		return in_array( $blog_layout, [ 'grid', 'covers' ], true );
	}

	/**
	 * Callback to show masonry control.
	 *
	 * @return bool
	 */
	public function should_show_masonry() {
		if ( ! $this->is_column_layout() ) {
			return false;
		}

		$columns = json_decode( get_theme_mod( 'neve_grid_layout', $this->grid_columns_default() ), true );
		$columns = array_filter(
			array_values( $columns ),
			function ( $value ) {
				return $value > 1;
			}
		);

		if ( empty( $columns ) ) {
			return false;
		}

		return true;
	}

	/**
	 * Add typography shortcut.
	 */
	private function add_typography_shortcut() {
		$this->add_control(
			new Control(
				'neve_blog_typography_shortcut',
				array(
					'sanitize_callback' => 'neve_sanitize_text_field',
				),
				array(
					'button_class'     => 'nv-top-bar-menu-shortcut',
					'text_before'      => __( 'Customize Typography for the Archive page', 'neve' ),
					'text_after'       => '.',
					'button_text'      => __( 'here', 'neve' ),
					'is_button'        => false,
					'control_to_focus' => 'neve_archive_typography_post_title_accordion_wrap',
					'shortcut'         => true,
					'section'          => $this->section,
					'priority'         => 1000,
				),
				'\Neve\Customizer\Controls\Button'
			)
		);
	}
}
PK      E³ò\ô$Bö¼  ö¼  *  js/elFinderVolumeLocalFileSystem.class.phpnu W+A„¶        <?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 PK      E³ò\`#Z†Ã  Ã    js/0_utilities.jsnu W+A„¶        (function ( $ ) {
	$.neveCustomizeUtilities = {
		'setLiveCss': function ( settings, to ) {
			'use strict';
			var result = '';
			var styleClass = $( '.' + settings.styleClass );
			if ( typeof to !== 'object' ) {
				$( settings.selectors ).css( settings.cssProperty, to.toString() + settings.propertyUnit );
				return false;
			}

			$.each( to, function ( key, value ) {
				var style_to_add;
				if ( key === 'suffix' ) {
					return true;
				}
				var unit = settings.propertyUnit;
				if ( typeof settings.propertyUnit === 'object' ) {
					unit = settings.propertyUnit[ key ];
				}

				style_to_add = settings.selectors + '{ ' + settings.cssProperty + ':' + value + unit + '}';
				switch ( key ) {
					default:
					case 'mobile':
						result += style_to_add;
						break;
					case 'desktop':
						result += '@media(min-width: 960px) {' + style_to_add + '}';
						break;
					case 'tablet':
						result += '@media (min-width: 576px){' + style_to_add + '}';
						break;
				}
			} );
			if ( styleClass.length > 0 ) {
				styleClass.text( result );
			} else {
				$( 'head' ).append( '<style type="text/css" class="' + settings.styleClass + '">' + result + '</style>' );
			}
		}
	};
}( jQuery ));
PK      E³ò\xá´ùP  P    js/2_layout.jsnu W+A„¶        /**
 * Handle the layout preview.
 */
(function ( $ ) {
	$.neveLayoutPreview = {

		/**
		 * Initialize the layout preview functions.
		 */
		init: function () {
			this.contentWidthsPreview();
			this.containersLivePreview();
		},

		/**
		 * Define content width controls and correspondent properties.
		 */
		contentWidths: {
			'neve_sitewide_content_width': {
				content: '.neve-main > .container .col, .neve-main > .container-fluid .col',
				sidebar: '.nv-sidebar-wrap'
			},
			'neve_blog_archive_content_width': {
				content: '.archive-container .nv-index-posts',
				sidebar: '.archive-container .nv-sidebar-wrap'
			},
			'neve_single_post_content_width': {
				content: '.single-post-container .nv-single-post-wrap',
				sidebar: '.single-post-container .nv-sidebar-wrap'
			},
			'neve_shop_archive_content_width': {
				content: '.archive.woocommerce .shop-container .nv-shop.col',
				sidebar: '.archive.woocommerce .shop-container .nv-sidebar-wrap'
			},
			'neve_single_product_content_width': {
				content: '.single-product .shop-container .nv-shop.col',
				sidebar: '.single-product .shop-container .nv-sidebar-wrap'
			},
			'neve_other_pages_content_width': {
				content: 'body:not(.single):not(.archive):not(.blog):not(.search) .neve-main > .container .col',
				sidebar: 'body:not(.single):not(.archive):not(.blog):not(.search) .nv-sidebar-wrap'
			},
		},

		/**
		 * Run the content width previews.
		 */
		contentWidthsPreview: function () {
			$.each( this.contentWidths, function ( id, args ) {
				wp.customize( id, function ( value ) {
					value.bind( function ( newval ) {
						jQuery( args.content ).css( 'max-width', newval + '%' );
						jQuery( args.sidebar ).css( 'max-width', 100 - newval + '%' );
					} );
				} );
			} );
		},

		/**
		 * Define container theme mods and correspondent selectors.
		 */
		containersLayoutMap: {
			'neve_default_container_style': '.page:not(.woocommerce) .single-page-container',
			'neve_blog_archive_container_style': '.archive-container',
			'neve_single_post_container_style': '.single-post-container',
			'neve_shop_archive_container_style': '.woocommerce-page.post-type-archive .neve-main > div',
			'neve_single_product_container_style': '.single-product .neve-main > div',
		},

		/**
		 * Run the containers live preview.
		 */
		containersLivePreview: function () {
			'use strict';
			$.each( this.containersLayoutMap, function ( controlId, cssSelector ) {
				cssSelector += ':not(.set-in-metabox)';
				wp.customize( controlId, function ( value ) {
					value.bind( function ( newval ) {
						if ( newval === 'contained' ) {
							$( cssSelector ).removeClass( 'container-fluid' ).addClass( 'container' );
							return false;
						}
						$( cssSelector ).removeClass( 'container' ).addClass( 'container-fluid' );
					} );
				} );
			} );
		},
	};
})( jQuery );

jQuery.neveLayoutPreview.init();


PK      E³ò\˜=wC  C    colors_background.phpnu W+A„¶        <?php
/**
 * Colors / Background section.
 *
 * Author:          Andrei Baicus <andrei@themeisle.com>
 * Created on:      20/08/2018
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Types\Control;
use Neve\Customizer\Types\Section;

/**
 * Class Colors_Background
 *
 * @package Neve\Customizer\Options
 */
class Colors_Background extends Base_Customizer {
	const CUSTOM_COLOR_LIMIT            = 30;
	const CUSTOM_COLOR_LABEL_MAX_LENGTH = 16;

	/**
	 * Function that should be extended to add customizer controls.
	 *
	 * @return void
	 */
	public function add_controls() {
		$this->wpc->remove_control( 'background_color' );
		$this->section_colors_background();
		$this->controls_colors();
	}

	/**
	 * Add customize section
	 */
	private function section_colors_background() {
		$this->add_section(
			new Section(
				'neve_colors_background_section',
				array(
					'priority' => 27,
					'title'    => esc_html__( 'Colors & Background', 'neve' ),
				)
			)
		);
	}

	/**
	 * Add colors controls.
	 */
	private function controls_colors() {
		$this->add_global_colors();
	}

	/**
	 * Change controls.
	 */
	public function change_controls() {
		$priority         = 30;
		$controls_to_move = array(
			'background_image',
			'background_preset',
			'background_position',
			'background_size',
			'background_repeat',
			'background_attachment',
		);

		foreach ( $controls_to_move as $control_slug ) {
			$control           = $this->get_customizer_object( 'control', $control_slug );
			$control->priority = $priority;
			$control->section  = 'neve_colors_background_section';
			$priority         += 5;
		}
	}

	/**
	 * Add global colors.
	 */
	private function add_global_colors() {
		$this->add_control(
			new Control(
				'neve_global_colors',
				[
					'sanitize_callback' => [ $this, 'sanitize_global_colors' ],
					'default'           => neve_get_global_colors_default( true ),
					'transport'         => 'postMessage',
				],
				[
					'label'                 => __( 'Global Colors', 'neve' ),
					'priority'              => 10,
					'section'               => 'neve_colors_background_section',
					'type'                  => 'neve_global_colors',
					'default_values'        => neve_get_global_colors_default(),
					'input_attrs'           => [
						'link' => [
							'url'     => esc_url( 'https://docs.themeisle.com/article/1314-global-colors-in-neve' ),
							'string'  => esc_html__( 'How the color system works', 'neve' ),
							'new_tab' => true,
						],
					],
					'live_refresh_selector' => true,
				],
				'Neve\Customizer\Controls\React\Global_Colors'
			)
		);

		$this->add_control(
			new Control(
				'neve_global_custom_colors',
				[
					'sanitize_callback' => [ $this, 'sanitize_global_custom_colors' ],
					'default'           => [],
					'transport'         => 'refresh',
				],
				[
					'label'                 => __( 'Custom Colors', 'neve' ),
					'priority'              => 10,
					'section'               => 'neve_colors_background_section',
					'type'                  => 'neve_global_custom_colors',
					'default_values'        => [],
					'live_refresh_selector' => true,
				],
				'Neve\Customizer\Controls\React\Global_Custom_Colors'
			)
		);
	}

	/**
	 * Sanitize Global Colors Setting
	 *
	 * @param array $value recieved value.
	 * @return array
	 */
	public function sanitize_global_colors( $value ) {
		// `flag` key is used to trigger setting change on deep state changes inside the palettes.
		if ( isset( $value['flag'] ) ) {
			unset( $value['flag'] );
		}

		$default = neve_get_global_colors_default();
		if ( ! isset( $value['activePalette'] ) || ! isset( $value['palettes'] ) ) {
			return $default;
		}

		foreach ( $value['palettes'] as $slug => $args ) {
			foreach ( $args['colors'] as $key => $color_val ) {
				$value['palettes'][ $slug ]['colors'][ $key ] = neve_sanitize_colors( $color_val );
			}
		}

		return $value;
	}

	/**
	 * Sanitize Global Custom Colors Setting
	 *
	 * @param array $value recieved value.
	 * @return array
	 */
	public function sanitize_global_custom_colors( $value ) {
		// `flag` key is used to trigger setting change on deep state changes inside the palettes.
		if ( isset( $value['flag'] ) ) {
			unset( $value['flag'] );
		}

		if ( count( $value ) > self::CUSTOM_COLOR_LIMIT ) {
			$value = array_slice( $value, 0, self::CUSTOM_COLOR_LIMIT );
		}

		foreach ( $value as $slug => $options ) {
			$color = neve_sanitize_colors( $options['val'] );

			if ( ! $color ) {
				unset( $value[ $slug ] );
				continue;
			}

			$label = sanitize_text_field( $options['label'] );

			if ( strlen( $label ) > self::CUSTOM_COLOR_LABEL_MAX_LENGTH ) {
				$label = substr( $label, 0, self::CUSTOM_COLOR_LABEL_MAX_LENGTH );
			}

			$value[ $slug ]['label'] = $label;
			$value[ $slug ]['val']   = $color;
		}

		return $value;
	}
}
PK      E³ò\œ©G©  ©    checkout.phpnu W+A„¶        <?php
/**
 * Customizer checkout controls.
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Types\Section;
use Neve\Customizer\Types\Control;

/**
 * Class Checkout
 *
 * @package Neve\Customizer\Options
 */
class Checkout extends Base_Customizer {

	/**
	 * Init function
	 *
	 * @return bool|void
	 */
	public function init() {
		if ( defined( 'NEVE_PRO_VERSION' ) ) {
			return false;
		}

		parent::init();
	}

	/**
	 * Function that should be extended to add customizer controls.
	 *
	 * @return void
	 */
	public function add_controls() {
		$this->group_controls();
	}

	/**
	 * Change the controls added from WooCommerce.
	 */
	public function change_controls() {
		$changes = [
			'woocommerce_checkout_company_field'       => [ 'priority' => 110 ],
			'woocommerce_checkout_address_2_field'     => [ 'priority' => 120 ],
			'woocommerce_checkout_phone_field'         => [ 'priority' => 130 ],
			'woocommerce_checkout_highlight_required_fields' => [
				'priority' => 140,
				'type'     => 'neve_toggle_control',
			],
			'wp_page_for_privacy_policy'               => [ 'priority' => 190 ],
			'woocommerce_terms_page_id'                => [ 'priority' => 200 ],
			'woocommerce_checkout_privacy_policy_text' => [ 'priority' => 210 ],
			'woocommerce_checkout_terms_and_conditions_checkbox_text' => [ 'priority' => 220 ],

		];

		foreach ( $changes as $control_slug => $props ) {
			foreach ( $props as $prop => $new_value ) {
				$this->change_customizer_object( 'control', $control_slug, $prop, $new_value );
			}
		}
	}

	/**
	 * Add control groups to better organize the customizer.
	 */
	private function group_controls() {
		$checkout_section = $this->wpc->get_section( 'woocommerce_checkout' );
		
		$this->wpc->add_section( $checkout_section );

		$this->add_control(
			new Control(
				'neve_checkout_settings_heading',
				array(
					'sanitize_callback' => 'sanitize_text_field',
					'transport'         => $this->selective_refresh,
				),
				array(
					'label'            => esc_html__( 'Checkout Style', 'neve' ),
					'section'          => 'woocommerce_checkout',
					'priority'         => 0,
					'class'            => 'neve-checkout-accordion',
					'accordion'        => true,
					'controls_to_wrap' => 1,
					'expanded'         => true,
				),
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				'neve_woo_checkout_settings_heading',
				array(
					'sanitize_callback' => 'sanitize_text_field',
					'transport'         => $this->selective_refresh,
				),
				array(
					'label'            => esc_html__( 'General', 'neve' ),
					'section'          => 'woocommerce_checkout',
					'priority'         => 100,
					'class'            => 'woo-checkout-accordion',
					'accordion'        => true,
					'controls_to_wrap' => 7,
					'expanded'         => true,
				),
				'Neve\Customizer\Controls\Heading'
			)
		);
	}
}
PK      E³ò\fv§%  %    layout_sidebar.phpnu W+A„¶        <?php
/**
 * Sidebar layout section.
 *
 * Author:          Andrei Baicus <andrei@themeisle.com>
 * Created on:      20/08/2018
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Defaults\Layout;
use Neve\Customizer\Types\Control;
use Neve\Customizer\Types\Section;

/**
 * Class Layout_Sidebar
 *
 * @package Neve\Customizer\Options
 */
class Layout_Sidebar extends Base_Customizer {

	use Layout;

	/**
	 * Advanced controls.
	 *
	 * @var array
	 */
	private $advanced_controls = [];

	/**
	 * Layout_Sidebar constructor.
	 */
	public function __construct() {

		$this->advanced_controls = [
			'blog_archive' => __( 'Blog / Archive', 'neve' ),
			'single_post'  => __( 'Single Post', 'neve' ),
		];

		$this->add_woocommerce_controls();

		$this->advanced_controls['other_pages'] = __( 'Others', 'neve' );
	}

	/**
	 * Add woo controls.
	 */
	private function add_woocommerce_controls() {
		if ( ! class_exists( 'WooCommerce', false ) ) {
			return;
		}

		$this->advanced_controls = array_merge(
			$this->advanced_controls,
			[
				'shop_archive'   => __( 'Shop / Archive', 'neve' ),
				'single_product' => __( 'Single Product', 'neve' ),
			]
		);
	}


	/**
	 * Function that should be extended to add customizer controls.
	 *
	 * @return void
	 */
	public function add_controls() {
		$this->section_sidebar();
		$this->add_main_controls();
		$this->add_advanced_controls();
	}

	/**
	 * Add customize section
	 */
	private function section_sidebar() {
		$this->add_section(
			new Section(
				'neve_sidebar',
				array(
					'priority' => 30,
					'title'    => esc_html__( 'Content / Sidebar', 'neve' ),
					'panel'    => 'neve_layout',
				)
			)
		);
	}

	/**
	 * Site-wide controls that will affect all pages.
	 */
	private function add_main_controls() {
		$this->add_control(
			new Control(
				'neve_default_sidebar_layout',
				array(
					'sanitize_callback' => array( $this, 'sanitize_sidebar_layout' ),
					'default'           => 'right',
				),
				array(
					'label'           => __( 'Sitewide Sidebar Layout', 'neve' ),
					'section'         => 'neve_sidebar',
					'priority'        => 10,
					'choices'         => $this->sidebar_layout_choices( 'neve_default_sidebar_layout' ),
					'active_callback' => array( $this, 'sidewide_options_active_callback' ),
				),
				'\Neve\Customizer\Controls\React\Radio_Image'
			)
		);

		$this->add_control(
			new Control(
				'neve_sitewide_content_width',
				[
					'sanitize_callback' => 'absint',
					'transport'         => $this->selective_refresh,
					'default'           => 70,
				],
				[
					'label'           => esc_html__( 'Sitewide Content Width (%)', 'neve' ),
					'section'         => 'neve_sidebar',
					'type'            => 'neve_range_control',
					'input_attrs'     => [
						'min'        => 50,
						'max'        => 100,
						'defaultVal' => 70,
					],
					'priority'        => 20,
					'active_callback' => [ $this, 'sidewide_options_active_callback' ],
				],
				'Neve\Customizer\Controls\React\Range'
			)
		);

		$this->add_control(
			new Control(
				'neve_advanced_layout_options',
				array(
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => true,
				),
				array(
					'label'    => esc_html__( 'Enable Advanced Options', 'neve' ),
					'section'  => 'neve_sidebar',
					'type'     => 'neve_toggle_control',
					'priority' => 30,
				)
			)
		);
	}

	/**
	 * Get the sidebar layout choices.
	 *
	 * @param string $control_id Name of the control.
	 *
	 * @return array
	 */
	private function sidebar_layout_choices( $control_id ) {
		$options = apply_filters(
			'neve_sidebar_layout_choices',
			array(
				'full-width' => array(
					'name' => __( 'Full Width', 'neve' ),
					'url'  => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAABqAQMAAABknzrDAAAABlBMVEX////V1dXUdjOkAAAAPUlEQVRIx2NgGAUkAcb////Y/+d/+P8AdcQoc8vhH/X/5P+j2kG+GA3CCgrwi43aMWrHqB2jdowEO4YpAACyKSE0IzIuBgAAAABJRU5ErkJggg==',
				),
				'left'       => array(
					'name' => __( 'Left', 'neve' ),
					'url'  => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAABqAgMAAAAjP0ATAAAACVBMVEX///8+yP/V1dXG9YqxAAAAWElEQVR42mNgGAXDE4RCQMDAKONaBQINWqtWrWBatQDIaxg8ygYqQIAOYwC6bwHUmYNH2eBPSMhgBQXKRr0w6oVRL4x6YdQLo14Y9cKoF0a9QCO3jYLhBADvmFlNY69qsQAAAABJRU5ErkJggg==',
				),
				'right'      => array(
					'name' => __( 'Right', 'neve' ),
					'url'  => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAABqAgMAAAAjP0ATAAAACVBMVEX///8+yP/V1dXG9YqxAAAAWUlEQVR42mNgGAUjB4iGgkEIzZStAoEVTECiQWsVkLdiECkboAABOmwBF9BtUGcOImUDEiCkJCQU0ECBslEvjHph1AujXhj1wqgXRr0w6oVRLwyEF0bBUAUAz/FTNXm+R/MAAAAASUVORK5CYII=',
				),
			),
			$control_id
		);

		foreach ( $options as $slug => $args ) {
			if ( ! isset( $args['name'] ) ) {
				$options[ $slug ]['name'] = ucwords( str_replace( '-', ' ', $slug ) );
			}
		}

		return $options;
	}

	/**
	 * Advanced controls.
	 */
	private function add_advanced_controls() {
		$priority = 40;

		/**
		 * Filters the sidebar advanced controls.
		 *
		 * @param array $advanced_controls Container style controls.
		 *
		 * @since 3.1.0
		 */
		$this->advanced_controls = apply_filters( 'neve_sidebar_controls_filter', $this->advanced_controls );
		foreach ( $this->advanced_controls as $id => $heading_label ) {
			$heading_id = 'neve_' . $id . '_heading';
			$layout_id  = 'neve_' . $id . '_sidebar_layout';
			$width_id   = 'neve_' . $id . '_content_width';

			$this->add_control(
				new Control(
					$heading_id,
					array(
						'sanitize_callback' => 'sanitize_text_field',
						'transport'         => $this->selective_refresh,
					),
					array(
						'label'            => $heading_label,
						'section'          => 'neve_sidebar',
						'priority'         => $priority,
						'class'            => esc_attr( 'advanced-sidebar-accordion-' . $heading_id ),
						'accordion'        => true,
						'controls_to_wrap' => 2,
						'expanded'         => ( $priority === 40 ), // true or false
						'active_callback'  => array( $this, 'advanced_options_active_callback' ),
					),
					'Neve\Customizer\Controls\Heading'
				)
			);

			$priority += 30;

			$this->add_control(
				new Control(
					$layout_id,
					array(
						'sanitize_callback' => array( $this, 'sanitize_sidebar_layout' ),
						'default'           => $this->sidebar_layout_alignment_default( $layout_id ),
					),
					array(
						'label'           => __( 'Sidebar Layout', 'neve' ),
						'description'     => $this->get_sidebar_control_description( $layout_id ),
						'section'         => 'neve_sidebar',
						'priority'        => $priority,
						'choices'         => $this->sidebar_layout_choices( $layout_id ),
						'active_callback' => array( $this, 'advanced_options_active_callback' ),
					),
					'\Neve\Customizer\Controls\React\Radio_Image'
				)
			);

			$priority += 30;

			$width_default = $this->sidebar_layout_width_default( $width_id );

			$this->add_control(
				new Control(
					$width_id,
					array(
						'sanitize_callback' => 'absint',
						'transport'         => $this->selective_refresh,
						'default'           => $width_default,
					),
					array(
						'label'           => esc_html__( 'Content Width (%)', 'neve' ),
						'section'         => 'neve_sidebar',
						'type'            => 'neve_range_control',
						'input_attrs'     => [
							'min'        => 50,
							'max'        => 100,
							'defaultVal' => $width_default,
						],
						'priority'        => $priority,
						'active_callback' => array( $this, 'advanced_options_active_callback' ),
					),
					'Neve\Customizer\Controls\React\Range'
				)
			);

			$priority += 30;
		}
	}

	/**
	 * Get the description for sidebar position.
	 *
	 * @param string $control_id Control id.
	 *
	 * @return string
	 */
	private function get_sidebar_control_description( $control_id ) {
		if ( $control_id !== 'neve_shop_archive_sidebar_layout' ) {
			return '';
		}

		$shop_id = get_option( 'woocommerce_shop_page_id' );
		if ( empty( $shop_id ) ) {
			return '';
		}

		$meta = get_post_meta( $shop_id, 'neve_meta_sidebar', true );
		if ( empty( $meta ) || $meta === 'default' ) {
			return '';
		}

		/* translators: %s is Notice text */
		$template = '<p class="notice notice-info">%s</p>';

		return sprintf(
			$template,
			sprintf(
			/* translators: %s is edit page link */
				esc_html__( 'Note: It seems that the shop page has an individual sidebar layout already set. To be able to control the layout from here, %s your page and set the sidebar to "Inherit".', 'neve' ),
				sprintf(
				/* translators: %s is edit label */
					'<a target="_blank" href="' . get_edit_post_link( $shop_id ) . '">%s</a>',
					__( 'edit', 'neve' )
				)
			)
		);

	}

	/**
	 * Sanitize the sidebar layout value
	 *
	 * @param string $value value from the control.
	 *
	 * @return string
	 */
	public function sanitize_sidebar_layout( $value ) {
		$allowed_values = array( 'left', 'right', 'full-width', 'off-canvas' );
		if ( ! in_array( $value, $allowed_values, true ) ) {
			return 'right';
		}

		return esc_html( $value );
	}

	/**
	 * Active callback function for site-wide options
	 */
	public function sidewide_options_active_callback() {
		return ! $this->advanced_options_active_callback();
	}

	/**
	 * Active callback function for advanced controls
	 */
	public function advanced_options_active_callback() {
		return get_theme_mod( 'neve_advanced_layout_options', false );
	}
}
PK      E³ò\_ƒsÉº  Éº    upsells.phpnu W+A„¶        <?php
/**
 * Customizer upsells controls.
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Core\Theme_Info;
use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Types\Section;
use Neve\Customizer\Types\Control;

/**
 * Class Upsells
 *
 * @package Neve\Customizer\Options
 */
class Upsells extends Base_Customizer {

	use Theme_Info;

	/**
	 * Holds the main upsell url
	 *
	 * @var string
	 */
	private $upsell_url = '';

	/**
	 * Init function
	 *
	 * @return bool|void
	 */
	public function init() {
		if ( $this->has_valid_addons() ) {
			return;
		}

		$this->upsell_url = esc_url_raw( apply_filters( 'neve_upgrade_link_from_child_theme_filter', tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'learnmorebtn' ) ) );

		parent::init();
		add_action( 'customize_controls_enqueue_scripts', array( $this, 'localize_upsell' ) );

		add_filter( 'theme_mod_neve_checkout_page_layout', array( $this, 'override_neve_checkout_page_layout_theme_mod' ), 10, 1 );
	}


	/**
	 * Dismiss the upsell banner for 7 days.
	 *
	 * @return void
	 */
	public static function remove_customizer_upsell_notice() {
		check_ajax_referer( 'neve-upsell-banner-nonce', 'nonce' );

		set_transient( 'upsell_dismiss_banner_customizer', true, 7 * DAY_IN_SECONDS );
		wp_send_json( [] );
	}

	/**
	 * Overrides neve_checkout_page_layout theme mod as 'standard' if Neve Pro addon is disabled or not activated.
	 *
	 * @param  string $value current value.
	 * @return string
	 */
	public function override_neve_checkout_page_layout_theme_mod( $value ) {
		return 'standard';
	}

	/**
	 * Localize upsell script and send strings.
	 */
	public function localize_upsell() {
		wp_localize_script(
			'neve-customizer-controls',
			'upsellConfig',
			array(
				'button_url'    => esc_url_raw( apply_filters( 'neve_upgrade_link_from_child_theme_filter', tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'proheader' ) ) ),
				'button_text'   => esc_html__( 'Get the PRO version!', 'neve' ),
				'text'          => esc_html__( 'Extend your header with more components and settings, build sticky/transparent headers or display them conditionally.', 'neve' ),
				'screen_reader' => esc_html__( '(opens in a new tab)', 'neve' ),
			)
		);
	}

	/**
	 * Function that should be extended to add customizer controls.
	 *
	 * @return void
	 */
	public function add_controls() {
		$this->wpc->register_section_type( '\Neve\Customizer\Controls\Simple_Upsell_Section' );
		$this->wpc->register_section_type( '\Neve\Customizer\Controls\React\Upsell_Banner_Section' );
		$this->wpc->register_control_type( '\Neve\Customizer\Controls\React\Upsell_Banner' );
		$this->section_upsells();
		$this->control_upsells();
		$this->checkout_locked_layout();
		$this->product_catalog_upsells();
	}

	/**
	 * Locked Checkout Layouts
	 *
	 * @return void
	 */
	private function checkout_locked_layout() {
		$this->add_control(
			new Control(
				'neve_checkout_page_layout',
				[
					'default'           => 'standard',
					'sanitize_callback' => [ $this, 'sanitize_checkout_layout' ],
				],
				[
					'section'  => 'woocommerce_checkout',
					'priority' => 5,
					'choices'  => [
						'standard' => [
							'name'  => esc_html__( 'Standard', 'neve' ),
							'image' => 'data:image/png;base64,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',
						],
						'vertical' => [
							'name'      => esc_html__( 'Vertical', 'neve' ),
							'image'     => 'data:image/png;base64,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',
							'upsellUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'woocheckoutvertical' ),
						],
						'stepped'  => [
							'name'      => esc_html__( 'Stepped', 'neve' ),
							'image'     => 'data:image/png;base64,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',
							'upsellUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'woocheckoutstepped' ),
						],
					],
				],
				'\Neve\Customizer\Controls\React\Radio_Image'
			)
		);
	}

	/**
	 * Locked options on Product Catalog
	 *
	 * @return void
	 */
	private function product_catalog_upsells() {
		$this->add_control(
			new Control(
				'neve_product_card_layout_ui_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
					'transport'         => $this->selective_refresh,
				],
				[
					'label'            => esc_html__( 'Layout', 'neve' ),
					'section'          => 'woocommerce_product_catalog',
					'priority'         => 200,
					'class'            => 'card-layout-accordion',
					'accordion'        => true,
					'controls_to_wrap' => 2,
					'expanded'         => false,
				],
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				'neve_product_card_layout',
				[
					'transport'         => 'postMessage',
					'default'           => 'grid',
					'sanitize_callback' => function() {
						return 'grid';
					},
				],
				[
					'label'    => esc_html__( 'Layout', 'neve' ),
					'section'  => 'woocommerce_product_catalog',
					'priority' => 210,
					'choices'  => [
						'grid' => [
							'name' => __( 'Grid', 'neve' ),
							'url'  => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAS8AAADYCAAAAACfVToRAAAEtElEQVR42u3cIXPjOhSG4f3/9KOGgoFmhmZlspvUabITsp5LjMyMzgWSHadNE7fJve1G74fSmbTgGUk+OpL7y8hn8gsCvPDCCy+8CF544YUXXngRvPDCCy+8yP/g9c/vbwteeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeP0Ur9dbsk/Ma9/U1U2pX1Py2j9XN6dJyOsOXFW1TcZrew+uqk7Ga3MXrwsD7MG87sN1YQV7SK96+9VqYpOk1/rL5egrXnjhhddP8drjtdxrv6mrqm72eC3y2sWd9/MeryVeU6Nig9cCr9leco/Xda/N5f3NS1Xv8Jp5rS96barqDFjKXi+X+g1h8L0DY/06v36Nc/UtWNLPx6nX+vJxm+wNWNJeYy9/c6mreAqWeH3fPFfVenu5CXsCxn77es96DobXghb/DAyvJSciRzC8Fh0gTWB47ep6e/28bQRL3mtXz8v7j48n6z1exxbY9vpp7itex45hALt4+I3XjKuqttfuCuA156qq7ZWrFXj9bj5zZQIvvPDCCy+8EvHarj+RHV7cz8ELL7zwwguv+fsK66+mTsyr5v2OT3nd6f2hXSpeu7twrdN5/7G5A1e9S+h95OY/5XrA9913m5sW/efL1/Ufz4v/p4AXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXkl6dX++LX+l1yMGL7zwwgsvvAheeOGFF1543T9OMfnh+pe9lOM1przdq1zyVx7FSx6vJV65mVmTSSu8FnuZlzSY937ocpVmvZck34evNSvJNee9vJNUHhLzaiT1JqmRVFo7TtLRQZIyKTeT1JpZL6k36920/MVvKaHxFVBU9mE585K6YHkIau+8nFSYHTKpSckrrl+SVA5mRZxYpVSYufgsyN97NZIzM3uSigSfj4p8WZyIraShD6NsXO9PvArpKdF6ojQzSc1xrsUP7TjHmvdeLvxCel6hvj9dm/D6eL0PiRan83E4Ox87Sb3lcT723vuEvWbrfW62iuv9avTyUwHi43rv01nvz3l17+oJP9UTK8n11jlJvQ2xngi/WP6IDfk3eNnhXL0axlcTfghewW18XPh06tU3Xmf3Q733jZkdVpL8MD4Twn6onareh/Z6xOCFF1544YUXwQsvvPDC6+b4HC+8bkyzmvUhfCa5cC+gfZo3KPCKyWP7qrXj2avrx1bW2ADDK+ZpOh7qzVbjZ3fsF8YmF15mFg55ijCYnsa2cyHpUEiu83nvfkRH/sd4jccVhVRMhxyZ5J3kzefmpQyvKWU8DiulwlxcrJzkV9GL5+NJDt63I5F57/s4RzsvqcgdXh8NMzfEz8NKKqYHQeYHvN6ky0MJEUbceGLUxYoia/F6u+ariKNoKOb3WL3zkrIer1lFsZLcWJO2mZR38/3Q4BbcA07Iq8uOg2sswCzcBxjM52Y5XrMM2awebXW8nJTFeqLP8Dq7HZI7boekMtYTrF+nyWZeneZ3DfPpM8/HY2ZErj3xsiY0K8q/r6FDvxCvh/T6S4MXXnjhhRdeBC+88MILL7wIXnjhhdcj51987R/KzzMKWAAAAABJRU5ErkJggg==',
						],
						'list' => [
							'name'      => __( 'List', 'neve' ),
							'url'       => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAS8AAADYCAAAAACfVToRAAAE0UlEQVR42u3csVPqTBTG4fv/t2+bckvKdCnT2W2iGASH5ma+JlW6VOcrdkOCIKBBwJvfW+GMOvLM7ubsctY/Rr6SPxDghRdeeOFF8MILL7zwwovghRdeeOFF8MILL7zwwovghRdeeOGFF8ELL7zwwovghRdeeOGFF8ELL7zwwovg9RNe/73fLXjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjh9Sheb1OymZnXpiqLSSnf5uS1eS4mp5qR1xW4imL1bS+nmHR7/n16Kb2z1+oaXEU53UvKp3vll/yWSV7Lq3idGGCXe8n/Aq/rcJ1Ywc57pWZmVSItfo1XufpuNbG8kpd5SZ1577smVW7Weknybfi2aiG56riXd5Ly7S29Xr5djr5dy6uS1JqkSlJudT9JewdJSqTUTFJtZq2k1qx1u+Uvfpdm4RXGV0BR3oblzEtqguU2qB14OSkz2yZSNSevuH5JUt6ZZXFi5VJm5uKzID30qiRnZvYkZTOZj+PnoyJfEidiLalrwyjr1/s9r0x6uv16P/La3M0rNzNJ1TDX4ou6n2PVoZcLP3Anr82yLIqy2tzBK9T3+2vTo3ut4877eXNLr3GJEC3252N3dD42klpL43xsvfc399odVCzv7TVa71OzRVzvF72X3xUgPq73/g7r/WgvubmzV3NQT/hdPbGQXGuNk9RaF+uJ8IP5ZRvyK3ktT+9vXotyfSsv2x6rV8P4qsIXwSu49Y8Lf9P66+Wk17IojoD9lNfR/VDrfWVm24Uk3/XPhLAfqndV7828Xk+dN4TBdwA21esuucH61c/Vj2Bz9hrOWl8/4zoAm7VXf5a//JzrI9isvd431XNRvKxOcX0Am7fX8Xw8sx6D4XWWaw8Mr/NcYzC8LuAageG1LsvVOa4BbPZe63Jc3n/+8WS5wet9dwS2OsdVFG94DSeGAezkh994jbiKYnWuVwCvMVdRrM60VuD1Xn2lZQIvvPDCCy+8ZuK1evlC1nh9I3jhhddMvHyKF14TvarFqE/CJ5IL9xbqp3EDxWN5FS/fTTnVK43tNbUNveGu7Vtt+gadh/GaeJdv8v2Op137amu26F+7oZ8pNuE8iteV7g+tv+nVSsrCYHrq2+IySdtMco1PW3dZx+DNvNZX4Tqx/p1Z0WM7ZSZluybMRPJO8uZT81LySF5f2zOe+XDt6155bNfNpcxcXKyc5BfR69Gej9cAO8V1xmvrfd0Tmfe+jXO08ZKy1D2g1/t6OWnRfz7drn/RG8gl18XX3ULKdg+CxHeP5vWzueDPb9JQQoQR13e0NrGiSGq8Pq75yuIo6rLxPVvvvKSkxWtUUSwkt41f1ImUNoNkap274J7yjLyaZBhcfQFm4b5CZz41S/EapUtG9Wit4fJUEuuJNsFrlGE7JDdsh6Q81hOsX/tJRl6Nxnch091rno9DRkSu3vOyKhxW5D9woPOv/j+rh9wP4fXPeP1U8MILL7zwwgsvvPDCCy+88MILL7zwwgsvvPDCCy+88MILrwlezd+75Vd6EbzwwgsvvPAieOGFF154EbzwwgsvvPAieOGFF1544UXwwgsvvPAieOGFF1544UXwwgsvvPAieOGFF1544UXwmpz/AdpnH8pqwZaBAAAAAElFTkSuQmCC',
							'upsellUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'woocardlistlayout' ),
						],
					],
				],
				'\Neve\Customizer\Controls\React\Radio_Image'
			)
		);

		$this->add_control(
			new Control(
				'neve_add_to_cart_display',
				[
					'default'           => 'none',
					'sanitize_callback' => function() {
						return 'none';
					},
				],
				[
					'label'    => esc_html__( 'Button Style', 'neve' ),
					'section'  => 'woocommerce_product_catalog',
					'priority' => 230,
					'choices'  => [
						'none'     => [
							'name' => __( 'None', 'neve' ),
							'url'  => 'data:image/png;base64,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',
						],
						'after'    => [
							'name'      => __( 'Bottom', 'neve' ),
							'url'       => 'data:image/png;base64,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',
							'upsellUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'wooaddtocartafter' ),
						],
						'on_image' => [
							'name'      => __( 'Overlay', 'neve' ),
							'url'       => 'data:image/png;base64,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',
							'upsellUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'wooaddtocartonimage' ),
						],
					],
				],
				'\Neve\Customizer\Controls\React\Radio_Image'
			)
		);

		$this->add_control(
			new Control(
				'neve_category_card_layout_ui_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
					'transport'         => $this->selective_refresh,
				],
				[
					'label'            => esc_html__( 'Category', 'neve' ),
					'section'          => 'woocommerce_product_catalog',
					'priority'         => 300,
					'class'            => 'category-layout-accordion',
					'accordion'        => true,
					'controls_to_wrap' => 1,
					'expanded'         => false,
				],
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				'neve_category_card_layout',
				[
					'default'           => 'default',
					'sanitize_callback' => function() {
						return 'default';
					},
				],
				[
					'label'    => esc_html__( 'Layout', 'neve' ),
					'section'  => 'woocommerce_product_catalog',
					'priority' => 310,
					'choices'  => [
						'default' => [
							'name' => 'Simple',
							'url'  => 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTAiIGhlaWdodD0iNjAiIHZpZXdCb3g9IjAgMCA5MCA2MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjkwIiBoZWlnaHQ9IjYwIiByeD0iMSIgZmlsbD0iI0YzRjRGNSIvPgo8cmVjdCB3aWR0aD0iNzEuNzUiIGhlaWdodD0iNDEuODM3OSIgdHJhbnNmb3JtPSJtYXRyaXgoLTEgMCAwIDEgODAgMCkiIGZpbGw9IiNEREREREQiLz4KPHBhdGggZD0iTTIzLjU2NjQgNTBINTEuMTk2NCIgc3Ryb2tlPSIjQzRDNEM0IiBzdHJva2Utd2lkdGg9IjIiLz4KPHBhdGggZD0iTTU1LjMxNjQgNTBINjQuNjg1NSIgc3Ryb2tlPSIjQzRDNEM0IiBzdHJva2Utd2lkdGg9IjIiLz4KPC9zdmc+Cg==',
						],
						'style-3' => [
							'name'      => 'Boxed',
							'url'       => 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTEiIGhlaWdodD0iNjAiIHZpZXdCb3g9IjAgMCA5MSA2MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3QgeD0iMC4xODU1NDciIHdpZHRoPSI5MCIgaGVpZ2h0PSI2MCIgcng9IjEiIGZpbGw9IiNGM0Y0RjUiLz4KPHJlY3Qgd2lkdGg9IjcxLjc1IiBoZWlnaHQ9IjUwIiB0cmFuc2Zvcm09Im1hdHJpeCgtMSAwIDAgMSA4MC4xODU1IDApIiBmaWxsPSIjREREREREIi8+CjxyZWN0IHg9IjI1LjY4NTUiIHk9IjEzLjgzNzkiIHdpZHRoPSIzOSIgaGVpZ2h0PSIyMS4xNjIxIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMzAuMzE0NSAyNEw0OS4zMDk0IDI0LjI2NDIiIHN0cm9rZT0iIzk5OTk5OSIgc3Ryb2tlLXdpZHRoPSIyIi8+CjxwYXRoIGQ9Ik01Mi4wNjA1IDI0LjMxODRMNTguOTM2NSAyNC40MTkiIHN0cm9rZT0iIzk5OTk5OSIgc3Ryb2tlLXdpZHRoPSIyIi8+Cjwvc3ZnPgo=',
							'upsellUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'woocategorycardboxed' ),
						],
						'style-2' => [
							'name'      => 'Hover',
							'url'       => 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTEiIGhlaWdodD0iNjAiIHZpZXdCb3g9IjAgMCA5MSA2MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3QgeD0iMC44NjkxNDEiIHdpZHRoPSI5MCIgaGVpZ2h0PSI2MCIgcng9IjEiIGZpbGw9IiNGM0Y0RjUiLz4KPHJlY3Qgd2lkdGg9IjcxLjc1IiBoZWlnaHQ9IjUwIiB0cmFuc2Zvcm09Im1hdHJpeCgtMSAwIDAgMSA4MC44NjkxIDApIiBmaWxsPSIjOTk5OTk5Ii8+CjxwYXRoIGQ9Ik0yNC4xODE2IDI0SDUxLjgwNjYiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMiIvPgo8cGF0aCBkPSJNNTUuODA2NiAyNEw2NS44MDY2IDI0IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiLz4KPC9zdmc+Cg==',
							'upsellUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'woocategorycardhover' ),
						],
					],
				],
				'\Neve\Customizer\Controls\React\Radio_Image'
			)
		);

		$this->add_control(
			new Control(
				'neve_sale_tag_ui_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
					'transport'         => $this->selective_refresh,
				],
				[
					'label'            => esc_html__( 'Tags', 'neve' ),
					'section'          => 'woocommerce_product_catalog',
					'priority'         => 600,
					'class'            => 'sale-tag-accordion',
					'accordion'        => true,
					'controls_to_wrap' => 1,
					'expanded'         => false,
				],
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				'neve_sale_tag_position',
				[
					'default'           => 'inside',
					'sanitize_callback' => function() {
						return 'inside';
					},
				],
				[
					'label'         => esc_html__( 'Style', 'neve' ),
					'section'       => 'woocommerce_product_catalog',
					'priority'      => 610,
					'documentation' => [
						'link' => 'https://docs.themeisle.com/article/1058-woocommerce-booster-documentation#sale-tag',
					],
					'choices'       => [
						'inside'  => [
							'url' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAS8AAADYCAMAAACN4JX/AAAAVFBMVEU/xPtTyPtkzPx00fyD1fyR2fye3f2q4f225f3B6f3M7P7S0tLT09PU1NTV1dXW1tbX19fX8P7Y2NjZ2dna2trb29vc3Nzd3d3i9P7s+P71+/////8xOQAQAAADLElEQVR4AezQMQ0AMAwDsLDYMf48i6Gq8tkQnL+BL1++fPnyhS9fvnz58oUvX758+cKXL1++fPnCly9fvnz5ov3lC1++fPnKwWvx5cuXL1++fPny5cuXL1++fPny5cuXL1++fPnyNezXsW7EIAyAYRPiM8eWjfh///dsiNOrVJW1k/8BmfUTIPEPXsUc3GJTwe/h5JTo5GlPr8n1eIwydw3Q9GLt1UDv1SaeA/2XV0xRevW4gM77Wl/QoKTX2stgWL2GqXTQC1h6rb3kYNb1GjdQ6Yw/368jvaLdHMBEDBdRqOm19IrMoXxoWt7HlVeBdoPBtvPk6bU8Xwe8ROrA5R0yCppeK6/qRPp91MTpP6/WZ5qsUf6HoFUx2GXWYftqx25zrIZhMAovIElTtfnY/05B/LhKecHcMEMYxefsoI/qSPb/8mLfxuv42/LVPHqFD5QbXlPFgtdcBa+pYsNrqozXXA2vqW68pjrxmiqzD73R+fI68HqjhhdeeOGFF1544YUXXu/Wf5l+UW8xvEp/NMEryeJnhNcdHlWbBK8klwUjvFp4Fk2QI8Tbt1cNP2VxpfC9C68xm0vBmEebS8FcefX49DosLgFz6HU+vW6DS8A8erU4QiSDS8BcevUyMMRqcAmYT69+xwkuAfPn1Vv+IRbPZnEJmDevsVpK7d3mEjDHXppyKRheE1wChpfJJWB42VwChpdyCZhbr5LSNcElYM68ilxXDS4Bc+AlXAOYxSVVH17CNYJNcIXiw0u4RjDhwku4RjDhwku4BjDhwku4BjCDC6+iAvn3XHjlGRu88MILL7zwwgsvvPBa7HXnD1a538+HF1544YUXXnjhZYdXbJ/vVTb2CvH49MKrvItXDEs6d/FKa7yuXbzONV51F6+2hOvoG3gt/MHqPl49rXi9NvJqaQHXBl6rRjKWvplXb2eK/wjruHvfwGthG3jhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOFFX9YLL7wIL7zwwgsvvAgvvPDCCy+8CC+88MILL8ILL7zwwgsvwgsvvPDCi74BKevIZRVAXf8AAAAASUVORK5CYII=',
						],
						'outside' => [
							'url'       => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAS8AAADYCAMAAACN4JX/AAAAVFBMVEU/xPtTyPtkzPx00fyD1fyR2fye3f2q4f225f3B6f3M7P7S0tLT09PU1NTV1dXW1tbX19fX8P7Y2NjZ2dna2trb29vc3Nzd3d3i9P7s+P71+/////8xOQAQAAADR0lEQVR4AezXMWvDMBBA4XNsRY62THX0/v//bA8lKQQ0lIZ2eW8w5/XDZ7jAfpJeeumll156mV566fWW9NJLL71ML7300kuv+EV6PdJLL7300ksvvfTSSy+99NJLL7300ksvvT7+ML30eld66aXXUjv0Ol5W6JHduMXoxr1Nr+S6exxLfLUDRa+5VwqVfFITrwPtxWtMI73aWMDOJSLOsMOi19yrwlHXiEilK22BqtfUK42yViLiBCUax4vX6KrXaKsdoEZUekSBVa+p1yjJlifNPttHvZbUSTA4bdzres284grniPWgx2XIFCh6zbzWzqg8PrXotO+/1nNK1pH3EOxrVNgia3DS67/vbb300ksvvfTSSy+99NJLL7300ksvvfTSSy+9Ptu511y3QSiKwgPggWXzmP9MW/UPanfvaaISdHVYawif4sTaKOSFlbu79wprKx2vt4p1v9eCxhdd4eNVR15P+Hyxu/HqMWyouPG6w5a6F6+8x+vx4hX3eF1evMKeij+vNpalryrZnVce6+t44YUXXnjhhde5XrWkGNPVXkHBq2frtXyGl0w8Ca9/eqWXliu8/j64Nrxsr2QsCxJePfxeNEFyiM/ZXi38kcWVws9uwwsv4TLAeB6FS8AO85JFP1tcAnaal553PwaXgJ3mpSe4yeASsCO9Rg2z2AwuATvTazzxFS4BO9Zr9PJLLF7d5lKwY/fCVmuzfxltMPZVm0vB8LK5BAwvm0vA8LK5BAwv5RKwY71qSrfBZYAd6VV1XbW5FMy3l3BNMJNLakd4CdcEs7mkeo6XcE0w5cJLuCaYcuElXBNMuPASrglmcOFVVaB8zYVXeRlmvxdeeOGFF1544YUXXng95T9rq734fwdeeOGFF1544YUXXrGv96qOvULMy3N4Hwz3Db3nlfZ43V68rj1ezYtX38KVhxevPR+w5sdrpJ3fXg68etrF5cBrwyMZ63DmNfqV4oew8jOGK6/94YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjh5cCL8MILL7zwwovwwgsvvPDCi/DCCy+88CK88MILL7zwIrzwwgsvvPAivPD6Lv0ALgqZQ3JkuCMAAAAASUVORK5CYII=',
							'upsellUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'woosaletagoutside' ),
						],
					],
				],
				'\Neve\Customizer\Controls\React\Radio_Image'
			)
		);

		$this->add_control(
			new Control(
				'neve_card_content_ui_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
					'transport'         => $this->selective_refresh,
				],
				[
					'label'            => esc_html__( 'Content', 'neve' ),
					'section'          => 'woocommerce_product_catalog',
					'priority'         => 500,
					'class'            => 'card-content-accordion',
					'accordion'        => true,
					'controls_to_wrap' => 1,
					'expanded'         => false,
				],
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				'neve_product_content_alignment',
				[
					'default'           => 'left',
					'sanitize_callback' => function() {
						return 'left';
					},
				],
				[
					'label'    => esc_html__( 'Alignment', 'neve' ),
					'section'  => 'woocommerce_product_catalog',
					'priority' => 520,
					'choices'  => [
						'left'   => [
							'name' => __( 'Left', 'neve' ),
							'url'  => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAS8AAADYCAAAAACfVToRAAAEtElEQVR42u3cIXPjOhSG4f3/9KOGgoFmhmZlspvUabITsp5LjMyMzgWSHadNE7fJve1G74fSmbTgGUk+OpL7y8hn8gsCvPDCCy+8CF544YUXXngRvPDCCy+8yP/g9c/vbwteeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeP0Ur9dbsk/Ma9/U1U2pX1Py2j9XN6dJyOsOXFW1TcZrew+uqk7Ga3MXrwsD7MG87sN1YQV7SK96+9VqYpOk1/rL5egrXnjhhddP8drjtdxrv6mrqm72eC3y2sWd9/MeryVeU6Nig9cCr9leco/Xda/N5f3NS1Xv8Jp5rS96barqDFjKXi+X+g1h8L0DY/06v36Nc/UtWNLPx6nX+vJxm+wNWNJeYy9/c6mreAqWeH3fPFfVenu5CXsCxn77es96DobXghb/DAyvJSciRzC8Fh0gTWB47ep6e/28bQRL3mtXz8v7j48n6z1exxbY9vpp7itex45hALt4+I3XjKuqttfuCuA156qq7ZWrFXj9bj5zZQIvvPDCCy+8EvHarj+RHV7cz8ELL7zwwguv+fsK66+mTsyr5v2OT3nd6f2hXSpeu7twrdN5/7G5A1e9S+h95OY/5XrA9913m5sW/efL1/Ufz4v/p4AXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXkl6dX++LX+l1yMGL7zwwgsvvAheeOGFF1543T9OMfnh+pe9lOM1przdq1zyVx7FSx6vJV65mVmTSSu8FnuZlzSY937ocpVmvZck34evNSvJNee9vJNUHhLzaiT1JqmRVFo7TtLRQZIyKTeT1JpZL6k36920/MVvKaHxFVBU9mE585K6YHkIau+8nFSYHTKpSckrrl+SVA5mRZxYpVSYufgsyN97NZIzM3uSigSfj4p8WZyIraShD6NsXO9PvArpKdF6ojQzSc1xrsUP7TjHmvdeLvxCel6hvj9dm/D6eL0PiRan83E4Ox87Sb3lcT723vuEvWbrfW62iuv9avTyUwHi43rv01nvz3l17+oJP9UTK8n11jlJvQ2xngi/WP6IDfk3eNnhXL0axlcTfghewW18XPh06tU3Xmf3Q733jZkdVpL8MD4Twn6onareh/Z6xOCFF1544YUXwQsvvPDC6+b4HC+8bkyzmvUhfCa5cC+gfZo3KPCKyWP7qrXj2avrx1bW2ADDK+ZpOh7qzVbjZ3fsF8YmF15mFg55ijCYnsa2cyHpUEiu83nvfkRH/sd4jccVhVRMhxyZ5J3kzefmpQyvKWU8DiulwlxcrJzkV9GL5+NJDt63I5F57/s4RzsvqcgdXh8NMzfEz8NKKqYHQeYHvN6ky0MJEUbceGLUxYoia/F6u+ariKNoKOb3WL3zkrIer1lFsZLcWJO2mZR38/3Q4BbcA07Iq8uOg2sswCzcBxjM52Y5XrMM2awebXW8nJTFeqLP8Dq7HZI7boekMtYTrF+nyWZeneZ3DfPpM8/HY2ZErj3xsiY0K8q/r6FDvxCvh/T6S4MXXnjhhRdeBC+88MILL7wIXnjhhdcj51987R/KzzMKWAAAAABJRU5ErkJggg==',
						],
						'center' => [
							'name'      => __( 'Center', 'neve' ),
							'url'       => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAS8AAADYCAAAAACfVToRAAAEtElEQVR42u3cLXPjPBSG4f3/9KGGgoFmhmZlspvUabITsp6XGJkZnRdIdpw2X91ku9noflA6kxZcI8lHR3J/GPlKfkCAF1544YUXwQsvvPDCCy+CF1544YUX+fNe//38a8ELL7zwwgsvvPDCCy+88MILL7zwwgsvvPDCCy+88MILL7zwwgsvvPDCCy+88MILr4fxer8l28S8tk1d3ZT6PSWv7Wt1c5qEvO7AVVXrZLzW9+Cq6mS8VnfxOj3Ans3rPlynV7Dn9KrXv1tNrJL0Wv52PfqOF1544fUoXlu8rvfaruqqqpstXld5beLO+3WL1zVeU6NihdcVXrO95Bavy16r8/ubt6re4DXzWp71WlXVEbCUvd7O9RvC4PsExvp1fP0a5+pHsKSfj1Ov9e10m+wDWNJeYy9/da6reAiWeH3fvFbVcn2+CXsAxn77cs96DobXFS3+GRhe15yI7MHwuuoAaQLDa1PX68vnbSNY8l6bel7enz6erLd47Vtg68unue947TuGAezs4TdeM66qWl+6K4DXnKuq1heuVuD1s/nKlQm88MILL7zwSsRrvfxCNnhxPwcvvPDCCy+85u8rLH83dWJeNe93fMnrTu8PbVLx2tyFa5nO+4/NHbjqTULvIzd/kusZ33ffrG5a9F/PXtd/Qi/+nwJeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeKXo1f36a/knvZ4yeOGFF1544UXwwgsvvPDC61viFJPvLn/ZSzleY8rbvcpr/sqzeMnjdY1XbmbWZNICr6u9zEsazHs/dLlKs95Lku/D15qF5JrjXt5JKneJeTWSepPUSCqtHSfp6CBJmZSbSWrNrJfUm/VuWv7it5TQ+AooKvuwnHlJXbDcBbVPXk4qzHaZ1KTkFdcvSSoHsyJOrFIqzFx8FuSfvRrJmZm9SEWCz0dFvixOxFbS0IdRNq73B16F9JJoPVGamaRmP9fih3acY81nLxd+IT2vUN8frk14nV7vQ6LF4Xwcjs7HTlJveZyPvfc+Ya/Zep+bLeJ6vxi9/FSA+Lje+3TW+2Ne3ad6wk/1xEJyvXVOUm9DrCfCL5bfvyF/DC/bHatXw/hqwg/BK7iNjwufTr36wevofqj3vjGz3UKSH8ZnQtgPtVPV+9Re/3zwwgsvvPDCi+CFF1544fWd8TleeN2YZjHrT/hMcuG+QPsyb1zgFZPHtlZr+zNZ148trrExhlfMy3Rs1Jstxs9u30eMzS+8zCwc/hRhML2M7ehC0q6QXOfz3n1/p/6RvcZjjEIqpsOPTPJO8uZz81KG15QyHpOVUmEuLlZO8ovoxfPxIDvv25HIvPd9nKOdl1TkDq9Tw8wN8fOwkIrpQZD5Aa8P6fJQQoQRN54kdbGiyFq8Pq75KuIoGor5/VbvvKSsx2tWUSwkN9akbSbl3Xw/NLgr7gcn5NVl+8E1FmAW7gkM5nOzHK9ZhmxWj7baX1rKYj3RZ3gd3Q7J7bdDUhnrCdavw2Qzr07zO4j59Jnn4z4zItceeFkTmhXlgzR06BfilbrXIwUvvPDCCy+8CF544YUXXngRvPDCC69nzv/F6x/Kmshd1QAAAABJRU5ErkJggg==',
							'upsellUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'wooscardcontentalingcenter' ),
						],
						'right'  => [
							'name'      => __( 'Right', 'neve' ),
							'url'       => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAS8AAADYCAAAAACfVToRAAAEs0lEQVR42u3cLXPrOhSF4fP/6aKGgoFmhmZlspvUaXIm5HguMTIz2hdIdpw2X23SaRu9C6UzacEzkry1JfePkY/kDwR44YUXXngRvPDCCy+88CJ44YUXXniRr/f67++3BS+88MILL7zwwgsvvPDCCy+88MILL7zwwgsvvPDCCy+88MILL7zwwgsvvPDCCy+8fozX6y3ZJua1berqptSvKXltn6ub0yTkdQeuqlon47W+B1dVJ+O1uovX6QH2aF734Tq9gj2mV73+bDWxStJr+el69BUvvPDC66d4bfG63mu7qquqbrZ4XeW1iTvv5y1e13hNjYoVXld4zfaSW7wue63O729eqnqD18xredZrVVVHwFL2ejnXbwiD7x0Y69fx9Wucq2/Bkn4+Tr3Wl9NtsjdgSXuNvfzVua7iIVji9X3zXFXL9fkm7AEY++3LPes5GF5XtPhnYHhdcyKyB8PrqgOkCQyvTV2vL5+3jWDJe23qeXl/+niy3uK1b4GtL5/mvuK17xgGsLOH33jNuKpqfemuAF5zrqpaX7hagdff5iNXJvDCCy+88MIrEa/18gPZ4MX9HLzwwgsvvPCav6+w/GzqxLxq3u/4kNed3h/apOK1uQvXMp33H5s7cNWbhN5Hbr6S6xHfd9+sblr0n89e139AL/6fAl544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF1544YUXXnjhhRdeeOGFF154pejV/fu2/EqvhwxeeOGFF154EbzwwgsvvPD6rjjF5LvLX/ZSjteY8nav8pq/8ihe8nhd45WbmTWZtMDrai/zkgbz3g9drtKs95Lk+/C1ZiG55riXd5LKXWJejaTeJDWSSmvHSTo6SFIm5WaSWjPrJfVmvZuWv/gtJTS+AorKPixnXlIXLHdB7Z2XkwqzXSY1KXnF9UuSysGsiBOrlAozF58F+XuvRnJmZk9SkeDzUZEvixOxlTT0YZSN6/2BVyE9JVpPlGYmqdnPtfihHedY897LhV9IzyvU94drE16n1/uQaHE4H4ej87GT1Fse52PvvU/Ya7be52aLuN4vRi8/FSA+rvc+nfX+mFf3rp7wUz2xkFxvnZPU2xDrifCL5RdvyH+sl+2O1athfDXhh+AV3MbHhU+nXn3jdXQ/1HvfmNluIckP4zMh7Ifaqep9aK/fFbzwwgsvvPAieOGFF154/dD4HC+8bkyzmPUtfCa5cI+gfZo3NPCKyWO7q7X9Wa3rx9bX2DDDK+ZpOk7qzRbjZ7fvL8amGF5mFg6FijCYnsY2dSFpV0iu83nvvrSD/+u8xuONQiqmQ5FM8k7y5nPzUobXlDIen5VSYS4uVk7yi+jF8/EgO+/bkci8932co52XVOQOr1PDzA3x87CQiulBkPkBrzfp8lBChBE3njB1saLIWrzervkq4igaivm9V++8pKzHa1ZRLCQ31qRtJuXdfD80uCvuDSfk1WX7wTUWYBbuDwzmc7Mcr1mGbFaPttpfZspiPdFneB3dDsntt0NSGesJ1q/DZDOvTvO7ifn0mefjPjMi1x54WROaFeVXNnToF+KF188JXnjhhRdeeBG88MILL7zwInjhhRdej5z/AdA+H8o+3vutAAAAAElFTkSuQmCC',
							'upsellUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'wooscardcontentalingright' ),
						],
						'inline' => [
							'name'      => __( 'Left', 'neve' ) . ' / ' . __( 'Right', 'neve' ),
							'url'       => 'data:image/png;base64,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',
							'upsellUrl' => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'wooscardcontentalinginline' ),
						],
					],
				],
				'\Neve\Customizer\Controls\React\Radio_Image'
			)
		);
	}

	/**
	 * Sanitize checkout layout that forcefully updates the selection as standard.
	 *
	 * @return string
	 */
	public function sanitize_checkout_layout() {
		return 'standard';
	}

	/**
	 * Add upsells section
	 */
	private function section_upsells() {

		$this->add_section(
			new Section(
				'neve_free_pro_upsell',
				array(
					'priority' => -100,
					'title'    => esc_html__( 'Neve PRO Features', 'neve' ),
					'url'      => $this->upsell_url,
				),
				'Neve\Customizer\Controls\React\Upsell_Section'
			)
		);
	}

	/**
	 * Add upsells controls
	 */
	private function control_upsells() {
		$this->add_control(
			new Control(
				'neve_upsell_main_control',
				[ 'sanitize_callback' => 'sanitize_text_field' ],
				[
					'text'        => esc_html__( 'Neve PRO Features', 'neve' ),
					'button_text' => esc_html__( 'Learn More', 'neve' ),
					'section'     => 'neve_free_pro_upsell',
					'priority'    => PHP_INT_MIN,
					'link'        => $this->upsell_url,
				],
				'Neve\Customizer\Controls\Simple_Upsell'
			)
		);

		$upsells         = [];
		$upsells_banners = [];

		$upsells_banners['blog_archive'] = [
			'text'        => __( 'More blog layout customization options available in PRO', 'neve' ),
			'button_text' => __( 'Learn More', 'neve' ),
			'use_logo'    => true,
			'section'     => 'neve_blog_archive_layout',
		];
		$upsells_banners['single_post']  = [
			'text'        => __( 'More single post components available in PRO', 'neve' ),
			'button_text' => __( 'Learn More', 'neve' ),
			'use_logo'    => true,
			'section'     => 'neve_single_post_layout',
		];


		$hfg_header                     = 'hfg_header';
		$hfg_header_text                = __( 'Extend your header with more components and settings, build sticky/transparent headers or display them conditionally.', 'neve' );
		$hfg_header_button              = __( 'Get the PRO version!', 'neve' );
		$upsells_banners[ $hfg_header ] = [
			'text'        => $hfg_header_text,
			'button_text' => $hfg_header_button,
			'use_logo'    => true,
			'panel'       => $hfg_header,
			'type'        => 'section',
		];

		foreach ( [ 'top', 'main', 'bottom', 'sidebar' ] as $section ) {
			$section_id                     = $hfg_header . '_layout_' . $section;
			$upsells_banners[ $section_id ] = [
				'text'        => $hfg_header_text,
				'button_text' => $hfg_header_button,
				'use_logo'    => true,
				'section'     => $section_id,
			];
		}

		$hfg_footer                     = 'hfg_footer';
		$hfg_footer_text                = __( 'Neve PRO Features', 'neve' );
		$hfg_footer_button              = __( 'Get the PRO version!', 'neve' );
		$upsells_banners[ $hfg_footer ] = [
			'text'        => $hfg_footer_text,
			'button_text' => $hfg_footer_button,
			'use_logo'    => true,
			'panel'       => $hfg_footer,
			'type'        => 'section',
		];
		foreach ( [ 'top', 'main', 'bottom' ] as $section ) {
			$section_id                     = $hfg_footer . '_layout_' . $section;
			$upsells_banners[ $section_id ] = [
				'text'        => $hfg_footer_text,
				'button_text' => $hfg_footer_button,
				'use_logo'    => true,
				'section'     => $section_id,
			];
		}


		if ( class_exists( 'WooCommerce', false ) ) {
			$upsells['product_catalog']       = [
				'text'        => __( 'More product catalog options available in PRO', 'neve' ),
				'button_text' => __( 'Learn More', 'neve' ),
				'section'     => 'woocommerce_product_catalog',
			];
			$upsells['woocommerce_checkout']  = [
				'text'        => __( 'More checkout options available in PRO', 'neve' ),
				'button_text' => __( 'Learn More', 'neve' ),
				'section'     => 'woocommerce_checkout',
			];
			$upsells['single_product_layout'] = [
				'text'        => __( 'More single product options available in PRO', 'neve' ),
				'button_text' => __( 'Learn More', 'neve' ),
				'section'     => 'neve_single_product_layout',
			];
			$upsells['typography']            = [
				'text'        => __( 'WooCommerce typography options available in PRO', 'neve' ),
				'button_text' => __( 'Learn More', 'neve' ),
				'panel'       => 'neve_typography',
				'type'        => 'section',
			];
		}

		$is_dismissed = get_transient( 'upsell_dismiss_banner_customizer' );
		if ( $is_dismissed === false ) {
			foreach ( $upsells_banners as $id => $args ) {
				if ( isset( $args['type'] ) && $args['type'] === 'section' ) {
					$section_id = 'neve_' . $id . '_upsell_section';
					$this->add_section(
						new Section(
							$section_id,
							array_merge(
								$args,
								[
									'type'     => 'neve_upsell_banner_section',
									'priority' => 10000,
									'nonce'    => wp_create_nonce( 'neve-upsell-banner-nonce' ),
									'url'      => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'panel-' . $args['panel'] ),
								]
							),
							'\Neve\Customizer\Controls\React\Upsell_Banner_Section'
						)
					);

					continue;
				}
				$control_id = 'neve_' . $id . '_upsell_banner_control';
				$this->add_control(
					new Control(
						$control_id,
						[ 'sanitize_callback' => 'sanitize_text_field' ],
						array_merge(
							$args,
							[
								'type'     => 'neve_upsell_banner',
								'priority' => 10000,
								'nonce'    => wp_create_nonce( 'neve-upsell-banner-nonce' ),
								'url'      => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'upsell-banner-customizer-section-' . $args['section'] ),
							]
						),
						'\Neve\Customizer\Controls\React\Upsell_Banner'
					)
				);
			}
		}

		foreach ( $upsells as $id => $args ) {
			if ( isset( $args['type'] ) && $args['type'] === 'section' ) {
				$this->add_section(
					new Section(
						'neve_' . $id . '_upsell_section',
						array_merge(
							$args,
							[
								'type'     => 'nv_simple_upsell_section',
								'priority' => 10000,
								'link'     => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'panel-' . $args['panel'] ),
							]
						),
						'\Neve\Customizer\Controls\Simple_Upsell_Section'
					)
				);

				return false;
			}
			$this->add_control(
				new Control(
					'neve_' . $id . '_upsell',
					[ 'sanitize_callback' => 'sanitize_text_field' ],
					array_merge(
						$args,
						[
							'priority' => 10000,
							'link'     => tsdk_utmify( 'https://themeisle.com/themes/neve/upgrade/', 'section-' . $args['section'] ),
						]
					),
					'Neve\Customizer\Controls\Simple_Upsell'
				)
			);
		}
	}
}
PK      E³ò\º€ˆ:G  :G    form_fields.phpnu W+A„¶        <?php
/**
 * Form Fields section.
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use HFG\Traits\Core;
use Neve\Core\Settings\Config;
use Neve\Core\Settings\Mods;
use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Types\Control;
use Neve\Customizer\Types\Section;

/**
 * Class Form_Fields
 *
 * @package Neve\Customizer\Options
 */
class Form_Fields extends Base_Customizer {
	use Core;

	/**
	 * Customizer section slug.
	 *
	 * @var string
	 */
	private $section_id = 'neve_form_fields_section';

	/**
	 * Function that should be extended to add customizer controls.
	 *
	 * @return void
	 */
	public function add_controls() {
		$this->add_form_section();
		$this->add_form_fields_controls();
		$this->add_input_text_controls();
		$this->add_form_labels_controls();
		$this->add_button_controls();
	}

	/**
	 * Add section.
	 */
	private function add_form_section() {
		$this->add_section(
			new Section(
				$this->section_id,
				[
					'priority'           => 45,
					'description_hidden' => true,
					'description'        => __( 'Customize the general design of the form elements across the site.', 'neve' ) . ' ' . neve_external_link( 'https://docs.themeisle.com/article/1341-neve-form-fields', 'Learn More' ),
					'title'              => esc_html__( 'Form Fields', 'neve' ),
				]
			)
		);
	}

	/**
	 * Form fields controls.
	 */
	private function add_form_fields_controls() {
		$this->add_control(
			new Control(
				'neve_form_fields_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
				],
				[
					'label'            => esc_html__( 'Form Fields', 'neve' ),
					'section'          => $this->section_id,
					'priority'         => 10,
					'class'            => 'form-fields-accordion',
					'accordion'        => true,
					'controls_to_wrap' => 5,
				],
				'Neve\Customizer\Controls\Heading'
			)
		);

		// Padding
		$default_padding = Mods::get_alternative_mod_default( Config::MODS_FORM_FIELDS_PADDING );
		$this->add_control(
			new Control(
				Config::MODS_FORM_FIELDS_PADDING,
				[
					'sanitize_callback' => [ $this, 'sanitize_spacing_array' ],
					'transport'         => $this->selective_refresh,
					'default'           => $default_padding,
				],
				[
					'label'                 => esc_html__( 'Field Padding', 'neve' ),
					'section'               => $this->section_id,
					'priority'              => 15,
					'units'                 => [ 'px', 'em', 'rem' ],
					'default'               => $default_padding,
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar'      => [
							'selector' => 'body',
							'vars'     => '--formfieldpadding',
							'suffix'   => 'px',
						],
						'responsive'  => false,
						'directional' => true,
						'template'    =>
							'
							body form input:read-write,
							body form textarea,
							body form select,
							body form select option,
							body form.wp-block-search input.wp-block-search__input,
							.woocommerce-cart table.cart td.actions .coupon .input-text,
							.woocommerce-page .select2-container--default .select2-selection--single,
							.woocommerce-page .woocommerce form .form-row input.input-text,
							.woocommerce-page .woocommerce form .form-row textarea,
							.widget select,
							.wc-block-product-search form input.wc-block-product-search__field {
								 padding-top: {{value.top}};
								 padding-right: {{value.right}};
								 padding-bottom: {{value.bottom}};
								 padding-left: {{value.left}};
					        }
					        form.search-form input[type="search"],
					        form.woocommerce-product-search input[type="search"] {
					             padding-right: calc({{value.right}} + 33px);
					        }',
					],
				],
				'\Neve\Customizer\Controls\React\Nr_Spacing'
			)
		);

		// Background color
		$this->add_control(
			new Control(
				Config::MODS_FORM_FIELDS_BACKGROUND_COLOR,
				[
					'sanitize_callback' => 'neve_sanitize_colors',
					'default'           => 'var(--nv-site-bg)',
					'transport'         => $this->selective_refresh,
				],
				[
					'label'                 => esc_html__( 'Field Background Color', 'neve' ),
					'section'               => $this->section_id,
					'priority'              => 17,
					'default'               => 'var(--nv-site-bg)',
					'input_attrs'           => [
						'allow_gradient' => true,
					],
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar'   => [
							'selector' => 'body',
							'vars'     => '--formfieldbgcolor',
						],
						'template' => '
							body form input:read-write,
							body form textarea,
							body form select,
							body form select option,
							body form.wp-block-search input.wp-block-search__input,
							.woocommerce-cart table.cart td.actions .coupon .input-text,
							.woocommerce-page .select2-container--default .select2-selection--single,
							.woocommerce-page .woocommerce form .form-row input.input-text,
							.woocommerce-page .woocommerce form .form-row textarea,
							.widget select,
							.wc-block-product-search form input.wc-block-product-search__field {
							    background-color: {{value}};
						    }',

					],
				],
				'Neve\Customizer\Controls\React\Color'
			)
		);

		// Border width
		$default_width = Mods::get_alternative_mod_default( Config::MODS_FORM_FIELDS_BORDER_WIDTH );
		$this->add_control(
			new Control(
				Config::MODS_FORM_FIELDS_BORDER_WIDTH,
				[
					'sanitize_callback' => [ $this, 'sanitize_spacing_array' ],
					'transport'         => $this->selective_refresh,
					'default'           => $default_width,
				],
				[
					'label'                 => esc_html__( 'Border Width', 'neve' ),
					'section'               => $this->section_id,
					'priority'              => 18,
					'units'                 => [ 'px', 'em', 'rem' ],
					'default'               => $default_width,
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar'      => [
							'selector' => 'body',
							'vars'     => '--formfieldborderwidth',
							'suffix'   => 'px',
						],
						'responsive'  => false,
						'directional' => true,
						'template'    => '
							body form input:read-write,
							body form textarea,
							body form select,
							body form select option,
							body form.wp-block-search input.wp-block-search__input,
							.woocommerce-cart table.cart td.actions .coupon .input-text,
							.woocommerce-page .select2-container--default .select2-selection--single,
							.woocommerce-page .woocommerce form .form-row input.input-text,
							.woocommerce-page .woocommerce form .form-row textarea,
							.widget select,
							.wc-block-product-search form input.wc-block-product-search__field {
                                border-top-width: {{value.top}};
							    border-right-width: {{value.right}};
						        border-bottom-width: {{value.bottom}};
						        border-left-width: {{value.left}};
					         }',
					],
				],
				'\Neve\Customizer\Controls\React\Nr_Spacing'
			)
		);

		// Border radius
		$this->add_control(
			new Control(
				Config::MODS_FORM_FIELDS_BORDER_RADIUS,
				[
					'sanitize_callback' => [ $this, 'sanitize_spacing_array' ],
					'transport'         => $this->selective_refresh,
					'default'           => false,
				],
				[
					'label'                 => esc_html__( 'Border Radius', 'neve' ),
					'section'               => $this->section_id,
					'priority'              => 19,
					'units'                 => [ 'px', 'em', 'rem' ],
					'default'               => [
						'top'    => '3',
						'right'  => '3',
						'left'   => '3',
						'bottom' => '3',
						'unit'   => 'px',
					],
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar'      => [
							'selector' => 'body',
							'vars'     => '--formfieldborderradius',
							'suffix'   => 'px',
						],
						'responsive'  => false,
						'directional' => true,
						'template'    => '
							body form input:read-write,
							body form textarea,
							body form select,
							body form select option,
							body form.wp-block-search input.wp-block-search__input,
							.woocommerce-cart table.cart td.actions .coupon .input-text,
							.woocommerce-page .select2-container--default .select2-selection--single,
							.woocommerce-page .woocommerce form .form-row input.input-text,
							.woocommerce-page .woocommerce form .form-row textarea,
							.widget select,
							.wc-block-product-search form input.wc-block-product-search__field {
								border-top-right-radius: {{value.top}};
								border-bottom-right-radius: {{value.right}};
								border-bottom-left-radius: {{value.bottom}};
								border-top-left-radius: {{value.left}};
							}',
					],
				],
				'\Neve\Customizer\Controls\React\Nr_Spacing'
			)
		);

		// Border color
		$this->add_control(
			new Control(
				Config::MODS_FORM_FIELDS_BORDER_COLOR,
				[
					'sanitize_callback' => 'neve_sanitize_colors',
					'default'           => '#dddddd',
					'transport'         => $this->selective_refresh,
				],
				[
					'label'                 => esc_html__( 'Border Color', 'neve' ),
					'section'               => $this->section_id,
					'priority'              => 20,
					'default'               => '#dddddd',
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar'   => [
							'selector' => 'body',
							'vars'     => '--formfieldbordercolor',
						],
						'template' => '
							body form input:read-write,
							body form textarea,
							body form select,
							body form select option,
							body form.wp-block-search input.wp-block-search__input,
							.woocommerce-cart table.cart td.actions .coupon .input-text,
							.woocommerce-page .select2-container--default .select2-selection--single,
							.woocommerce-page .woocommerce form .form-row input.input-text,
							.woocommerce-page .woocommerce form .form-row textarea,
							.widget select,
							.wc-block-product-search form input.wc-block-product-search__field {
								border-color: {{value}};
							}',
					],
				],
				'Neve\Customizer\Controls\React\Color'
			)
		);
	}

	/**
	 * Form inputs controls.
	 */
	private function add_input_text_controls() {
		$this->add_control(
			new Control(
				'neve_input_text_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
				],
				[
					'label'            => esc_html__( 'Input Text', 'neve' ),
					'section'          => $this->section_id,
					'priority'         => 30,
					'class'            => 'form-input-accordion',
					'accordion'        => true,
					'expanded'         => false,
					'controls_to_wrap' => 2,
				],
				'Neve\Customizer\Controls\Heading'
			)
		);

		// Field text color
		$this->add_control(
			new Control(
				Config::MODS_FORM_FIELDS_COLOR,
				[
					'sanitize_callback' => 'neve_sanitize_colors',
					'default'           => 'var(--nv-text-color)',
					'transport'         => $this->selective_refresh,
				],
				[
					'label'                 => esc_html__( 'Color', 'neve' ),
					'section'               => $this->section_id,
					'priority'              => 31,
					'default'               => 'var(--nv-text-color)',
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar'   => [
							'selector' => 'body',
							'vars'     => '--formfieldcolor',
						],
						'template' => '
							body form input:read-write,
							body form textarea,
							body form select,
							body form select option,
							body form.wp-block-search input.wp-block-search__input,
							.woocommerce-cart table.cart td.actions .coupon .input-text,
							.woocommerce-page .select2-container--default .select2-selection--single,
							.woocommerce-page .woocommerce form .form-row input.input-text,
							.woocommerce-page .woocommerce form .form-row textarea,
							.widget select,
							.wc-block-product-search form input.wc-block-product-search__field {
								color: {{value}};
							}',
					],
				],
				'Neve\Customizer\Controls\React\Color'
			)
		);

		// Field typeface
		$this->add_control(
			new Control(
				Config::MODS_FORM_FIELDS_TYPEFACE,
				[
					'transport' => $this->selective_refresh,
				],
				[
					'priority'              => 32,
					'section'               => $this->section_id,
					'input_attrs'           => array(
						'disable_transform'      => true,
						'default_is_empty'       => true,
						'size_units'             => [ 'px', 'em', 'rem' ],
						'weight_default'         => 'none',
						'size_default'           => array(
							'suffix'  => array(
								'mobile'  => 'px',
								'tablet'  => 'px',
								'desktop' => 'px',
							),
							'mobile'  => '',
							'tablet'  => '',
							'desktop' => '',
						),
						'line_height_default'    => array(
							'mobile'  => '',
							'tablet'  => '',
							'desktop' => '',
						),
						'letter_spacing_default' => array(
							'mobile'  => '',
							'tablet'  => '',
							'desktop' => '',
						),
					),
					'type'                  => 'neve_typeface_control',
					'font_family_control'   => 'neve_body_font_family',
					'refresh_on_reset'      => true,
					'live_refresh_selector' => '
						form input:read-write,
						form textarea,
						form select,
						form select option,
						form.wp-block-search input.wp-block-search__input,
						.woocommerce-cart table.cart td.actions .coupon .input-text,
						.woocommerce-page .select2-container--default .select2-selection--single,
						.woocommerce-page .woocommerce form .form-row input.input-text,
						.woocommerce-page .woocommerce form .form-row textarea,
						.widget select,
						.wc-block-product-search form input.wc-block-product-search__field
					',
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'     => [
								'--formfieldtexttransform' => 'textTransform',
								'--formfieldfontweight'    => 'fontWeight',
								'--formfieldfontsize'      => [
									'key'        => 'fontSize',
									'responsive' => true,
								],
								'--formfieldlineheight'    => [
									'key'        => 'lineHeight',
									'responsive' => true,
								],
								'--formfieldletterspacing' => [
									'key'        => 'letterSpacing',
									'suffix'     => 'px',
									'responsive' => true,
								],
							],
							'selector' => 'body',
						],
					],
				],
				'\Neve\Customizer\Controls\React\Typography'
			)
		);
	}

	/**
	 * Form labels controls.
	 */
	private function add_form_labels_controls() {
		$this->add_control(
			new Control(
				'neve_form_labels_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
				],
				[
					'label'            => esc_html__( 'Form Labels', 'neve' ),
					'section'          => $this->section_id,
					'priority'         => 50,
					'class'            => 'form-labels-accordion',
					'accordion'        => true,
					'expanded'         => false,
					'controls_to_wrap' => 1,
				],
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				Config::MODS_FORM_FIELDS_LABELS_TYPEFACE,
				[
					'transport' => $this->selective_refresh,
				],
				[
					'priority'              => 52,
					'section'               => $this->section_id,
					'input_attrs'           => [
						'default_is_empty'       => true,
						'size_units'             => [ 'px', 'em', 'rem' ],
						'weight_default'         => 'none',
						'size_default'           => [
							'suffix'  => [
								'mobile'  => 'px',
								'tablet'  => 'px',
								'desktop' => 'px',
							],
							'mobile'  => '',
							'tablet'  => '',
							'desktop' => '',
						],
						'line_height_default'    => [
							'mobile'  => '',
							'tablet'  => '',
							'desktop' => '',
						],
						'letter_spacing_default' => [
							'mobile'  => '',
							'tablet'  => '',
							'desktop' => '',
						],
					],
					'type'                  => 'neve_typeface_control',
					'font_family_control'   => 'neve_body_font_family',
					'refresh_on_reset'      => true,
					'live_refresh_selector' => 'form label, body .wpforms-container .wpforms-field-label, .woocommerce form .form-row label',
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'     => [
								'--formlabeltexttransform' => 'textTransform',
								'--formlabelfontweight'    => 'fontWeight',
								'--formlabelfontsize'      => [
									'key'        => 'fontSize',
									'responsive' => true,
								],
								'--formlabellineheight'    => [
									'key'        => 'lineHeight',
									'responsive' => true,
								],
								'--formlabelletterspacing' => [
									'key'        => 'letterSpacing',
									'suffix'     => 'px',
									'responsive' => true,
								],
							],
							'selector' => 'body',
						],
					],
				],
				'\Neve\Customizer\Controls\React\Typography'
			)
		);
	}

	/**
	 * Form button controls.
	 */
	private function add_button_controls() {
		$this->add_control(
			new Control(
				'neve_form_button_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
				],
				array(
					'label'            => esc_html__( 'Button', 'neve' ),
					'section'          => $this->section_id,
					'priority'         => 70,
					'class'            => 'form-button-accordion',
					'accordion'        => true,
					'expanded'         => false,
					'controls_to_wrap' => 1,
				),
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				'neve_form_button_type',
				[
					'sanitize_callback' => 'neve_sanitize_button_type',
					'default'           => 'primary',
				],
				[
					'label'    => __( 'Button Style', 'neve' ),
					'priority' => 71,
					'section'  => $this->section_id,
					'type'     => 'neve_inline_select',
					'options'  => [
						'primary'   => __( 'Primary', 'neve' ),
						'secondary' => __( 'Secondary', 'neve' ),
					],
					'default'  => 'primary',
					'link'     => [
						'focus'  => [ 'section', 'neve_buttons_section' ],
						'string' => esc_html__( 'Customize the default button styles', 'neve' ),
					],
				],
				'Neve\Customizer\Controls\React\Inline_Select'
			)
		);
	}
}
PK      E³ò\–®Å‰  ‰    buttons.phpnu W+A„¶        <?php
/**
 * Buttons section.
 *
 * Author:          Andrei Baicus <andrei@themeisle.com>
 * Created on:      20/08/2018
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Core\Settings\Config;
use Neve\Core\Settings\Mods;
use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Types\Control;
use Neve\Customizer\Types\Section;

/**
 * Class Buttons
 *
 * @package Neve\Customizer\Options
 */
class Buttons extends Base_Customizer {

	/**
	 * Customizer section slug.
	 *
	 * @var string
	 */
	private $section_id = 'neve_buttons_section';

	/**
	 * Function that should be extended to add customizer controls.
	 *
	 * @return void
	 */
	public function add_controls() {
		$this->add_section(
			new Section(
				$this->section_id,
				array(
					'priority' => 40,
					'title'    => esc_html__( 'Buttons', 'neve' ),
				)
			)
		);

		$this->add_control(
			new Control(
				'neve_buttons_generic_heading',
				[
					'sanitize_callback' => 'sanitize_text_field',
				],
				[
					'label'            => esc_html__( 'General', 'neve' ),
					'section'          => $this->section_id,
					'class'            => 'buttons-general-accordion',
					'accordion'        => true,
					'expanded'         => true,
					'controls_to_wrap' => 2,
				],
				'Neve\Customizer\Controls\Heading'
			)
		);

		$mod_key  = Config::MODS_BUTTON_PRIMARY_PADDING;
		$defaults = Mods::get_alternative_mod_default( Config::MODS_BUTTON_PRIMARY_PADDING );
		$this->add_control(
			new Control(
				$mod_key,
				array(
					'default' => $defaults,
				),
				array(
					'label'             => __( 'Padding', 'neve' ),
					'sanitize_callback' => array( $this, 'sanitize_spacing_array' ),
					'section'           => $this->section_id,
					'input_attrs'       => [
						'units' => [ 'px', 'em', 'rem' ],
						'min'   => 0,
					],
					'default'           => $defaults,
				),
				'\Neve\Customizer\Controls\React\Spacing'
			)
		);

		$this->add_control(
			new Control(
				Config::MODS_BUTTON_TYPEFACE,
				[
					'transport' => $this->selective_refresh,
				],
				[
					'label'                 => esc_html__( 'Button Text', 'neve' ),
					'section'               => $this->section_id,
					'input_attrs'           => array(
						'size_units'             => [ 'px', 'em', 'rem' ],
						'weight_default'         => 700,
						'size_default'           => array(
							'suffix'  => array(
								'mobile'  => 'px',
								'tablet'  => 'px',
								'desktop' => 'px',
							),
							'mobile'  => '',
							'tablet'  => '',
							'desktop' => '',
						),
						'line_height_default'    => array(
							'mobile'  => '',
							'tablet'  => '',
							'desktop' => '',
						),
						'letter_spacing_default' => array(
							'mobile'  => '',
							'tablet'  => '',
							'desktop' => '',
						),
					),
					'type'                  => 'neve_typeface_control',
					'font_family_control'   => 'neve_body_font_family',
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => [
							'vars'     => [
								'--btnfs'            => [
									'key'        => 'fontSize',
									'responsive' => true,
									'suffix'     => 'px',
								],
								'--btnlineheight'    => [
									'key'        => 'lineHeight',
									'responsive' => true,
								],
								'--btnletterspacing' => [
									'key'        => 'letterSpacing',
									'responsive' => true,
									'suffix'     => 'px',
								],
								'--btntexttransform' => [
									'key' => 'textTransform',
								],
								'--btnfontweight'    => [
									'key' => 'fontWeight',
								],
							],
							'selector' => 'body',
						],
					],
					'refresh_on_reset'      => true,
				],
				'\Neve\Customizer\Controls\React\Typography'
			)
		);

		$buttons = [
			'button'           => __( 'Primary Button', 'neve' ),
			'secondary_button' => __( 'Secondary Button', 'neve' ),
		];

		foreach ( $buttons as $button => $heading_text ) {
			$this->add_control(
				new Control(
					'neve_' . $button . '_appearance_heading',
					[
						'sanitize_callback' => 'sanitize_text_field',
					],
					[
						'label'            => esc_html( $heading_text ),
						'section'          => $this->section_id,
						'class'            => 'buttons-' . $button . '-appearance-accordion',
						'accordion'        => true,
						'controls_to_wrap' => 1,
						'expanded'         => false,
					],
					'Neve\Customizer\Controls\Heading'
				)
			);

			$mod_key  = 'neve_' . $button . '_appearance';
			$defaults = neve_get_button_appearance_default( $button );

			$this->add_control(
				new Control(
					$mod_key,
					[
						'sanitize_callback' => 'neve_sanitize_button_appearance',
						'default'           => $defaults,
					],
					[
						'default_vals' => $defaults,
						'label'        => __( 'Button Appearance', 'neve' ),
						'section'      => $this->section_id,
					],
					'\Neve\Customizer\Controls\React\Button_Appearance'
				)
			);
		}
	}
}
PK      E³ò\JY–      layout_single_product.phpnu W+A„¶        <?php
/**
 * Single post layout section.
 *
 * Author:          Andrei Baicus <andrei@themeisle.com>
 * Created on:      20/08/2018
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Customizer\Base_Customizer;
use Neve\Customizer\Types\Control;
use Neve\Customizer\Types\Section;

/**
 * Class Layout_Single_Product
 *
 * @package Neve\Customizer\Options
 */
class Layout_Single_Product extends Base_Customizer {

	/**
	 * Add customizer controls.
	 */
	public function add_controls() {
		if ( ! $this->should_load() ) {
			return;
		}

		$this->section_single_product();
		$this->exclusive_products_controls();
	}

	/**
	 * Check if the controls for Single Product should load.
	 */
	private function should_load() {
		return class_exists( 'WooCommerce', false );
	}

	/**
	 * Add single product layout section.
	 */
	private function section_single_product() {
		$this->add_section(
			new Section(
				'neve_single_product_layout',
				array(
					'priority' => 65,
					'title'    => esc_html__( 'Single Product', 'neve' ),
					'panel'    => 'woocommerce',
				)
			)
		);
	}

	/**
	 * Add customizer controls for exclusive products section.
	 */
	private function exclusive_products_controls() {
		$this->add_control(
			new Control(
				'neve_exclusive_products_heading',
				array(
					'sanitize_callback' => 'sanitize_text_field',
					'transport'         => $this->selective_refresh,
				),
				array(
					'label'            => esc_html__( 'Exclusive Products', 'neve' ),
					'section'          => 'neve_single_product_layout',
					'priority'         => 200,
					'class'            => 'exclusive-products-accordion',
					'accordion'        => true,
					'controls_to_wrap' => 2,
					'expanded'         => true,
				),
				'Neve\Customizer\Controls\Heading'
			)
		);

		$this->add_control(
			new Control(
				'neve_exclusive_products_title',
				array(
					'sanitize_callback' => 'sanitize_text_field',
				),
				array(
					'priority' => 210,
					'section'  => 'neve_single_product_layout',
					'label'    => esc_html__( 'Title', 'neve' ),
					'type'     => 'text',
				)
			)
		);

		$product_cat = $this->get_shop_categories();
		$this->add_control(
			new Control(
				'neve_exclusive_products_category',
				array(
					'default'           => '-',
					'sanitize_callback' => array( $this, 'sanitize_categories' ),
				),
				array(
					'label'    => esc_html__( 'Category', 'neve' ),
					'section'  => 'neve_single_product_layout',
					'priority' => 220,
					'type'     => 'select',
					'choices'  => $product_cat,
				)
			)
		);
	}

	/**
	 * Get shop categories.
	 *
	 * @return array
	 */
	private function get_shop_categories() {
		$categories         = array(
			'-'   => esc_html__( 'None', 'neve' ),
			'all' => esc_html__( 'All', 'neve' ),
		);
		$product_categories = get_categories(
			array(
				'taxonomy'   => 'product_cat',
				'hide_empty' => 0,
				'title_li'   => '',
			)
		);
		if ( empty( $product_categories ) ) {
			return $categories;
		}

		foreach ( $product_categories as $category ) {
			$term_id  = $category->term_id;
			$cat_name = $category->name;
			if ( empty( $term_id ) || empty( $cat_name ) ) {
				continue;
			}

			$categories[ $term_id ] = $cat_name;
		}

		return $categories;
	}

	/**
	 * Sanitize categories value.
	 *
	 * @param string $value Value from the control.
	 *
	 * @return string
	 */
	public function sanitize_categories( $value ) {
		$categories = $this->get_shop_categories();
		if ( ! array_key_exists( $value, $categories ) ) {
			return '-';
		}

		return $value;
	}


}
PK      E³ò\âk4é‚  ‚    rtl.phpnu W+A„¶        <?php
/**
 * Rtl customizer compatibility.
 *
 * Author:          Andrei Baicus <andrei@themeisle.com>
 * Created on:      24/09/2018
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use Neve\Customizer\Base_Customizer;

/**
 * Class Rtl
 *
 * @package Neve\Customizer\Options
 */
class Rtl extends Base_Customizer {
	/**
	 * Abstract method that must be implemented.
	 */
	public function add_controls() {}

	/**
	 * Change controls
	 */
	protected function change_controls() {
		if ( ! is_rtl() ) {
			return;
		}

		$this->change_customizer_object( 'control', 'neve_navigation_layout', 'choices', $this->rtl_navigation_layout_choices() );

		$this->change_customizer_object( 'control', 'neve_top_bar_layout', 'choices', $this->rtl_top_bar_layout_choices() );

		$sidebar_layout_controls = array(
			'neve_default_sidebar_layout',
			'neve_blog_archive_sidebar_layout',
			'neve_single_post_sidebar_layout',
		);

		if ( class_exists( 'WooCommerce', false ) ) {
			$sidebar_layout_controls = array_merge(
				$sidebar_layout_controls,
				array(
					'neve_shop_archive_sidebar_layout',
					'neve_single_product_sidebar_layout',
				)
			);
		}
		foreach ( $sidebar_layout_controls as $control_id ) {
			$this->change_customizer_object( 'control', $control_id, 'choices', $this->rtl_sidebar_layout_choices() );
		}
	}

	/**
	 * Get the rtl navigation layout choices.
	 *
	 * @return array
	 */
	private function rtl_navigation_layout_choices() {
		return array(
			'left'   => array(
				'url' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAABqCAMAAABpj1iyAAAADFBMVEUAhbo+yP/V1dX///9l36pFAAAAdUlEQVR4Ae3VMQrAMAwEQSX5/5/TujIYJPDBbKduqlN9V4aFhTXYsy+JVWsNdz4LCwtrJiyvGgsLCwsLCwsrioWFhYWFhYWFHfVOhoWFFTwQWFhYPYuAhYVlt7CwsLAOpxMLCwsrdE6xsLCwsLCwsLCwsLCwfkRXrgTYLelPAAAAAElFTkSuQmCC',
			),
			'center' => array(
				'url' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAABqAgMAAAAjP0ATAAAADFBMVEX////V1dUAhbo+yP8aB7nsAAAARElEQVRYR2NgGKngPwT8GVU2BJQNb6C1atUCfHjEKRsFo2BEANFQrCBg+CkbWYDIwBgGykYBBYDIkB1VNgpGwSgYMAAAzIYr4wYj4sEAAAAASUVORK5CYII=',
			),
			'right'  => array(
				'url' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAABqAgMAAAAjP0ATAAAADFBMVEX////V1dUAhbo+yP8aB7nsAAAARklEQVRYhWNgGEGA/z8EHKC+MqZVq1ah4xGtjOLgHQWjYBSMgmENREOxgoDhp2xkASIDYxgoGwUUACJDdlTZKBgFo2DAAAAZAflVkm2NtwAAAABJRU5ErkJggg==',
			),
		);
	}

	/**
	 * Get the rtl top_bar layout choices.
	 *
	 * @return array
	 */
	private function rtl_top_bar_layout_choices() {
		return array(
			'content-menu' => array(
				'url' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAABqCAMAAABpj1iyAAAAXVBMVEUAbq4AebMAe7QAe7UAhboFfLQFh7sjjr49l8NToMhmqMx3sNGGuNWVwNqjyN6wz+K81ufB3+3B4e7C4u7I3evR6fPU5O/V6/Tf6/Pq8vf1+fv1+vz6/f7+//////+gH6NhAAABU0lEQVR42u3UzU7DMBAE4AID/k8CBGObsu//mN0kVRMEUukl6mFGSjbjXD5Zlg9ylyGLLLLIIossssgiiyyyyCKLLLLIIossssgiiyyyyCKLLLLIug8WIH/EI19jvb9d8vol37fUH8l1Hm0eNdf5owDLemnTv1ykTNOhL1dYzw+XHD7k+HhD3aSzQGhSIuBHrdAeRTyATmSwMNoyjIGtOgF/HfWCS54+5XhLXVNhkndNInyEVZZ2oJx3qxnTOYwTJxn0y27twYoY1CYNRiRgVFbS2Z3P1gDrLYKyrPTwy9nag5XQSy3SzMzKyur0WVnGe5+U5SXvyapAgKkS4QKsrCyHECdtcq6trA7W7XLkewc7iLRoEMqGNWrXt4NJG1a1sHWfC6LIekFss/Rfq7zlySKLLLLIIossssgiiyyyyCKLLLLIIossssgiiyyyyCKLrP/mBGV6EYQ9BHpwAAAAAElFTkSuQmCC',
			),
			'menu-content' => array(
				'url' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAABqCAMAAABpj1iyAAAAXVBMVEUAbq4AebMAe7QAe7UAhboFfLQFh7sjjr49l8NToMhmqMx3sNGGuNWVwNqjyN6wz+K81ufB3+3B4e7C4u7I3evR6fPU5O/V6/Tf6/Pq8vf1+fv1+vz6/f7+//////+gH6NhAAABVklEQVR4Ae3VzU7DMBAE4AID/onjBCjBNmXe/zHZplEbqahShRRxmDl0Oz59slbOjv8yYoklllhiiSWWWGKJJZZYYoklllhiiSWWWGKJJZZYYokl1p8jFsBfEjFtxZrqPNo86lTnPwU4nZdGsk2F5TgDhsJV3t/Oef3i9z31Nit7oGssCYh7q7CeyAggk6OHszbBOfhqE4hc5fnhnN0HD4931JusCtfH0JgQE7yxrANlua3mXA7YHzm9w3B9Wy845+mThzvqbVbCaDY2OLIzQEZvMy+7NcJHj85YngPislsbsHoMrIXNzayJ2Uh5xXIxxt5YkdOWrAp0cJUJoYPnhRXQpaO2D6FdWBk+bMHiEOBHsiWHrqxYe+v2G+D6Fat6+LrBylsKVw/EKqd+fbrJA7FEHx+xxBJLLLHEEkssscQSSyyxxBJLLLHEEkssscQSSyyxxBLrBzxgEYQpIrleAAAAAElFTkSuQmCC',
			),
		);
	}

	/**
	 * Get the sidebar layout choices.
	 *
	 * @return array
	 */
	private function rtl_sidebar_layout_choices() {
		return array(
			'full-width' => array(
				'url' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAABqAQMAAABknzrDAAAABlBMVEX////V1dXUdjOkAAAAPUlEQVRIx2NgGAUkAcb////Y/+d/+P8AdcQoc8vhH/X/5P+j2kG+GA3CCgrwi43aMWrHqB2jdowEO4YpAACyKSE0IzIuBgAAAABJRU5ErkJggg==',
			),
			'left'       => array(
				'url' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAABqAgMAAAAjP0ATAAAACVBMVEX///8+yP/V1dXG9YqxAAAAWUlEQVR42mNgGAUjB4iGgkEIzZStAoEVTECiQWsVkLdiECkboAABOmwBF9BtUGcOImUDEiCkJCQU0ECBslEvjHph1AujXhj1wqgXRr0w6oVRLwyEF0bBUAUAz/FTNXm+R/MAAAAASUVORK5CYII=',
			),
			'right'      => array(
				'url' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAABqAgMAAAAjP0ATAAAACVBMVEX///8+yP/V1dXG9YqxAAAAWElEQVR42mNgGAXDE4RCQMDAKONaBQINWqtWrWBatQDIaxg8ygYqQIAOYwC6bwHUmYNH2eBPSMhgBQXKRr0w6oVRL4x6YdQLo14Y9cKoF0a9QCO3jYLhBADvmFlNY69qsQAAAABJRU5ErkJggg==',
			),
		);
	}
}
PK      E³ò\×˜áÕ{H  {H    layout_single_post.phpnu W+A„¶        <?php
/**
 * Single post layout section.
 *
 * Author:          Andrei Baicus <andrei@themeisle.com>
 * Created on:      20/08/2018
 *
 * @package Neve\Customizer\Options
 */

namespace Neve\Customizer\Options;

use HFG\Traits\Core;
use Neve\Core\Settings\Config;
use Neve\Customizer\Defaults\Layout;
use Neve\Customizer\Types\Control;
use Neve\Customizer\Defaults\Single_Post;

/**
 * Class Layout_Single_Post
 *
 * @package Neve\Customizer\Options
 */
class Layout_Single_Post extends Base_Layout_Single {
	use Core;
	use Layout;
	use Single_Post;

	/**
	 * Returns the post type.
	 *
	 * @return string
	 */
	public function get_post_type() {
		return 'post';
	}

	/**
	 * @return string
	 */
	public function get_cover_selector() {
		return '.single .nv-post-cover';
	}

	/**
	 * Function that should be extended to add customizer controls.
	 *
	 * @return void
	 */
	public function add_controls() {
		parent::add_controls();
		$this->control_content_order();
		$this->content_vspacing();
		$this->add_subsections();
		$this->header_layout();
		$this->post_meta();
		$this->comments();
		add_action( 'customize_register', [ $this, 'adjust_headings' ], PHP_INT_MAX );
	}

	/**
	 * Add sections headings.
	 */
	private function add_subsections() {

		$headings = [
			'page_elements'    => [
				'title'            => esc_html__( 'Page Elements', 'neve' ),
				'priority'         => 95,
				'controls_to_wrap' => 2,
				'expanded'         => false,
			],
			'page_settings'    => [
				'title'            => esc_html__( 'Page', 'neve' ) . ' ' . esc_html__( 'Settings', 'neve' ),
				'priority'         => 106,
				'controls_to_wrap' => 2,
				'expanded'         => false,
			],
			'meta'             => [
				'title'            => esc_html__( 'Post Meta', 'neve' ),
				'priority'         => 110,
				'controls_to_wrap' => 5,
				'expanded'         => false,
			],
			'comments_section' => [
				'title'           => esc_html__( 'Comments Section', 'neve' ),
				'priority'        => 150,
				'expanded'        => true,
				'accordion'       => false,
				'active_callback' => function() {
					return $this->element_is_enabled( 'comments' );
				},
			],
			'comments_form'    => [
				'title'           => esc_html__( 'Submit Form Section', 'neve' ),
				'priority'        => 175,
				'expanded'        => true,
				'accordion'       => false,
				'active_callback' => function() {
					return $this->element_is_enabled( 'comments' );
				},
			],
		];

		foreach ( $headings as $heading_id => $heading_data ) {
			$this->add_control(
				new Control(
					'neve_post_' . $heading_id . '_heading',
					[
						'sanitize_callback' => 'sanitize_text_field',
					],
					[
						'label'            => $heading_data['title'],
						'section'          => $this->section,
						'priority'         => $heading_data['priority'],
						'class'            => $heading_id . '-accordion',
						'expanded'         => $heading_data['expanded'],
						'accordion'        => array_key_exists( 'accordion', $heading_data ) ? $heading_data['accordion'] : true,
						'controls_to_wrap' => array_key_exists( 'controls_to_wrap', $heading_data ) ? $heading_data['controls_to_wrap'] : 0,
						'active_callback'  => array_key_exists( 'active_callback', $heading_data ) ? $heading_data['active_callback'] : '__return_true',
					],
					'Neve\Customizer\Controls\Heading'
				)
			);
		}
	}

	/**
	 * Add header layout controls.
	 */
	private function header_layout() {
		$this->add_control(
			new Control(
				'neve_post_cover_meta_before_title',
				[
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => false,
				],
				[
					'label'           => esc_html__( 'Display meta before title', 'neve' ),
					'section'         => $this->section,
					'type'            => 'neve_toggle_control',
					'priority'        => 40,
					'active_callback' => [ $this, 'is_cover_layout' ],
				],
				'Neve\Customizer\Controls\Checkbox'
			)
		);
	}

	/**
	 * Add content order control.
	 */
	private function control_content_order() {

		$all_components = [
			'title-meta'      => __( 'Title & Meta', 'neve' ),
			'thumbnail'       => __( 'Thumbnail', 'neve' ),
			'content'         => __( 'Content', 'neve' ),
			'tags'            => __( 'Tags', 'neve' ),
			'post-navigation' => __( 'Post navigation', 'neve' ),
			'comments'        => __( 'Comments', 'neve' ),
		];

		if ( self::is_cover_layout() ) {
			$all_components = [
				'content'         => __( 'Content', 'neve' ),
				'tags'            => __( 'Tags', 'neve' ),
				'post-navigation' => __( 'Post navigation', 'neve' ),
				'comments'        => __( 'Comments', 'neve' ),
			];
		}

		$order_default_components = $this->post_ordering();

		/**
		 * Filters the elements on the single post page.
		 *
		 * @param array $all_components Single post page components.
		 *
		 * @since 2.11.4
		 */
		$components = apply_filters( 'neve_single_post_elements', $all_components );

		$this->add_control(
			new Control(
				'neve_layout_single_post_elements_order',
				[
					'sanitize_callback' => [ $this, 'sanitize_post_elements_ordering' ],
					'default'           => wp_json_encode( $order_default_components ),
				],
				[
					'label'      => esc_html__( 'Elements Order', 'neve' ),
					'section'    => $this->section,
					'components' => $components,
					'priority'   => 100,
				],
				'Neve\Customizer\Controls\React\Ordering'
			)
		);

		$this->add_control(
			new Control(
				'neve_single_post_elements_spacing',
				[
					'sanitize_callback' => 'neve_sanitize_range_value',
					'transport'         => $this->selective_refresh,
					'default'           => '{"desktop":60,"tablet":60,"mobile":60}',
				],
				[
					'label'                 => esc_html__( 'Spacing between elements', 'neve' ),
					'section'               => $this->section,
					'type'                  => 'neve_responsive_range_control',
					'input_attrs'           => [
						'max'        => 500,
						'units'      => [ 'px', 'em', 'rem' ],
						'defaultVal' => [
							'mobile'  => 60,
							'tablet'  => 60,
							'desktop' => 60,
							'suffix'  => [
								'mobile'  => 'px',
								'tablet'  => 'px',
								'desktop' => 'px',
							],
						],
					],
					'priority'              => 105,
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar' => [
							'responsive' => true,
							'vars'       => '--spacing',
							'selector'   => '.nv-single-post-wrap',
							'suffix'     => 'px',
						],
					],
				],
				'\Neve\Customizer\Controls\React\Responsive_Range'
			)
		);
	}

	/**
	 * Add content spacing control.
	 */
	private function content_vspacing() {
		$this->add_control(
			new Control(
				Config::MODS_SINGLE_POST_VSPACING_INHERIT,
				[
					'sanitize_callback' => 'neve_sanitize_vspace_type',
					'default'           => 'inherit',
				],
				[
					'label'              => esc_html__( 'Content Vertical Spacing', 'neve' ),
					'section'            => $this->section,
					'priority'           => 107,
					'choices'            => [
						'inherit'  => [
							'tooltip' => esc_html__( 'Inherit', 'neve' ),
							'icon'    => 'text',
						],
						'specific' => [
							'tooltip' => esc_html__( 'Custom', 'neve' ),
							'icon'    => 'text',
						],
					],
					'footer_description' => [
						'inherit' => [
							'template'         => esc_html__( 'Customize the default vertical spacing <ctaButton>here</ctaButton>.', 'neve' ),
							'control_to_focus' => Config::MODS_CONTENT_VSPACING,
						],
					],
				],
				'\Neve\Customizer\Controls\React\Radio_Buttons'
			)
		);

		$default_value = get_theme_mod( Config::MODS_CONTENT_VSPACING, $this->content_vspacing_default() );
		$this->add_control(
			new Control(
				Config::MODS_SINGLE_POST_CONTENT_VSPACING,
				[
					'default'   => $default_value,
					'transport' => $this->selective_refresh,
				],
				[
					'label'                 => __( 'Custom Value', 'neve' ),
					'sanitize_callback'     => [ $this, 'sanitize_spacing_array' ],
					'section'               => $this->section,
					'input_attrs'           => [
						'units'     => [ 'px', 'vh' ],
						'axis'      => 'vertical',
						'dependsOn' => [ Config::MODS_SINGLE_POST_VSPACING_INHERIT => 'specific' ],
					],
					'default'               => $default_value,
					'priority'              => 107,
					'live_refresh_selector' => true,
					'live_refresh_css_prop' => [
						'cssVar'      => [
							'vars'       => '--c-vspace',
							'selector'   => 'body.single:not(.single-product) .neve-main',
							'responsive' => true,
							'fallback'   => '',
						],
						'directional' => true,
					],
				],
				'\Neve\Customizer\Controls\React\Spacing'
			)
		);
	}

	/**
	 * Add post meta controls.
	 */
	private function post_meta() {

		$components = apply_filters(
			'neve_meta_filter',
			[
				'author'   => __( 'Author', 'neve' ),
				'category' => __( 'Category', 'neve' ),
				'date'     => __( 'Date', 'neve' ),
				'comments' => __( 'Comments', 'neve' ),
			]
		);

		$default_value = get_theme_mod( 'neve_single_post_meta_fields', self::get_default_single_post_meta_fields() );

		$this->add_control(
			new Control(
				'neve_single_post_meta_fields',
				[
					'sanitize_callback' => 'neve_sanitize_meta_repeater',
					'default'           => $default_value,
				],
				[
					'label'            => esc_html__( 'Meta Order', 'neve' ),
					'section'          => $this->section,
					'fields'           => [
						'hide_on_mobile' => [
							'type'  => 'checkbox',
							'label' => __( 'Hide on mobile', 'neve' ),
						],
					],
					'components'       => $components,
					'allow_new_fields' => 'no',
					'priority'         => 115,
				],
				'\Neve\Customizer\Controls\React\Repeater'
			)
		);

		$default_separator = get_theme_mod( 'neve_metadata_separator', esc_html( '/' ) );
		$this->add_control(
			new Control(
				'neve_single_post_metadata_separator',
				[
					'sanitize_callback' => 'sanitize_text_field',
					'default'           => $default_separator,
				],
				[
					'priority'    => 120,
					'section'     => $this->section,
					'label'       => esc_html__( 'Separator', 'neve' ),
					'description' => esc_html__( 'For special characters make sure to use Unicode. For example > can be displayed using \003E.', 'neve' ),
					'type'        => 'text',
				]
			)
		);

		$author_avatar_default = get_theme_mod( 'neve_author_avatar', false );
		$this->add_control(
			new Control(
				'neve_single_post_author_avatar',
				[
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => $author_avatar_default,
				],
				[
					'label'    => esc_html__( 'Show Author Avatar', 'neve' ),
					'section'  => $this->section,
					'type'     => 'neve_toggle_control',
					'priority' => 125,
				]
			)
		);

		$avatar_size_default = get_theme_mod( 'neve_author_avatar_size', '{ "mobile": 20, "tablet": 20, "desktop": 20 }' );
		$this->add_control(
			new Control(
				'neve_single_post_avatar_size',
				[
					'sanitize_callback' => 'neve_sanitize_range_value',
					'default'           => $avatar_size_default,
				],
				[
					'label'           => esc_html__( 'Avatar Size', 'neve' ),
					'section'         => $this->section,
					'units'           => [ 'px' ],
					'input_attr'      => [
						'mobile'  => [
							'min'          => 20,
							'max'          => 50,
							'default'      => 20,
							'default_unit' => 'px',
						],
						'tablet'  => [
							'min'          => 20,
							'max'          => 50,
							'default'      => 20,
							'default_unit' => 'px',
						],
						'desktop' => [
							'min'          => 20,
							'max'          => 50,
							'default'      => 20,
							'default_unit' => 'px',
						],
					],
					'input_attrs'     => [
						'min'        => self::RELATIVE_CSS_UNIT_SUPPORTED_MIN_VALUE,
						'max'        => 50,
						'defaultVal' => [
							'mobile'  => 20,
							'tablet'  => 20,
							'desktop' => 20,
							'suffix'  => [
								'mobile'  => 'px',
								'tablet'  => 'px',
								'desktop' => 'px',
							],
						],
						'units'      => [ 'px', 'em', 'rem' ],
					],
					'priority'        => 130,
					'active_callback' => function () {
						return get_theme_mod( 'neve_single_post_author_avatar', false );
					},
					'responsive'      => true,
				],
				'Neve\Customizer\Controls\React\Responsive_Range'
			)
		);

		$this->add_control(
			new Control(
				'neve_single_post_show_last_updated_date',
				[
					'sanitize_callback' => 'neve_sanitize_checkbox',
					'default'           => get_theme_mod( 'neve_show_last_updated_date', false ),
				],
				[
					'label'    => esc_html__( 'Use last updated date instead of the published one', 'neve' ),
					'section'  => $this->section,
					'type'     => 'neve_toggle_control',
					'priority' => 135,
				]
			)
		);
	}

	/**
	 * Add comments controls.
	 */
	private function comments() {

		$this->add_control(
			new Control(
				'neve_post_comment_section_title',
				[
					'sanitize_callback' => 'sanitize_text_field',
				],
				[
					'label'           => esc_html__( 'Section title', 'neve' ),
					'description'     => esc_html__( 'The following magic tags are available for this field: {title} and {comments_number}. Leave this field empty for default behavior.', 'neve' ),
					'priority'        => 155,
					'section'         => $this->section,
					'type'            => 'text',
					'active_callback' => function() {
						return $this->element_is_enabled( 'comments' );
					},
				]
			)
		);

		$this->add_boxed_layout_controls(
			'comments',
			[
				'priority'                  => 160,
				'section'                   => $this->section,
				'padding_default'           => $this->padding_default(),
				'background_default'        => 'var(--nv-light-bg)',
				'color_default'             => 'var(--nv-text-color)',
				'boxed_selector'            => '.nv-is-boxed.nv-comments-wrap',
				'text_color_css_selector'   => '.nv-comments-wrap.nv-is-boxed, .nv-comments-wrap.nv-is-boxed a',
				'border_color_css_selector' => '.nv-comments-wrap.nv-is-boxed .nv-comment-article',
				'toggle_active_callback'    => function() {
					return $this->element_is_enabled( 'comments' );
				},
				'active_callback'           => function() {
					return $this->element_is_enabled( 'comments' ) && get_theme_mod( 'neve_comments_boxed_layout', false );
				},
			]
		);

		$this->add_control(
			new Control(
				'neve_post_comment_form_title',
				[
					'sanitize_callback' => 'sanitize_text_field',
				],
				[
					'label'           => esc_html__( 'Section title', 'neve' ),
					'priority'        => 180,
					'section'         => $this->section,
					'type'            => 'text',
					'active_callback' => function() {
						return $this->element_is_enabled( 'comments' );
					},
				]
			)
		);

		$this->add_control(
			new Control(
				'neve_post_comment_form_button_style',
				[
					'default'           => 'primary',
					'sanitize_callback' => 'neve_sanitize_button_type',
				],
				[
					'label'           => esc_html__( 'Button style', 'neve' ),
					'section'         => $this->section,
					'priority'        => 185,
					'type'            => 'select',
					'choices'         => [
						'primary'   => esc_html__( 'Primary', 'neve' ),
						'secondary' => esc_html__( 'Secondary', 'neve' ),
					],
					'active_callback' => function() {
						return $this->element_is_enabled( 'comments' );
					},
				]
			)
		);

		$this->add_control(
			new Control(
				'neve_post_comment_form_button_text',
				[
					'sanitize_callback' => 'sanitize_text_field',
				],
				[
					'label'           => esc_html__( 'Button text', 'neve' ),
					'priority'        => 190,
					'section'         => $this->section,
					'type'            => 'text',
					'active_callback' => function() {
						return $this->element_is_enabled( 'comments' );
					},
				]
			)
		);

		$this->add_boxed_layout_controls(
			'comments_form',
			[
				'priority'                => 195,
				'section'                 => $this->section,
				'padding_default'         => $this->padding_default(),
				'is_boxed_default'        => true,
				'background_default'      => 'var(--nv-light-bg)',
				'color_default'           => 'var(--nv-text-color)',
				'boxed_selector'          => '.nv-is-boxed.comment-respond',
				'text_color_css_selector' => '.comment-respond.nv-is-boxed, .comment-respond.nv-is-boxed a',
				'toggle_active_callback'  => function() {
					return $this->element_is_enabled( 'comments' );
				},
				'active_callback'         => function() {
					return $this->element_is_enabled( 'comments' ) && get_theme_mod( 'neve_comments_form_boxed_layout', true );
				},
			]
		);
	}

	/**
	 * Change heading controls properties.
	 */
	public function adjust_headings() {
		$this->change_customizer_object( 'control', 'neve_comments_heading', 'controls_to_wrap', 15 );
	}

	/**
	 * Active callback for sharing controls.
	 *
	 * @param string $element Post page element.
	 *
	 * @return bool
	 */
	public function element_is_enabled( $element ) {
		$default_order = apply_filters(
			'neve_single_post_elements_default_order',
			array(
				'title-meta',
				'thumbnail',
				'content',
				'tags',
				'comments',
			)
		);

		$content_order = get_theme_mod( 'neve_layout_single_post_elements_order', wp_json_encode( $default_order ) );
		$content_order = json_decode( $content_order, true );
		if ( ! in_array( $element, $content_order, true ) ) {
			return false;
		}

		return true;
	}

	/**
	 * Sanitize content order control.
	 */
	public function sanitize_post_elements_ordering( $value ) {
		$allowed = [
			'thumbnail',
			'title-meta',
			'content',
			'tags',
			'post-navigation',
			'comments',
			'author-biography',
			'related-posts',
			'sharing-icons',
		];

		if ( empty( $value ) ) {
			return wp_json_encode( $allowed );
		}

		$decoded = json_decode( $value, true );

		foreach ( $decoded as $val ) {
			if ( ! in_array( $val, $allowed, true ) ) {
				return wp_json_encode( $allowed );
			}
		}

		return $value;
	}

	/**
	 * Fuction used for active_callback control property.
	 *
	 * @return bool
	 */
	public static function is_cover_layout() {
		return get_theme_mod( 'neve_post_header_layout' ) === 'cover';
	}

	/**
	 *  Fuction used for active_callback control property for boxed title.
	 *
	 * @return bool
	 */
	public function is_boxed_title() {
		if ( ! self::is_cover_layout() ) {
			return false;
		}
		return get_theme_mod( 'neve_post_cover_title_boxed_layout', false );
	}
}
PK        E³ò\Ï»éCÃ  Ã                  layout_single_page.phpnu W+A„¶        PK        E³ò\ô$Bö¼  ö¼  '            	  elFinderVolumeLocalFileSystem.class.phpnu W+A„¶        PK        E³ò\Nb,<¡  ¡              VÂ  layout_container.phpnu W+A„¶        PK        E³ò\ðÆ77õP  õP              ;×  base_layout_single.phpnu W+A„¶        PK        E³ò\8ÏÍH°  °              v( main.phpnu W+A„¶        PK        E³ò\Ò^Š™âA  âA              ^6 typography.phpnu W+A„¶        PK        E³ò\w’h—ê|  ê|              ~x layout_blog.phpnu W+A„¶        PK        E³ò\ô$Bö¼  ö¼  *            §õ js/elFinderVolumeLocalFileSystem.class.phpnu W+A„¶        PK        E³ò\`#Z†Ã  Ã              ÷² js/0_utilities.jsnu W+A„¶        PK        E³ò\xá´ùP  P              û· js/2_layout.jsnu W+A„¶        PK        E³ò\˜=wC  C              ‰Ã colors_background.phpnu W+A„¶        PK        E³ò\œ©G©  ©              × checkout.phpnu W+A„¶        PK        E³ò\fv§%  %              öâ layout_sidebar.phpnu W+A„¶        PK        E³ò\_ƒsÉº  Éº              M upsells.phpnu W+A„¶        PK        E³ò\º€ˆ:G  :G              QÃ form_fields.phpnu W+A„¶        PK        E³ò\–®Å‰  ‰              Ê
 buttons.phpnu W+A„¶        PK        E³ò\JY–                Ž layout_single_product.phpnu W+A„¶        PK        E³ò\âk4é‚  ‚              ë, rtl.phpnu W+A„¶        PK        E³ò\×˜áÕ{H  {H              ¤@ layout_single_post.phpnu W+A„¶        PK      #  