Merge branch 'dev' of https://github.com/redmatrix/hubzilla into dev_merge

This commit is contained in:
redmatrix 2016-04-23 16:57:32 -07:00
commit ce45a1cf94
39 changed files with 1923 additions and 1614 deletions

View File

@ -47,7 +47,7 @@ require_once('include/account.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'RED_VERSION', trim(file_get_contents('version.inc')));
define ( 'STD_VERSION', '1.4.2' );
define ( 'STD_VERSION', '1.4.3' );
define ( 'ZOT_REVISION', 1 );
define ( 'DB_UPDATE_VERSION', 1166 );

View File

@ -143,19 +143,17 @@ EOT;
if((App::$module != 'home') && (! (local_channel())))
$nav['home'] = array($homelink, t('Home'), "", t('Home Page'),'home_nav_btn');
if((App::$config['system']['register_policy'] == REGISTER_OPEN) && (! local_channel()) && (! remote_channel()))
$nav['register'] = array('register',t('Register'), "", t('Create an account'),'register_nav_btn');
$help_url = z_root() . '/help?f=&cmd=' . App::$cmd;
if(! get_config('system','hide_help')) {
$help_url = z_root() . '/help?f=&cmd=' . App::$cmd;
$context_help = '';
$enable_context_help = ((intval(get_config('system','enable_context_help')) === 1 || get_config('system','enable_context_help') === false) ? true : false);
if($enable_context_help === true) {
require_once('include/help.php');
$context_help = load_context_help();
//direct directly to /help if $context_help is empty - this can be removed once we have context help for all modules
//point directly to /help if $context_help is empty - this can be removed once we have context help for all modules
$enable_context_help = (($context_help) ? true : false);
}
$nav['help'] = array($help_url, t('Help'), "", t('Help and documentation'), 'help_nav_btn', $context_help, $enable_context_help);
@ -166,7 +164,6 @@ EOT;
$nav['search'] = array('search', t('Search'), "", t('Search site @name, #tag, ?docs, content'));
$nav['directory'] = array('directory', t('Directory'), "", t('Channel Directory'),'directory_nav_btn');
@ -240,16 +237,10 @@ $powered_by = '';
// $powered_by = '<strong>red<img class="smiley" src="' . z_root() . '/images/rm-16.png" alt="r#" />matrix</strong>';
$tpl = get_markup_template('nav_header.tpl');
App::$page['htmlhead'] .= replace_macros($tpl, array(
'$enable_context_help' => $enable_context_help
));
$tpl = get_markup_template('nav.tpl');
App::$page['nav'] .= replace_macros($tpl, array(
'$baseurl' => z_root(),
'$baseurl' => z_root(),
'$sitelocation' => $sitelocation,
'$nav' => $x['nav'],
'$banner' => $banner,
@ -260,7 +251,7 @@ $powered_by = '';
'$powered_by' => $powered_by,
'$help' => t('@name, #tag, ?doc, content'),
'$pleasewait' => t('Please wait...')
));
));
call_hooks('page_header', App::$page['nav']);
}

View File

@ -21,17 +21,17 @@ Smarty 3.1.28
fetch() and display()
=====================
The fetch() and display() methods of the template object accept now optionally the same parameter
as the corresponding Smarty methods to get tne content of another template.
as the corresponding Smarty methods to get the content of another template.
Example:
$template->display(); Does display template of template object
$template->dispaly('foo.tpl'); Does display template 'foo.bar'
$template->display('foo.tpl'); Does display template 'foo.bar'
File: resource
==============
Multiple template_dir entries can now be selected by a comma separated list of indices.
The template_dir array is searched in the order of the indices. (Could be used to change the default search order)
Example:
$smarty->display([1],[0]foo.bar');
$smarty->display('[1],[0]foo.bar');
Filter support
==============
@ -130,4 +130,4 @@ Smarty 3.1.22
Smarty::DEBUG_INDIVIDUAL will create for each display() and fetch() call an individual debug window.
.

View File

@ -1,14 +1,50 @@
 ===== 3.1.28 ===== (13.12.2015)
 ===== 3.1.29 ===== (21.12.2015)
21.12.2015
- optimization improve speed of filetime checks on extends and extendsall resource
20.12.2015
- bugfix failure when the default resource type was set to 'extendsall' https://github.com/smarty-php/smarty/issues/123
- update compilation of Smarty special variables
- bugfix add addition check for OS type on normalizaition of file path https://github.com/smarty-php/smarty/issues/134
- bugfix the source uid of the extendsall resource must contain $template_dir settings https://github.com/smarty-php/smarty/issues/123
19.12.2015
- bugfix using $smarty.capture.foo in expressions could fail https://github.com/smarty-php/smarty/pull/138
- bugfix broken PHP 5.2 compatibility https://github.com/smarty-php/smarty/issues/139
- remove no longer used code
- improvement make sure that compiled and cache templates never can contain a trailing '?>?
18.12.2015
- bugfix regression when modifier parameter was follow by math https://github.com/smarty-php/smarty/issues/132
17.12.2015
- bugfix {$smarty.capture.nameFail} did lowercase capture name https://github.com/smarty-php/smarty/issues/135
- bugfix using {block append/prepend} on same block in multiple levels of inheritance templates could fail (forum topic 25827)
- bugfix text content consisting of just a single '0' like in {if true}0{/if} was suppressed (forum topic 25834)
16.12.2015
- bugfix {foreach} did fail if from atrribute is a Generator class https://github.com/smarty-php/smarty/issues/128
- bugfix direct access $smarty->template_dir = 'foo'; should call Smarty::setTemplateDir() https://github.com/smarty-php/smarty/issues/121
15.12.2015
- bugfix {$smarty.cookies.foo} did return the $_COOKIE array not the 'foo' value https://github.com/smarty-php/smarty/issues/122
- bugfix a call to clearAllCache() and other should clear all internal template object caches (forum topic 25828)
14.12.2015
- bugfix {$smarty.config.foo} broken in 3.1.28 https://github.com/smarty-php/smarty/issues/120
- bugfix multiple calls of {section} with same name droped E_NOTICE error https://github.com/smarty-php/smarty/issues/118
===== 3.1.28 ===== (13.12.2015)
13.12.2015
- bugfix {foreach} and {section} with uppercase characters in name attribute did not work (forum topic 25819)
- bugfix $smarty->debugging_ctrl = 'URL' did not work (forum topic 25811)
- bugfix Debug Console could display incorrect data when using subtemplates
09.12.2015
- bugix Smarty did fail under PHP 7.0.0 with use_include_path = true;
- bugfix Smarty did fail under PHP 7.0.0 with use_include_path = true;
09.12.2015
-bugfix {strip} should exclude some html tags from stripping, related to fix for https://github.com/smarty-php/smarty/issues/111
- bugfix {strip} should exclude some html tags from stripping, related to fix for https://github.com/smarty-php/smarty/issues/111
08.12.2015
- bugfix internal template function data got stored in wrong compiled file https://github.com/smarty-php/smarty/issues/114

View File

@ -27,7 +27,7 @@
* @author Uwe Tews
* @author Rodney Rehm
* @package Smarty
* @version 3.1.28
* @version 3.1.29
*/
/**
@ -118,7 +118,7 @@ class Smarty extends Smarty_Internal_TemplateBase
/**
* smarty version
*/
const SMARTY_VERSION = '3.1.28';
const SMARTY_VERSION = '3.1.29';
/**
* define variable scopes
@ -677,15 +677,20 @@ class Smarty extends Smarty_Internal_TemplateBase
/**
* removed properties
*
* @var array
* @var string[]
*/
private static $obsoleteProperties = array('resource_caching', 'template_resource_caching',
'direct_access_security', '_dir_perms', '_file_perms',
'plugin_search_order', 'inheritance_merge_compiled_includes');
private static $accessMap = array('template_dir' => 'getTemplateDir', 'config_dir' => 'getConfigDir',
'plugins_dir' => 'getPluginsDir', 'compile_dir' => 'getCompileDir',
'cache_dir' => 'getCacheDir',);
/**
* List of private properties which will call getter/setter ona direct access
*
* @var array
*/
private static $accessMap = array('template_dir' => 'TemplateDir', 'config_dir' => 'ConfigDir',
'plugins_dir' => 'PluginsDir', 'compile_dir' => 'CompileDir',
'cache_dir' => 'CacheDir',);
/**#@-*/
@ -1173,7 +1178,7 @@ class Smarty extends Smarty_Internal_TemplateBase
$path = str_replace($nds, DS, $path);
}
if ($realpath === true && $path[0] !== '/' && $path[1] !== ':') {
if ($realpath === true && (($path[0] !== '/' && DS == '/') || ($path[1] !== ':' && DS != '/'))) {
$path = getcwd() . DS . $path;
}
while ((strpos($path, '.' . DS) !== false) || (strpos($path, DS . DS) !== false)) {
@ -1344,7 +1349,8 @@ class Smarty extends Smarty_Internal_TemplateBase
{
if (isset(self::$accessMap[$name])) {
return $this->{self::$accessMap[$name]}();
$method = 'get' . self::$accessMap[$name];
return $this->{$method}();
} elseif (in_array($name, self::$obsoleteProperties)) {
return null;
} else {
@ -1363,7 +1369,8 @@ class Smarty extends Smarty_Internal_TemplateBase
public function __set($name, $value)
{
if (isset(self::$accessMap[$name])) {
$this->{self::$accessMap[$name]}($value);
$method = 'set' . self::$accessMap[$name];
$this->{$method}($value);
} elseif (in_array($name, self::$obsoleteProperties)) {
return;
} else {

View File

@ -215,12 +215,9 @@ abstract class Smarty_CacheResource
*/
public function invalidLoadedCache(Smarty $smarty)
{
if (isset($smarty->_cache['template_objects'])) {
foreach ($smarty->_cache['template_objects'] as $key => $tpl) {
if (isset($tpl->cached)) {
unset ($smarty->_cache['template_objects'][$key]);
}
}
$smarty->_cache['isCached'] = array();
if (isset($smarty->ext->_subtemplate)) {
$smarty->ext->_subtemplate->tplObjects = array();
}
}
}

View File

@ -142,7 +142,7 @@ class Smarty_Internal_Compile_Block extends Smarty_Internal_Compile_Shared_Inher
}
$compiler->suppressNocacheProcessing = true;
$compiler->has_code = true;
$output = "<?php \n\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 3, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, null, \$_blockParentStack);\n?>\n";
$output = "<?php \n\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 4, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, null, \$_blockParentStack);\n?>\n";
return $output;
}
}

View File

@ -69,13 +69,12 @@ class Smarty_Internal_Compile_Capture extends Smarty_Internal_CompileBase
*/
public static function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
// make all lower case
$parameter = array_map('strtolower', $parameter);
$tag = trim($parameter[0], '"\'');
if (!isset($parameter[1]) || false === $name = $compiler->getId($parameter[1])) {
$tag = strtolower(trim($parameter[ 0 ], '"\''));
$name = isset($parameter[ 1 ]) ? $compiler->getId($parameter[ 1 ]) : false;
if (!$name) {
$compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", null, true);
}
return "isset(\$_smarty_tpl->_cache['__smarty_capture']['{$name}']) ? \$_smarty_tpl->_cache['__smarty_capture']['{$name}'] : null";
return "(isset(\$_smarty_tpl->_cache['__smarty_capture']['{$name}']) ? \$_smarty_tpl->_cache['__smarty_capture']['{$name}'] : null)";
}
}

View File

@ -59,7 +59,7 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_Compile_Private_Fo
*
* @var array
*/
public static $nameProperties = array('first', 'last', 'index', 'iteration', 'show', 'total');
public $nameProperties = array('first', 'last', 'index', 'iteration', 'show', 'total');
/**
* Valid properties of $item@xxx variable
@ -183,8 +183,10 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_Compile_Private_Fo
foreach ($saveVars as $k => $code) {
$output .= "{$local}{$k} = {$code}\n";
}
if (isset($itemAttr['show']) || isset($itemAttr['total']) || isset($namedAttr['total']) || isset($namedAttr['show']) || isset($itemAttr['last']) || isset($namedAttr['last'])) {
$output .= "{$local}total = \$_smarty_tpl->smarty->ext->_foreach->count(\$_from);\n";
}
$output .= "{$itemVar} = new Smarty_Variable();\n";
$output .= "{$local}total = \$_smarty_tpl->smarty->ext->_foreach->count(\$_from);\n";
if (isset($itemAttr['show'])) {
$output .= "{$itemVar}->show = ({$local}total > 0);\n";
}
@ -210,7 +212,6 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_Compile_Private_Fo
$output .= "{$foreachVar} = new Smarty_Variable({$_vars});\n";
}
}
$output .= "if ({$local}total) {\n";
if (isset($attributes['key'])) {
$output .= "\$_smarty_tpl->tpl_vars['{$key}'] = new Smarty_Variable();\n";
}
@ -226,7 +227,9 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_Compile_Private_Fo
if ($needIteration) {
$output .= "{$local}iteration=0;\n";
}
$output .= "{$itemVar}->_loop = false;\n";
$output .= "foreach (\$_from as {$keyTerm}{$itemVar}->value) {\n";
$output .= "{$itemVar}->_loop = true;\n";
if (isset($attributes['key']) && isset($itemAttr['key'])) {
$output .= "\$_smarty_tpl->tpl_vars['{$key}']->value = {$itemVar}->key;\n";
}
@ -296,7 +299,7 @@ class Smarty_Internal_Compile_Foreachelse extends Smarty_Internal_CompileBase
$output = "<?php\n";
$output .= "{$itemVar} = {$local}saved_local_item;\n";
$output .= "}\n";
$output .= "} else {\n?>";
$output .= "if (!{$itemVar}->_loop) {\n?>";
return $output;
}
}
@ -332,7 +335,6 @@ class Smarty_Internal_Compile_Foreachclose extends Smarty_Internal_CompileBase
if ($restore) {
$output .= "{$itemVar} = {$local}saved_local_item;\n";
$output .= "}\n";
}
$output .= "}\n";
foreach ($restoreVars as $restore) {

View File

@ -50,7 +50,7 @@ class Smarty_Internal_Compile_Private_ForeachSection extends Smarty_Internal_Com
*
* @var array
*/
public static $nameProperties = array();
public $nameProperties = array();
/**
* {section} tag has no item properties
@ -112,8 +112,7 @@ class Smarty_Internal_Compile_Private_ForeachSection extends Smarty_Internal_Com
if ($named) {
$this->resultOffsets['named'] = $this->startOffset + 3;
$this->propertyPreg .= "([\$]smarty[.]{$this->tagName}[.]{$attributes['name']}[.](";
$className = get_class($this);
$properties = $className::$nameProperties;
$properties = $this->nameProperties;
} else {
$this->resultOffsets['item'] = $this->startOffset + 3;
$this->propertyPreg .= "([\$]{$attributes['item']}[@](";
@ -204,17 +203,15 @@ class Smarty_Internal_Compile_Private_ForeachSection extends Smarty_Internal_Com
* @return string compiled code
* @throws \SmartyCompilerException
*/
public static function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
public function compileSpecialVariable($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
$tag = strtolower(trim($parameter[ 0 ], '"\''));
$name = isset($parameter[ 1 ]) ? $compiler->getId($parameter[ 1 ]) : false;
if (!$name) {
$compiler->trigger_template_error("missing or illegal \$smarty.{$tag} name attribute", null, true);
}
/* @var Smarty_Internal_Compile_Foreach|Smarty_Internal_Compile_Section $className */
$className = 'Smarty_Internal_Compile_' . ucfirst($tag);
$property = isset($parameter[ 2 ]) ? strtolower($compiler->getId($parameter[ 2 ])) : false;
if (!$property || !in_array($property, $className::$nameProperties)) {
if (!$property || !in_array($property, $this->nameProperties)) {
$compiler->trigger_template_error("missing or illegal \$smarty.{$tag} property attribute", null, true);
}
$tagVar = "'__smarty_{$tag}_{$name}'";

View File

@ -29,7 +29,7 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
$_index = preg_split("/\]\[/", substr($parameter, 1, strlen($parameter) - 2));
$variable = strtolower($compiler->getId($_index[0]));
$variable = strtolower($compiler->getId($_index[ 0 ]));
if ($variable === false) {
$compiler->trigger_template_error("special \$Smarty variable name index can not be variable", null, true);
}
@ -39,7 +39,11 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C
switch ($variable) {
case 'foreach':
case 'section':
return Smarty_Internal_Compile_Private_ForeachSection::compileSpecialVariable(array(), $compiler, $_index);
if (!isset($compiler->_tag_objects[ $variable ])) {
$class = 'Smarty_Internal_Compile_' . ucfirst($variable);
$compiler->_tag_objects[ $variable ] = new $class;
}
return $compiler->_tag_objects[ $variable ]->compileSpecialVariable(array(), $compiler, $_index);
case 'capture':
if (class_exists('Smarty_Internal_Compile_Capture')) {
return Smarty_Internal_Compile_Capture::compileSpecialVariable(array(), $compiler, $_index);
@ -54,7 +58,8 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C
$compiler->trigger_template_error("(secure mode) super globals not permitted");
break;
}
return '$_COOKIE';
$compiled_ref = '$_COOKIE';
break;
case 'get':
case 'post':
case 'env':
@ -80,9 +85,7 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C
return 'dirname($_smarty_tpl->source->filepath)';
case 'version':
$_version = Smarty::SMARTY_VERSION;
return "'$_version'";
return "Smarty::SMARTY_VERSION";
case 'const':
if (isset($compiler->smarty->security_policy) &&
@ -91,33 +94,27 @@ class Smarty_Internal_Compile_Private_Special_Variable extends Smarty_Internal_C
$compiler->trigger_template_error("(secure mode) constants not permitted");
break;
}
if (strpos($_index[1], '$') === false && strpos($_index[1], '\'') === false) {
if (strpos($_index[ 1 ], '$') === false && strpos($_index[ 1 ], '\'') === false) {
return "@constant('{$_index[1]}')";
} else {
return "@constant({$_index[1]})";
}
case 'config':
if (isset($_index[2])) {
return "(is_array(\$tmp = \$_smarty_tpl->smarty->ext->_config->_getConfigVariable(\$_smarty_tpl, $_index[1])) ? \$tmp[$_index[2]] : null)";
if (isset($_index[ 2 ])) {
return "(is_array(\$tmp = \$_smarty_tpl->smarty->ext->configload->_getConfigVariable(\$_smarty_tpl, $_index[1])) ? \$tmp[$_index[2]] : null)";
} else {
return "\$_smarty_tpl->smarty->ext->_config->_getConfigVariable(\$_smarty_tpl, $_index[1])";
return "\$_smarty_tpl->smarty->ext->configload->_getConfigVariable(\$_smarty_tpl, $_index[1])";
}
case 'ldelim':
$_ldelim = $compiler->smarty->left_delimiter;
return "'$_ldelim'";
return "\$_smarty_tpl->smarty->left_delimiter";
case 'rdelim':
$_rdelim = $compiler->smarty->right_delimiter;
return "'$_rdelim'";
return "\$_smarty_tpl->smarty->right_delimiter";
default:
$compiler->trigger_template_error('$smarty.' . trim($_index[0], "'") . ' is invalid');
$compiler->trigger_template_error('$smarty.' . trim($_index[ 0 ], "'") . ' is not defined');
break;
}
if (isset($_index[1])) {
if (isset($_index[ 1 ])) {
array_shift($_index);
foreach ($_index as $_ind) {
$compiled_ref = $compiled_ref . "[$_ind]";

View File

@ -59,7 +59,7 @@ class Smarty_Internal_Compile_Section extends Smarty_Internal_Compile_Private_Fo
*
* @var array
*/
public static $nameProperties = array('first', 'last', 'index', 'iteration', 'show', 'total', 'rownum',
public $nameProperties = array('first', 'last', 'index', 'iteration', 'show', 'total', 'rownum',
'index_prev', 'index_next');
/**
@ -103,7 +103,7 @@ class Smarty_Internal_Compile_Section extends Smarty_Internal_Compile_Private_Fo
// maybe nocache because of nocache variables
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
$initLocal = array('saved' => "isset(\$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}']) ? \$_smarty_tpl->tpl_vars['__section_{$attributes['name']}'] : false",);
$initLocal = array('saved' => "isset(\$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}']) ? \$_smarty_tpl->tpl_vars['__smarty_section_{$attributes['name']}'] : false",);
$initNamedProperty = array();
$initFor = array();
$incFor = array();

View File

@ -187,6 +187,21 @@ class Smarty_Internal_Data
return $this->ext->getTemplateVars->getTemplateVars($this, $varName, $_ptr, $searchParents);
}
/**
* gets the object of a Smarty variable
*
* @param string $variable the name of the Smarty variable
* @param Smarty_Internal_Data $_ptr optional pointer to data object
* @param boolean $searchParents search also in parent data
* @param bool $error_enable
*
* @return Smarty_Variable|Smarty_Undefined_Variable the object of the variable
* @deprecated since 3.1.28 please use Smarty_Internal_Data::getTemplateVars() instead.
*/
public function getVariable($variable = null, Smarty_Internal_Data $_ptr = null, $searchParents = true, $error_enable = true){
return $this->ext->getTemplateVars->_getVariable($this, $variable, $_ptr, $searchParents, $error_enable);
}
/**
* Follow the parent chain an merge template and config variables
*

View File

@ -114,14 +114,6 @@ class Smarty_Internal_Extension_Clear
}
}
}
// remove from template cache
if (isset($smarty->_cache['template_objects'])) {
foreach ($smarty->_cache['template_objects'] as $key => $tpl) {
if (isset($tpl->cached) && $tpl->cached->filepath == (string) $_file) {
unset($smarty->_cache['template_objects'][$key]);
}
}
}
$_count += @unlink((string) $_file) ? 1 : 0;
if (function_exists('opcache_invalidate')) {
opcache_invalidate((string) $_file);

View File

@ -34,10 +34,7 @@ class Smarty_Internal_Method_ClearAllCache
{
// load cache resource and call clearAll
$_cache_resource = Smarty_CacheResource::load($smarty, $type);
if ($smarty->caching_type != 'file') {
$_cache_resource->invalidLoadedCache($smarty);
}
$_cache_resource->invalidLoadedCache($smarty);
return $_cache_resource->clearAll($smarty, $exp_time);
}
}

View File

@ -37,10 +37,7 @@ class Smarty_Internal_Method_ClearCache
{
// load cache resource and call clear
$_cache_resource = Smarty_CacheResource::load($smarty, $type);
if ($smarty->caching_type != 'file' && !isset($template_name)) {
$_cache_resource->invalidLoadedCache($smarty);
}
$_cache_resource->invalidLoadedCache($smarty);
return $_cache_resource->clear($smarty, $template_name, $cache_id, $compile_id, $exp_time);
}
}

View File

@ -107,13 +107,6 @@ class Smarty_Internal_Method_ClearCompiledTemplate
}
if ($unlink && @unlink($_filepath)) {
if (isset($smarty->_cache['template_objects'])) {
foreach ($smarty->_cache['template_objects'] as $key => $tpl) {
if (isset($tpl->compiled) && $tpl->compiled->filepath == $_filepath) {
unset($smarty->_cache['template_objects'][$key]);
}
}
}
$_count ++;
if (function_exists('opcache_invalidate')) {
opcache_invalidate($_filepath);
@ -121,11 +114,10 @@ class Smarty_Internal_Method_ClearCompiledTemplate
}
}
}
// clear compiled cache
if (!isset($resource_name) && isset($smarty->_cache['source_objects'])) {
foreach ($smarty->_cache['source_objects'] as $source) {
$source->compileds = array();
}
// clear template objects cache
$smarty->_cache['isCached'] = array();
if (isset($smarty->ext->_subtemplate)) {
$smarty->ext->_subtemplate->tplObjects = array();
}
return $_count;
}

View File

@ -162,7 +162,7 @@ class Smarty_Internal_Method_ConfigLoad
*
* @return mixed the value of the config variable
*/
public function _getConfigVariable(\Smarty_Internal_Template $tpl, $varName, $errorEnable = true)
public function _getConfigVariable(Smarty_Internal_Template $tpl, $varName, $errorEnable = true)
{
$_ptr = $tpl;
while ($_ptr !== null) {

View File

@ -44,7 +44,7 @@ class Smarty_Internal_Resource_Extends extends Smarty_Resource
if ($_s->type == 'php') {
throw new SmartyException("Resource type {$_s->type} cannot be used with the extends resource type");
}
$sources[$_s->uid] = $_s;
$sources[ $_s->uid ] = $_s;
$uid .= $_s->filepath;
if ($_template) {
$exists = $exists && $_s->exists;
@ -110,4 +110,15 @@ class Smarty_Internal_Resource_Extends extends Smarty_Resource
{
return str_replace(':', '.', basename($source->filepath));
}
/*
* Disable timestamp checks for extends resource.
* The individual source components will be checked.
*
* @return bool
*/
public function checkTimestamps()
{
return false;
}
}

View File

@ -89,6 +89,6 @@ class Smarty_Internal_Runtime_CodeFrame
$output .= $functions;
$output .= "<?php }\n";
// remove unneeded PHP tags
return preg_replace('/\s*\?>[\n]?<\?php\s*/', "\n", $output);
return preg_replace(array('/\s*\?>[\n]?<\?php\s*/', '/\?>\s*$/'), array("\n", ''), $output);
}
}

View File

@ -27,6 +27,9 @@ class Smarty_Internal_Runtime_Foreach
// thus rewind() and valid() methods may not be present
return iterator_count($value->getIterator());
} elseif ($value instanceof Iterator) {
if ($value instanceof Generator) {
return 1;
}
return iterator_count($value);
} elseif ($value instanceof PDOStatement) {
return $value->rowCount();

View File

@ -127,8 +127,11 @@ class Smarty_Internal_Runtime_Inheritance
* - search in inheritance template hierarchy for child blocks
* if found call it, otherwise ignore
*
* $type 3 = {$smarty.block.parent}:
* - get block id from parent stack and call parent block
* $type 3 = {block append} {block prepend}:
* - call parent block
*
* $type 4 = {$smarty.block.parent}:
* - call parent block
*
* @param \Smarty_Internal_Template $tpl template object of caller
* @param int $type call type see above
@ -140,16 +143,22 @@ class Smarty_Internal_Runtime_Inheritance
*/
public function processBlock(Smarty_Internal_Template $tpl, $type = 0, $name, $block, $callStack = array())
{
if (!isset($this->blockParameter[$name])) {
$this->blockParameter[$name] = array();
if (!isset($this->blockParameter[ $name ])) {
$this->blockParameter[ $name ] = array();
}
if ($this->state == 1) {
$block[2] = count($this->blockParameter[$name]);
$block[3] = $this->tplIndex;
$this->blockParameter[$name][] = $block;
$block[ 2 ] = count($this->blockParameter[ $name ]);
$block[ 3 ] = $this->tplIndex;
$this->blockParameter[ $name ][] = $block;
return;
}
if ($type == 3) {
if (!empty($callStack)) {
$block = array_shift($callStack);
} else {
return;
}
} elseif ($type == 4) {
if (!empty($callStack)) {
array_shift($callStack);
if (empty($callStack)) {
@ -160,23 +169,23 @@ class Smarty_Internal_Runtime_Inheritance
return;
}
} else {
$blockParameter = &$this->blockParameter[$name];
$index = 0;
$blockParameter = &$this->blockParameter[ $name ];
if ($type == 0) {
$index = $block[2] = count($blockParameter);
$block[3] = $this->tplIndex;
$index = $block[ 2 ] = count($blockParameter);
$block[ 3 ] = $this->tplIndex;
$callStack = array(&$block);
} elseif ($type == 1) {
$block[3] = $callStack[0][3];
$index = 0;
$block[ 3 ] = $callStack[ 0 ][ 3 ];
for ($i = 0; $i < count($blockParameter); $i ++) {
if ($blockParameter[$i][3] <= $block[3]) {
$index = $blockParameter[$i][2];
if ($blockParameter[ $i ][ 3 ] <= $block[ 3 ]) {
$index = $blockParameter[ $i ][ 2 ];
}
}
$block[2] = $index;
$block[ 2 ] = $index;
$callStack = array(&$block);
} else {
$index = $callStack[0][2];
} elseif ($type == 2) {
$index = $callStack[ 0 ][ 2 ];
if ($index == 0) {
return;
}
@ -184,29 +193,40 @@ class Smarty_Internal_Runtime_Inheritance
}
$index --;
// find lowest level child block
while ($index >= 0 && ($type || !$block[1])) {
$block = &$blockParameter[$index];
while ($index >= 0 && ($type || !$block[ 1 ])) {
$block = &$blockParameter[ $index ];
array_unshift($callStack, $block);
if ($block[1]) {
if ($block[ 1 ]) {
break;
}
$index --;
}
if (isset($block['hide']) && $index <= 0) {
if (isset($block[ 'hide' ]) && $index <= 0) {
return;
}
}
$this->blockNesting ++;
if (isset($block['append'])) {
$this->processBlock($tpl, 3, $name, null, $callStack);
// {block append} ?
if (isset($block[ 'append' ])) {
$appendStack = $callStack;
if ($type == 0) {
array_shift($appendStack);
}
$this->processBlock($tpl, 3, $name, null, $appendStack);
}
// call block of current stack level
if (isset($block[6])) {
$block[6]($tpl, $callStack);
} else {
$block[0]($tpl, $callStack);
}
if (isset($block['prepend'])) {
$this->processBlock($tpl, 3, $name, null, $callStack);
// {block prepend} ?
if (isset($block[ 'prepend' ])) {
$prependStack = $callStack;
if ($type == 0) {
array_shift($prependStack);
}
$this->processBlock($tpl, 3, $name, null, $prependStack);
}
$this->blockNesting --;
}

View File

@ -20,7 +20,7 @@ class Smarty_Internal_Runtime_TplFunction
*
* @throws \SmartyException
*/
public function callTemplateFunction(\Smarty_Internal_Template $tpl, $name, $params, $nocache)
public function callTemplateFunction(Smarty_Internal_Template $tpl, $name, $params, $nocache)
{
if (isset($tpl->tpl_function[$name])) {
if (!$tpl->caching || ($tpl->caching && $nocache)) {

View File

@ -73,7 +73,7 @@ class Smarty_Internal_Runtime_UpdateCache
/**
* Cache was invalid , so render from compiled and write to cache
*
*
* @param \Smarty_Template_Cached $cached
* @param \Smarty_Internal_Template $_template
* @param $no_output_filter
@ -129,20 +129,6 @@ class Smarty_Internal_Runtime_UpdateCache
return false;
}
$content = $_template->smarty->ext->_codeFrame->create($_template, $content, '', true);
if (!empty($_template->cached->tpl_function)) {
foreach ($_template->cached->tpl_function as $funcParam) {
if (is_file($funcParam['compiled_filepath'])) {
// read compiled file
$code = file_get_contents($funcParam['compiled_filepath']);
// grab template function
if (preg_match("/\/\* {$funcParam['call_name']} \*\/([\S\s]*?)\/\*\/ {$funcParam['call_name']} \*\//",
$code, $match)) {
unset($code);
$content .= "<?php " . $match[0] . "?>\n";
}
}
}
}
return $this->write($cached, $_template, $content);
}

View File

@ -17,7 +17,7 @@ class Smarty_Internal_Runtime_UpdateScope
* @param string $varName variable name
* @param int $scope scope to which bubble up variable value
*/
public function updateScope(\Smarty_Internal_Template $tpl, $varName, $scope = Smarty::SCOPE_LOCAL)
public function updateScope(Smarty_Internal_Template $tpl, $varName, $scope = Smarty::SCOPE_LOCAL)
{
if (!$scope && !$tpl->scope) {
return;

View File

@ -43,8 +43,13 @@ class Smarty_Internal_Runtime_ValidateCompiled
} elseif ($_file_to_check[2] == 'string') {
continue;
} else {
$source = Smarty_Template_Source::load(null, $tpl->smarty, $_file_to_check[0]);
$mtime = $source->getTimeStamp();
$handler = Smarty_Resource::load($tpl->smarty, $_file_to_check[2]);
if ($handler->checkTimestamps()) {
$source = Smarty_Template_Source::load($tpl, $tpl->smarty, $_file_to_check[ 0 ]);
$mtime = $source->getTimeStamp();
} else {
continue;
}
}
if (!$mtime || $mtime > $_file_to_check[1]) {
$is_valid = false;

View File

@ -17,7 +17,7 @@ class Smarty_Internal_Runtime_Var
* @param string $varName template variable name
* @param bool $nocache cache mode of variable
*/
public function createLocalArrayVariable(\Smarty_Internal_Template $tpl, $varName, $nocache = false)
public function createLocalArrayVariable(Smarty_Internal_Template $tpl, $varName, $nocache = false)
{
if (!isset($tpl->tpl_vars[$varName])) {
$tpl->tpl_vars[$varName] = new Smarty_Variable(array(), $nocache);

View File

@ -328,7 +328,8 @@ abstract class Smarty_Internal_TemplateCompilerBase
$this->compileTemplateSource($template, $nocache,
$parent_compiler),
$this->postFilter($this->blockOrFunctionCode) .
join('', $this->mergedSubTemplatesCode), false, $this);
join('', $this->mergedSubTemplatesCode), false,
$this);
return $_compiled_code;
}
@ -374,7 +375,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
$this->has_variable_string = false;
$this->prefix_code = array();
// add file dependency
$this->parent_compiler->template->compiled->file_dependency[$this->template->source->uid] =
$this->parent_compiler->template->compiled->file_dependency[ $this->template->source->uid ] =
array($this->template->source->filepath, $this->template->source->getTimeStamp(),
$this->template->source->type);
$this->smarty->_current_file = $this->template->source->filepath;
@ -423,7 +424,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
{
// run post filter if on code
if (!empty($code) &&
(isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post']))
(isset($this->smarty->autoload_filters[ 'post' ]) || isset($this->smarty->registered_filters[ 'post' ]))
) {
return $this->smarty->ext->_filterHandler->runFilter('post', $code, $this->template);
} else {
@ -443,7 +444,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
{
// run pre filter if required
if ($_content != '' &&
((isset($this->smarty->autoload_filters['pre']) || isset($this->smarty->registered_filters['pre'])))
((isset($this->smarty->autoload_filters[ 'pre' ]) || isset($this->smarty->registered_filters[ 'pre' ])))
) {
return $this->smarty->ext->_filterHandler->runFilter('pre', $_content, $this->template);
} else {
@ -496,8 +497,8 @@ abstract class Smarty_Internal_TemplateCompilerBase
$this->has_code = true;
$this->has_output = false;
// log tag/attributes
if (isset($this->smarty->_cache['get_used_tags'])) {
$this->template->_cache['used_tags'][] = array($tag, $args);
if (isset($this->smarty->_cache[ 'get_used_tags' ])) {
$this->template->_cache[ 'used_tags' ][] = array($tag, $args);
}
// check nocache option flag
if (in_array("'nocache'", $args) || in_array(array('nocache' => 'true'), $args) ||
@ -507,9 +508,9 @@ abstract class Smarty_Internal_TemplateCompilerBase
}
// compile the smarty tag (required compile classes to compile the tag are auto loaded)
if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) {
if (isset($this->parent_compiler->template->tpl_function[$tag])) {
if (isset($this->parent_compiler->template->tpl_function[ $tag ])) {
// template defined by {template} tag
$args['_attr']['name'] = "'" . $tag . "'";
$args[ '_attr' ][ 'name' ] = "'" . $tag . "'";
$_output = $this->callTagCompiler('call', $args, $parameter);
}
}
@ -529,8 +530,8 @@ abstract class Smarty_Internal_TemplateCompilerBase
return null;
} else {
// map_named attributes
if (isset($args['_attr'])) {
foreach ($args['_attr'] as $key => $attribute) {
if (isset($args[ '_attr' ])) {
foreach ($args[ '_attr' ] as $key => $attribute) {
if (is_array($attribute)) {
$args = array_merge($args, $attribute);
}
@ -539,14 +540,14 @@ abstract class Smarty_Internal_TemplateCompilerBase
// not an internal compiler tag
if (strlen($tag) < 6 || substr($tag, - 5) != 'close') {
// check if tag is a registered object
if (isset($this->smarty->registered_objects[$tag]) && isset($parameter['object_method'])) {
$method = $parameter['object_method'];
if (!in_array($method, $this->smarty->registered_objects[$tag][3]) &&
(empty($this->smarty->registered_objects[$tag][1]) ||
in_array($method, $this->smarty->registered_objects[$tag][1]))
if (isset($this->smarty->registered_objects[ $tag ]) && isset($parameter[ 'object_method' ])) {
$method = $parameter[ 'object_method' ];
if (!in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ]) &&
(empty($this->smarty->registered_objects[ $tag ][ 1 ]) ||
in_array($method, $this->smarty->registered_objects[ $tag ][ 1 ]))
) {
return $this->callTagCompiler('private_object_function', $args, $parameter, $tag, $method);
} elseif (in_array($method, $this->smarty->registered_objects[$tag][3])) {
} elseif (in_array($method, $this->smarty->registered_objects[ $tag ][ 3 ])) {
return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag,
$method);
} else {
@ -558,7 +559,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
// check if tag is registered
foreach (array(Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK) as $plugin_type)
{
if (isset($this->smarty->registered_plugins[$plugin_type][$tag])) {
if (isset($this->smarty->registered_plugins[ $plugin_type ][ $tag ])) {
// if compiler function plugin call it now
if ($plugin_type == Smarty::PLUGIN_COMPILER) {
$new_args = array();
@ -566,18 +567,18 @@ abstract class Smarty_Internal_TemplateCompilerBase
if (is_array($mixed)) {
$new_args = array_merge($new_args, $mixed);
} else {
$new_args[$key] = $mixed;
$new_args[ $key ] = $mixed;
}
}
if (!$this->smarty->registered_plugins[$plugin_type][$tag][1]) {
if (!$this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 1 ]) {
$this->tag_nocache = true;
}
$function = $this->smarty->registered_plugins[$plugin_type][$tag][0];
$function = $this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 0 ];
if (!is_array($function)) {
return $function($new_args, $this);
} elseif (is_object($function[0])) {
return $this->smarty->registered_plugins[$plugin_type][$tag][0][0]->{$function[1]}($new_args,
$this);
} elseif (is_object($function[ 0 ])) {
return $this->smarty->registered_plugins[ $plugin_type ][ $tag ][ 0 ][ 0 ]->{$function[ 1 ]}($new_args,
$this);
} else {
return call_user_func_array($function, array($new_args, $this));
}
@ -604,7 +605,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
if (is_array($mixed)) {
$new_args = array_merge($new_args, $mixed);
} else {
$new_args[$key] = $mixed;
$new_args[ $key ] = $mixed;
}
}
@ -632,7 +633,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
$found = false;
// look for already resolved tags
foreach ($this->plugin_search_order as $plugin_type) {
if (isset($this->default_handler_plugins[$plugin_type][$tag])) {
if (isset($this->default_handler_plugins[ $plugin_type ][ $tag ])) {
$found = true;
break;
}
@ -653,12 +654,12 @@ abstract class Smarty_Internal_TemplateCompilerBase
foreach ($args as $mixed) {
$new_args = array_merge($new_args, $mixed);
}
$function = $this->default_handler_plugins[$plugin_type][$tag][0];
$function = $this->default_handler_plugins[ $plugin_type ][ $tag ][ 0 ];
if (!is_array($function)) {
return $function($new_args, $this);
} elseif (is_object($function[0])) {
return $this->default_handler_plugins[$plugin_type][$tag][0][0]->$function[1]($new_args,
$this);
} elseif (is_object($function[ 0 ])) {
return $this->default_handler_plugins[ $plugin_type ][ $tag ][ 0 ][ 0 ]->$function[ 1 ]($new_args,
$this);
} else {
return call_user_func_array($function, array($new_args, $this));
}
@ -672,9 +673,9 @@ abstract class Smarty_Internal_TemplateCompilerBase
// compile closing tag of block function
$base_tag = substr($tag, 0, - 5);
// check if closing tag is a registered object
if (isset($this->smarty->registered_objects[$base_tag]) && isset($parameter['object_method'])) {
$method = $parameter['object_method'];
if (in_array($method, $this->smarty->registered_objects[$base_tag][3])) {
if (isset($this->smarty->registered_objects[ $base_tag ]) && isset($parameter[ 'object_method' ])) {
$method = $parameter[ 'object_method' ];
if (in_array($method, $this->smarty->registered_objects[ $base_tag ][ 3 ])) {
return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag,
$method);
} else {
@ -684,13 +685,13 @@ abstract class Smarty_Internal_TemplateCompilerBase
}
}
// registered block tag ?
if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag]) ||
isset($this->default_handler_plugins[Smarty::PLUGIN_BLOCK][$base_tag])
if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ]) ||
isset($this->default_handler_plugins[ Smarty::PLUGIN_BLOCK ][ $base_tag ])
) {
return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag);
}
// registered function tag ?
if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_FUNCTION][$tag])) {
if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_FUNCTION ][ $tag ])) {
return $this->callTagCompiler('private_registered_function', $args, $parameter, $tag);
}
// block plugin?
@ -706,18 +707,18 @@ abstract class Smarty_Internal_TemplateCompilerBase
}
}
// registered compiler plugin ?
if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag])) {
if (isset($this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ])) {
// if compiler function plugin call it now
$args = array();
if (!$this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][1]) {
if (!$this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 1 ]) {
$this->tag_nocache = true;
}
$function = $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0];
$function = $this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 0 ];
if (!is_array($function)) {
return $function($args, $this);
} elseif (is_object($function[0])) {
return $this->smarty->registered_plugins[Smarty::PLUGIN_COMPILER][$tag][0][0]->$function[1]($args,
$this);
} elseif (is_object($function[ 0 ])) {
return $this->smarty->registered_plugins[ Smarty::PLUGIN_COMPILER ][ $tag ][ 0 ][ 0 ]->$function[ 1 ]($args,
$this);
} else {
return call_user_func_array($function, array($args, $this));
}
@ -783,58 +784,57 @@ abstract class Smarty_Internal_TemplateCompilerBase
*/
public function processText($text)
{
$store = array();
$_store = 0;
$_offset = 0;
if ($this->parser->strip) {
if (strpos($text, '<') !== false) {
// capture html elements not to be messed with
$_offset = 0;
if (preg_match_all('#(<script[^>]*>.*?</script[^>]*>)|(<textarea[^>]*>.*?</textarea[^>]*>)|(<pre[^>]*>.*?</pre[^>]*>)#is',
$text, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
foreach ($matches as $match) {
$store[] = $match[ 0 ][ 0 ];
$_length = strlen($match[ 0 ][ 0 ]);
$replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
$text = substr_replace($text, $replace, $match[ 0 ][ 1 ] - $_offset, $_length);
if ((string) $text != '') {
$store = array();
$_store = 0;
$_offset = 0;
if ($this->parser->strip) {
if (strpos($text, '<') !== false) {
// capture html elements not to be messed with
$_offset = 0;
if (preg_match_all('#(<script[^>]*>.*?</script[^>]*>)|(<textarea[^>]*>.*?</textarea[^>]*>)|(<pre[^>]*>.*?</pre[^>]*>)#is',
$text, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
foreach ($matches as $match) {
$store[] = $match[ 0 ][ 0 ];
$_length = strlen($match[ 0 ][ 0 ]);
$replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
$text = substr_replace($text, $replace, $match[ 0 ][ 1 ] - $_offset, $_length);
$_offset += $_length - strlen($replace);
$_store ++;
$_offset += $_length - strlen($replace);
$_store ++;
}
}
}
$expressions = array(// replace multiple spaces between tags by a single space
// can't remove them entirely, becaue that might break poorly implemented CSS display:inline-block elements
'#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1 \2',
// remove spaces between attributes (but not in attribute values!)
'#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5',
'#^\s+<#Ss' => '<',
'#>\s+$#Ss' => '>',
$this->stripRegEx => ''
);
$expressions = array(// replace multiple spaces between tags by a single space
// can't remove them entirely, becaue that might break poorly implemented CSS display:inline-block elements
'#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1 \2',
// remove spaces between attributes (but not in attribute values!)
'#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5',
'#^\s+<#Ss' => '<',
'#>\s+$#Ss' => '>',
$this->stripRegEx => '');
$text = preg_replace(array_keys($expressions), array_values($expressions), $text);
$_offset = 0;
if (preg_match_all('#@!@SMARTY:([0-9]+):SMARTY@!@#is', $text, $matches,
PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
foreach ($matches as $match) {
$_length = strlen($match[ 0 ][ 0 ]);
$replace = $store[ $match[ 1 ][ 0 ] ];
$text = substr_replace($text, $replace, $match[ 0 ][ 1 ] + $_offset, $_length);
$text = preg_replace(array_keys($expressions), array_values($expressions), $text);
$_offset = 0;
if (preg_match_all('#@!@SMARTY:([0-9]+):SMARTY@!@#is', $text, $matches,
PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
foreach ($matches as $match) {
$_length = strlen($match[ 0 ][ 0 ]);
$replace = $store[ $match[ 1 ][ 0 ] ];
$text = substr_replace($text, $replace, $match[ 0 ][ 1 ] + $_offset, $_length);
$_offset += strlen($replace) - $_length;
$_store ++;
$_offset += strlen($replace) - $_length;
$_store ++;
}
}
} else {
$text = preg_replace($this->stripRegEx, '', $text);
}
} else {
$text = preg_replace($this->stripRegEx, '', $text);
}
}
if ($text) {
return new Smarty_Internal_ParseTree_Text($text);
}
return null;
}
}
/**
* lazy loads internal compile plugin for tag and calls the compile method
@ -853,7 +853,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null)
{
// re-use object if already exists
if (!isset($this->_tag_objects[$tag])) {
if (!isset($this->_tag_objects[ $tag ])) {
// lazy load internal compiler plugin
$_tag = explode('_', $tag);
$_tag = array_map('ucfirst', $_tag);
@ -861,15 +861,15 @@ abstract class Smarty_Internal_TemplateCompilerBase
if (class_exists($class_name) &&
(!isset($this->smarty->security_policy) || $this->smarty->security_policy->isTrustedTag($tag, $this))
) {
$this->_tag_objects[$tag] = new $class_name;
$this->_tag_objects[ $tag ] = new $class_name;
} else {
$this->_tag_objects[$tag] = false;
$this->_tag_objects[ $tag ] = false;
return false;
}
}
// compile this tag
return $this->_tag_objects[$tag] === false ? false :
$this->_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);
return $this->_tag_objects[ $tag ] === false ? false :
$this->_tag_objects[ $tag ]->compile($args, $this, $param1, $param2, $param3);
}
/**
@ -884,29 +884,29 @@ abstract class Smarty_Internal_TemplateCompilerBase
{
$function = null;
if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
if (isset($this->parent_compiler->template->compiled->required_plugins['nocache'][$plugin_name][$plugin_type])) {
if (isset($this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) {
$function =
$this->parent_compiler->template->compiled->required_plugins['nocache'][$plugin_name][$plugin_type]['function'];
} elseif (isset($this->parent_compiler->template->compiled->required_plugins['compiled'][$plugin_name][$plugin_type])) {
$this->parent_compiler->template->compiled->required_plugins['nocache'][$plugin_name][$plugin_type] =
$this->parent_compiler->template->compiled->required_plugins['compiled'][$plugin_name][$plugin_type];
$this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ];
} elseif (isset($this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) {
$this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ] =
$this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ];
$function =
$this->parent_compiler->template->compiled->required_plugins['nocache'][$plugin_name][$plugin_type]['function'];
$this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ];
}
} else {
if (isset($this->parent_compiler->template->compiled->required_plugins['compiled'][$plugin_name][$plugin_type])) {
if (isset($this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ])) {
$function =
$this->parent_compiler->template->compiled->required_plugins['compiled'][$plugin_name][$plugin_type]['function'];
} elseif (isset($this->parent_compiler->template->compiled->required_plugins['nocache'][$plugin_name][$plugin_type])) {
$this->parent_compiler->template->compiled->required_plugins['compiled'][$plugin_name][$plugin_type] =
$this->parent_compiler->template->compiled->required_plugins['nocache'][$plugin_name][$plugin_type];
$this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ];
} elseif (isset($this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ])) {
$this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ] =
$this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ];
$function =
$this->parent_compiler->template->compiled->required_plugins['compiled'][$plugin_name][$plugin_type]['function'];
$this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ];
}
}
if (isset($function)) {
if ($plugin_type == 'modifier') {
$this->modifier_plugins[$plugin_name] = true;
$this->modifier_plugins[ $plugin_name ] = true;
}
return $function;
@ -917,18 +917,18 @@ abstract class Smarty_Internal_TemplateCompilerBase
if (is_string($file)) {
if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
$this->parent_compiler->template->compiled->required_plugins['nocache'][$plugin_name][$plugin_type]['file'] =
$this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'file' ] =
$file;
$this->parent_compiler->template->compiled->required_plugins['nocache'][$plugin_name][$plugin_type]['function'] =
$this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ $plugin_type ][ 'function' ] =
$function;
} else {
$this->parent_compiler->template->compiled->required_plugins['compiled'][$plugin_name][$plugin_type]['file'] =
$this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'file' ] =
$file;
$this->parent_compiler->template->compiled->required_plugins['compiled'][$plugin_name][$plugin_type]['function'] =
$this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ $plugin_type ][ 'function' ] =
$function;
}
if ($plugin_type == 'modifier') {
$this->modifier_plugins[$plugin_name] = true;
$this->modifier_plugins[ $plugin_name ] = true;
}
return $function;
@ -961,14 +961,14 @@ abstract class Smarty_Internal_TemplateCompilerBase
if ($script !== null) {
if (is_file($script)) {
if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
$this->parent_compiler->template->compiled->required_plugins['nocache'][$tag][$plugin_type]['file'] =
$this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'file' ] =
$script;
$this->parent_compiler->template->compiled->required_plugins['nocache'][$tag][$plugin_type]['function'] =
$this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $tag ][ $plugin_type ][ 'function' ] =
$callback;
} else {
$this->parent_compiler->template->compiled->required_plugins['compiled'][$tag][$plugin_type]['file'] =
$this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'file' ] =
$script;
$this->parent_compiler->template->compiled->required_plugins['compiled'][$tag][$plugin_type]['function'] =
$this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $tag ][ $plugin_type ][ 'function' ] =
$callback;
}
require_once $script;
@ -976,11 +976,13 @@ abstract class Smarty_Internal_TemplateCompilerBase
$this->trigger_template_error("Default plugin handler: Returned script file \"{$script}\" for \"{$tag}\" not found");
}
}
if (!is_string($callback) && !(is_array($callback) && is_string($callback[0]) && is_string($callback[1]))) {
if (!is_string($callback) &&
!(is_array($callback) && is_string($callback[ 0 ]) && is_string($callback[ 1 ]))
) {
$this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" must be a static function name or array of class and function name");
}
if (is_callable($callback)) {
$this->default_handler_plugins[$plugin_type][$tag] = array($callback, true, array());
$this->default_handler_plugins[ $plugin_type ][ $tag ] = array($callback, true, array());
return true;
} else {
@ -1036,9 +1038,9 @@ abstract class Smarty_Internal_TemplateCompilerBase
"/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>\n";
// make sure we include modifier plugins for nocache code
foreach ($this->modifier_plugins as $plugin_name => $dummy) {
if (isset($this->parent_compiler->template->compiled->required_plugins['compiled'][$plugin_name]['modifier'])) {
$this->parent_compiler->template->compiled->required_plugins['nocache'][$plugin_name]['modifier'] =
$this->parent_compiler->template->compiled->required_plugins['compiled'][$plugin_name]['modifier'];
if (isset($this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ])) {
$this->parent_compiler->template->compiled->required_plugins[ 'nocache' ][ $plugin_name ][ 'modifier' ] =
$this->parent_compiler->template->compiled->required_plugins[ 'compiled' ][ $plugin_name ][ 'modifier' ];
}
}
} else {
@ -1064,7 +1066,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
public function getId($input)
{
if (preg_match('~^[\'"]*([0-9]*[a-zA-Z_]\w*)[\'"]*$~', $input, $match)) {
return $match[1];
return $match[ 1 ];
}
return false;
}
@ -1079,7 +1081,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
public function getVariableName($input)
{
if (preg_match('~^[$]_smarty_tpl->tpl_vars\[[\'"]*([0-9]*[a-zA-Z_]\w*)[\'"]*\]->value$~', $input, $match)) {
return $match[1];
return $match[ 1 ];
}
return false;
}
@ -1136,7 +1138,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
$error_text =
'Syntax error in template "' . (empty($this->trace_filepath) ? $templateName : $this->trace_filepath) .
'" on line ' . ($line + $this->trace_line_offset) . ' "' .
trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1])) . '" ';
trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ])) . '" ';
if (isset($args)) {
// individual error message
$error_text .= $args;
@ -1146,13 +1148,13 @@ abstract class Smarty_Internal_TemplateCompilerBase
$error_text .= ' - Unexpected "' . $lex->value . '"';
if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4) {
foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) {
$exp_token = $this->parser->yyTokenName[$token];
if (isset($lex->smarty_token_names[$exp_token])) {
$exp_token = $this->parser->yyTokenName[ $token ];
if (isset($lex->smarty_token_names[ $exp_token ])) {
// token type from lexer
$expect[] = '"' . $lex->smarty_token_names[$exp_token] . '"';
$expect[] = '"' . $lex->smarty_token_names[ $exp_token ] . '"';
} else {
// otherwise internal token name
$expect[] = $this->parser->yyTokenName[$token];
$expect[] = $this->parser->yyTokenName[ $token ];
}
}
$error_text .= ', expected one of: ' . implode(' , ', $expect);
@ -1160,7 +1162,7 @@ abstract class Smarty_Internal_TemplateCompilerBase
}
$e = new SmartyCompilerException($error_text);
$e->line = $line;
$e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[$line - 1]));
$e->source = trim(preg_replace('![\t\r\n]+!', ' ', $match[ $line - 1 ]));
$e->desc = $args;
$e->template = $this->template->source->filepath;
throw $e;

View File

@ -240,6 +240,16 @@ abstract class Smarty_Resource
return $resource->buildUniqueResourceName($smarty, $name);
}
/*
* Check if resource must check time stamps when when loading complied or cached templates.
* Resources like 'extends' which use source components my disable timestamp checks on own resource.
*
* @return bool
*/
public function checkTimestamps() {
return true;
}
/**
* initialize Source Object for given resource
* wrapper for backward compatibility to versions < 3.1.22

View File

@ -79,13 +79,6 @@ abstract class Smarty_Template_Resource_Base
*/
public $required_plugins = array();
/**
* Known template functions
*
* @var array
*/
public $tpl_function = array();
/**
* Included subtemplates
*

View File

@ -1,3 +1,16 @@
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === "object" && module.exports) {
var $ = require('jquery');
module.exports = factory($);
} else {
// Browser globals
factory(jQuery);
}
}(function (jQuery) {
/*!
* jQuery.textcomplete
*
@ -17,13 +30,18 @@ if (typeof jQuery === 'undefined') {
if (console.warn) { console.warn(message); }
};
var id = 1;
$.fn.textcomplete = function (strategies, option) {
var args = Array.prototype.slice.call(arguments);
return this.each(function () {
var self = this;
var $this = $(this);
var completer = $this.data('textComplete');
if (!completer) {
completer = new $.fn.textcomplete.Completer(this, option || {});
option || (option = {});
option._oid = id++; // unique object id
completer = new $.fn.textcomplete.Completer(this, option);
$this.data('textComplete', completer);
}
if (typeof strategies === 'string') {
@ -45,7 +63,10 @@ if (typeof jQuery === 'undefined') {
}
});
});
completer.register($.fn.textcomplete.Strategy.parse(strategies));
completer.register($.fn.textcomplete.Strategy.parse(strategies, {
el: self,
$el: $this
}));
}
});
};
@ -115,6 +136,10 @@ if (typeof jQuery === 'undefined') {
return Object.prototype.toString.call(obj) === '[object String]';
};
var isFunction = function (obj) {
return Object.prototype.toString.call(obj) === '[object Function]';
};
var uniqueId = 0;
function Completer(element, option) {
@ -124,7 +149,7 @@ if (typeof jQuery === 'undefined') {
this.views = [];
this.option = $.extend({}, Completer._getDefaults(), option);
if (!this.$el.is('input[type=text]') && !this.$el.is('textarea') && !element.isContentEditable && element.contentEditable != 'true') {
if (!this.$el.is('input[type=text]') && !this.$el.is('input[type=search]') && !this.$el.is('textarea') && !element.isContentEditable && element.contentEditable != 'true') {
throw new Error('textcomplete must be called on a Textarea or a ContentEditable.');
}
@ -171,7 +196,7 @@ if (typeof jQuery === 'undefined') {
if (this.option.adapter) {
Adapter = this.option.adapter;
} else {
if (this.$el.is('textarea') || this.$el.is('input[type=text]')) {
if (this.$el.is('textarea') || this.$el.is('input[type=text]') || this.$el.is('input[type=search]')) {
viewName = typeof element.selectionEnd === 'number' ? 'Textarea' : 'IETextarea';
} else {
viewName = 'ContentEditable';
@ -192,6 +217,12 @@ if (typeof jQuery === 'undefined') {
this.$el = this.adapter = this.dropdown = null;
},
deactivate: function () {
if (this.dropdown) {
this.dropdown.deactivate();
}
},
// Invoke textcomplete.
trigger: function (text, skipUnchangedTerm) {
if (!this.dropdown) { this.initialize(); }
@ -200,7 +231,7 @@ if (typeof jQuery === 'undefined') {
if (searchQuery.length) {
var term = searchQuery[1];
// Ignore shift-key, ctrl-key and so on.
if (skipUnchangedTerm && this._term === term) { return; }
if (skipUnchangedTerm && this._term === term && term !== "") { return; }
this._term = term;
this._search.apply(this, searchQuery);
} else {
@ -224,8 +255,10 @@ if (typeof jQuery === 'undefined') {
//
// value - The selected element of the array callbacked from search func.
// strategy - The Strategy object.
select: function (value, strategy) {
this.adapter.select(value, strategy);
// e - Click or keydown event object.
select: function (value, strategy, e) {
this._term = null;
this.adapter.select(value, strategy, e);
this.fire('change').fire('textComplete:select', value, strategy);
this.adapter.focus();
},
@ -248,8 +281,9 @@ if (typeof jQuery === 'undefined') {
var strategy = this.strategies[i];
var context = strategy.context(text);
if (context || context === '') {
var matchRegexp = isFunction(strategy.match) ? strategy.match(text) : strategy.match;
if (isString(context)) { text = context; }
var match = text.match(strategy.match);
var match = text.match(matchRegexp);
if (match) { return [strategy, match[strategy.index], match]; }
}
}
@ -262,14 +296,14 @@ if (typeof jQuery === 'undefined') {
strategy.search(term, function (data, stillSearching) {
if (!self.dropdown.shown) {
self.dropdown.activate();
self.dropdown.setPosition(self.adapter.getCaretPosition());
}
if (self._clearAtNext) {
// The first callback in the current lock.
self.dropdown.clear();
self._clearAtNext = false;
}
self.dropdown.render(self._zip(data, strategy));
self.dropdown.setPosition(self.adapter.getCaretPosition());
self.dropdown.render(self._zip(data, strategy, term));
if (!stillSearching) {
// The last callback in the current lock.
free();
@ -284,9 +318,9 @@ if (typeof jQuery === 'undefined') {
//
// this._zip(['a', 'b'], 's');
// //=> [{ value: 'a', strategy: 's' }, { value: 'b', strategy: 's' }]
_zip: function (data, strategy) {
_zip: function (data, strategy, term) {
return $.map(data, function (value) {
return { value: value, strategy: strategy };
return { value: value, strategy: strategy, term: term };
});
}
});
@ -297,6 +331,8 @@ if (typeof jQuery === 'undefined') {
+function ($) {
'use strict';
var $window = $(window);
var include = function (zippedData, datum) {
var i, elem;
var idProperty = datum.strategy.idProperty
@ -320,6 +356,16 @@ if (typeof jQuery === 'undefined') {
});
});
var commands = {
SKIP_DEFAULT: 0,
KEY_UP: 1,
KEY_DOWN: 2,
KEY_ENTER: 3,
KEY_PAGEUP: 4,
KEY_PAGEDOWN: 5,
KEY_ESCAPE: 6
};
// Dropdown view
// =============
@ -327,7 +373,7 @@ if (typeof jQuery === 'undefined') {
//
// element - Textarea or contenteditable element.
function Dropdown(element, completer, option) {
this.$el = Dropdown.findOrCreateElement(option);
this.$el = Dropdown.createElement(option);
this.completer = completer;
this.id = completer.id + 'dropdown';
this._data = []; // zipped data.
@ -338,7 +384,7 @@ if (typeof jQuery === 'undefined') {
if (option.listPosition) { this.setPosition = option.listPosition; }
if (option.height) { this.$el.height(option.height); }
var self = this;
$.each(['maxCount', 'placement', 'footer', 'header', 'className'], function (_i, name) {
$.each(['maxCount', 'placement', 'footer', 'header', 'noResultsMessage', 'className'], function (_i, name) {
if (option[name] != null) { self[name] = option[name]; }
});
this._bindEvents(element);
@ -349,18 +395,19 @@ if (typeof jQuery === 'undefined') {
// Class methods
// -------------
findOrCreateElement: function (option) {
createElement: function (option) {
var $parent = option.appendTo;
if (!($parent instanceof $)) { $parent = $($parent); }
var $el = $parent.children('.dropdown-menu')
if (!$el.length) {
$el = $('<ul class="dropdown-menu"></ul>').css({
var $el = $('<ul></ul>')
.addClass('dropdown-menu textcomplete-dropdown')
.attr('id', 'textcomplete-dropdown-' + option._oid)
.css({
display: 'none',
left: 0,
position: 'absolute',
zIndex: option.zIndex
}).appendTo($parent);
}
})
.appendTo($parent);
return $el;
}
});
@ -391,6 +438,7 @@ if (typeof jQuery === 'undefined') {
this.$el.off('.' + this.id);
this.$inputEl.off('.' + this.id);
this.clear();
this.$el.remove();
this.$el = this.$inputEl = this.completer = null;
delete dropdownViews[this.id]
},
@ -399,34 +447,45 @@ if (typeof jQuery === 'undefined') {
var contentsHtml = this._buildContents(zippedData);
var unzippedData = $.map(this.data, function (d) { return d.value; });
if (this.data.length) {
var strategy = zippedData[0].strategy;
if (strategy.id) {
this.$el.attr('data-strategy', strategy.id);
} else {
this.$el.removeAttr('data-strategy');
}
this._renderHeader(unzippedData);
this._renderFooter(unzippedData);
if (contentsHtml) {
this._renderContents(contentsHtml);
this._fitToBottom();
this._fitToRight();
this._activateIndexedItem();
}
this._setScroll();
} else if (this.noResultsMessage) {
this._renderNoResultsMessage(unzippedData);
} else if (this.shown) {
this.deactivate();
}
},
setPosition: function (position) {
this.$el.css(this._applyPlacement(position));
setPosition: function (pos) {
// Make the dropdown fixed if the input is also fixed
// This can't be done during init, as textcomplete may be used on multiple elements on the same page
// Because the same dropdown is reused behind the scenes, we need to recheck every time the dropdown is showed
var position = 'absolute';
// Check if input or one of its parents has positioning we need to care about
this.$inputEl.add(this.$inputEl.parents()).each(function() {
this.$inputEl.add(this.$inputEl.parents()).each(function() {
if($(this).css('position') === 'absolute') // The element has absolute positioning, so it's all OK
return false;
if($(this).css('position') === 'fixed') {
pos.top -= $window.scrollTop();
pos.left -= $window.scrollLeft();
position = 'fixed';
return false;
}
});
this.$el.css(this._applyPlacement(pos));
this.$el.css({ position: position }); // Update positioning
return this;
@ -436,7 +495,7 @@ if (typeof jQuery === 'undefined') {
this.$el.html('');
this.data = [];
this._index = 0;
this._$header = this._$footer = null;
this._$header = this._$footer = this._$noResultsMessage = null;
},
activate: function () {
@ -481,19 +540,25 @@ if (typeof jQuery === 'undefined') {
return e.keyCode === 34; // PAGEDOWN
},
isEscape: function (e) {
return e.keyCode === 27; // ESCAPE
},
// Private properties
// ------------------
_data: null, // Currently shown zipped data.
_index: null,
_$header: null,
_$noResultsMessage: null,
_$footer: null,
// Private methods
// ---------------
_bindEvents: function () {
this.$el.on('mousedown.' + this.id, '.textcomplete-item', $.proxy(this._onClick, this))
this.$el.on('mousedown.' + this.id, '.textcomplete-item', $.proxy(this._onClick, this));
this.$el.on('touchstart.' + this.id, '.textcomplete-item', $.proxy(this._onClick, this));
this.$el.on('mouseover.' + this.id, '.textcomplete-item', $.proxy(this._onMouseover, this));
this.$inputEl.on('keydown.' + this.id, $.proxy(this._onKeydown, this));
},
@ -506,11 +571,16 @@ if (typeof jQuery === 'undefined') {
$el = $el.closest('.textcomplete-item');
}
var datum = this.data[parseInt($el.data('index'), 10)];
this.completer.select(datum.value, datum.strategy);
this.completer.select(datum.value, datum.strategy, e);
var self = this;
// Deactive at next tick to allow other event handlers to know whether
// the dropdown has been shown or not.
setTimeout(function () { self.deactivate(); }, 0);
setTimeout(function () {
self.deactivate();
if (e.type === 'touchstart') {
self.$inputEl.focus();
}
}, 0);
},
// Activate hovered item.
@ -526,21 +596,58 @@ if (typeof jQuery === 'undefined') {
_onKeydown: function (e) {
if (!this.shown) { return; }
var command;
if ($.isFunction(this.option.onKeydown)) {
command = this.option.onKeydown(e, commands);
}
if (command == null) {
command = this._defaultKeydown(e);
}
switch (command) {
case commands.KEY_UP:
e.preventDefault();
this._up();
break;
case commands.KEY_DOWN:
e.preventDefault();
this._down();
break;
case commands.KEY_ENTER:
e.preventDefault();
this._enter(e);
break;
case commands.KEY_PAGEUP:
e.preventDefault();
this._pageup();
break;
case commands.KEY_PAGEDOWN:
e.preventDefault();
this._pagedown();
break;
case commands.KEY_ESCAPE:
e.preventDefault();
this.deactivate();
break;
}
},
_defaultKeydown: function (e) {
if (this.isUp(e)) {
e.preventDefault();
this._up();
return commands.KEY_UP;
} else if (this.isDown(e)) {
e.preventDefault();
this._down();
return commands.KEY_DOWN;
} else if (this.isEnter(e)) {
e.preventDefault();
this._enter();
return commands.KEY_ENTER;
} else if (this.isPageup(e)) {
e.preventDefault();
this._pageup();
return commands.KEY_PAGEUP;
} else if (this.isPagedown(e)) {
e.preventDefault();
this._pagedown();
return commands.KEY_PAGEDOWN;
} else if (this.isEscape(e)) {
return commands.KEY_ESCAPE;
}
},
@ -564,10 +671,10 @@ if (typeof jQuery === 'undefined') {
this._setScroll();
},
_enter: function () {
_enter: function (e) {
var datum = this.data[parseInt(this._getActiveElement().data('index'), 10)];
this.completer.select(datum.value, datum.strategy);
this._setScroll();
this.completer.select(datum.value, datum.strategy, e);
this.deactivate();
},
_pageup: function () {
@ -630,7 +737,7 @@ if (typeof jQuery === 'undefined') {
index = this.data.length;
this.data.push(datum);
html += '<li class="textcomplete-item" data-index="' + index + '"><a>';
html += datum.strategy.template(datum.value);
html += datum.strategy.template(datum.value, datum.term);
html += '</a></li>';
}
return html;
@ -656,6 +763,16 @@ if (typeof jQuery === 'undefined') {
}
},
_renderNoResultsMessage: function (unzippedData) {
if (this.noResultsMessage) {
if (!this._$noResultsMessage) {
this._$noResultsMessage = $('<li class="textcomplete-no-results-message"></li>').appendTo(this.$el);
}
var html = $.isFunction(this.noResultsMessage) ? this.noResultsMessage(unzippedData) : this.noResultsMessage;
this._$noResultsMessage.html(html);
}
},
_renderContents: function (html) {
if (this._$footer) {
this._$footer.before(html);
@ -664,7 +781,32 @@ if (typeof jQuery === 'undefined') {
}
},
_applyPlacement: function (position) {
_fitToBottom: function() {
var windowScrollBottom = $window.scrollTop() + $window.height();
var height = this.$el.height();
if ((this.$el.position().top + height) > windowScrollBottom) {
this.$el.offset({top: windowScrollBottom - height});
}
},
_fitToRight: function() {
// We don't know how wide our content is until the browser positions us, and at that point it clips us
// to the document width so we don't know if we would have overrun it. As a heuristic to avoid that clipping
// (which makes our elements wrap onto the next line and corrupt the next item), if we're close to the right
// edge, move left. We don't know how far to move left, so just keep nudging a bit.
var tolerance = 30; // pixels. Make wider than vertical scrollbar because we might not be able to use that space.
var lastOffset = this.$el.offset().left, offset;
var width = this.$el.width();
var maxLeft = $window.width() - tolerance;
while (lastOffset + width > maxLeft) {
this.$el.offset({left: lastOffset - tolerance});
offset = this.$el.offset().left;
if (offset >= lastOffset) { break; }
lastOffset = offset;
}
},
_applyPlacement: function (position) {
// If the 'placement' option set to 'top', move the position above the element.
if (this.placement.indexOf('top') !== -1) {
// Overwrite the position object to set the 'bottom' property instead of the top.
@ -688,6 +830,7 @@ if (typeof jQuery === 'undefined') {
});
$.fn.textcomplete.Dropdown = Dropdown;
$.extend($.fn.textcomplete, commands);
}(jQuery);
+function ($) {
@ -713,9 +856,12 @@ if (typeof jQuery === 'undefined') {
if (this.cache) { this.search = memoize(this.search); }
}
Strategy.parse = function (optionsArray) {
return $.map(optionsArray, function (options) {
return new Strategy(options);
Strategy.parse = function (strategiesArray, params) {
return $.map(strategiesArray, function (strategy) {
var strategyObj = new Strategy(strategy);
strategyObj.el = params.el;
strategyObj.$el = params.$el;
return strategyObj;
});
};
@ -729,6 +875,7 @@ if (typeof jQuery === 'undefined') {
search: null,
// Optional
id: null,
cache: false,
context: function () { return true; },
index: 2,
@ -818,11 +965,19 @@ if (typeof jQuery === 'undefined') {
},
// Returns the caret's relative coordinates from body's left top corner.
//
// FIXME: Calculate the left top corner of `this.option.appendTo` element.
getCaretPosition: function () {
var position = this._getCaretRelativePosition();
var offset = this.$el.offset();
// Calculate the left top corner of `this.option.appendTo` element.
var $parent = this.option.appendTo;
if ($parent) {
if (!($parent instanceof $)) { $parent = $($parent); }
var parentOffset = $parent.offsetParent().offset();
offset.top -= parentOffset.top;
offset.left -= parentOffset.left;
}
position.top += offset.top;
position.left += offset.left;
return position;
@ -848,6 +1003,8 @@ if (typeof jQuery === 'undefined') {
// Suppress searching if it returns true.
_skipSearch: function (clickEvent) {
switch (clickEvent.keyCode) {
case 9: // TAB
case 13: // ENTER
case 40: // DOWN
case 38: // UP
return true;
@ -874,89 +1031,58 @@ if (typeof jQuery === 'undefined') {
this.initialize(element, completer, option);
}
Textarea.DIV_PROPERTIES = {
left: -9999,
position: 'absolute',
top: 0,
whiteSpace: 'pre-wrap'
}
Textarea.COPY_PROPERTIES = [
'border-width', 'font-family', 'font-size', 'font-style', 'font-variant',
'font-weight', 'height', 'letter-spacing', 'word-spacing', 'line-height',
'text-decoration', 'text-align', 'width', 'padding-top', 'padding-right',
'padding-bottom', 'padding-left', 'margin-top', 'margin-right',
'margin-bottom', 'margin-left', 'border-style', 'box-sizing', 'tab-size'
];
$.extend(Textarea.prototype, $.fn.textcomplete.Adapter.prototype, {
// Public methods
// --------------
// Update the textarea with the given value and strategy.
select: function (value, strategy) {
select: function (value, strategy, e) {
var pre = this.getTextFromHeadToCaret();
var post = this.el.value.substring(this.el.selectionEnd);
var newSubstr = strategy.replace(value);
if ($.isArray(newSubstr)) {
post = newSubstr[1] + post;
newSubstr = newSubstr[0];
var newSubstr = strategy.replace(value, e);
if (typeof newSubstr !== 'undefined') {
if ($.isArray(newSubstr)) {
post = newSubstr[1] + post;
newSubstr = newSubstr[0];
}
pre = pre.replace(strategy.match, newSubstr);
this.$el.val(pre + post);
this.el.selectionStart = this.el.selectionEnd = pre.length;
}
pre = pre.replace(strategy.match, newSubstr);
this.$el.val(pre + post);
this.el.selectionStart = this.el.selectionEnd = pre.length;
},
getTextFromHeadToCaret: function () {
return this.el.value.substring(0, this.el.selectionEnd);
},
// Private methods
// ---------------
// Returns the caret's relative coordinates from textarea's left top corner.
//
// Browser native API does not provide the way to know the position of
// caret in pixels, so that here we use a kind of hack to accomplish
// the aim. First of all it puts a dummy div element and completely copies
// the textarea's style to the element, then it inserts the text and a
// span element into the textarea.
// Consequently, the span element's position is the thing what we want.
_getCaretRelativePosition: function () {
var dummyDiv = $('<div></div>').css(this._copyCss())
.text(this.getTextFromHeadToCaret());
var span = $('<span></span>').text('.').appendTo(dummyDiv);
this.$el.before(dummyDiv);
var position = span.position();
position.top += span.height() - this.$el.scrollTop();
position.lineHeight = span.height();
dummyDiv.remove();
return position;
var p = $.fn.textcomplete.getCaretCoordinates(this.el, this.el.selectionStart);
return {
top: p.top + this._calculateLineHeight() - this.$el.scrollTop(),
left: p.left - this.$el.scrollLeft()
};
},
_copyCss: function () {
return $.extend({
// Set 'scroll' if a scrollbar is being shown; otherwise 'auto'.
overflow: this.el.scrollHeight > this.el.offsetHeight ? 'scroll' : 'auto'
}, Textarea.DIV_PROPERTIES, this._getStyles());
},
_getStyles: (function ($) {
var color = $('<div></div>').css(['color']).color;
if (typeof color !== 'undefined') {
return function () {
return this.$el.css(Textarea.COPY_PROPERTIES);
};
} else { // jQuery < 1.8
return function () {
var $el = this.$el;
var styles = {};
$.each(Textarea.COPY_PROPERTIES, function (i, property) {
styles[property] = $el.css(property);
});
return styles;
};
_calculateLineHeight: function () {
var lineHeight = parseInt(this.$el.css('line-height'), 10);
if (isNaN(lineHeight)) {
// http://stackoverflow.com/a/4515470/1297336
var parentNode = this.el.parentNode;
var temp = document.createElement(this.el.nodeName);
var style = this.el.style;
temp.setAttribute(
'style',
'margin:0px;padding:0px;font-family:' + style.fontFamily + ';font-size:' + style.fontSize
);
temp.innerHTML = 'test';
parentNode.appendChild(temp);
lineHeight = temp.clientHeight;
parentNode.removeChild(temp);
}
})($),
getTextFromHeadToCaret: function () {
return this.el.value.substring(0, this.el.selectionEnd);
return lineHeight;
}
});
@ -981,22 +1107,24 @@ if (typeof jQuery === 'undefined') {
// Public methods
// --------------
select: function (value, strategy) {
select: function (value, strategy, e) {
var pre = this.getTextFromHeadToCaret();
var post = this.el.value.substring(pre.length);
var newSubstr = strategy.replace(value);
if ($.isArray(newSubstr)) {
post = newSubstr[1] + post;
newSubstr = newSubstr[0];
var newSubstr = strategy.replace(value, e);
if (typeof newSubstr !== 'undefined') {
if ($.isArray(newSubstr)) {
post = newSubstr[1] + post;
newSubstr = newSubstr[0];
}
pre = pre.replace(strategy.match, newSubstr);
this.$el.val(pre + post);
this.el.focus();
var range = this.el.createTextRange();
range.collapse(true);
range.moveEnd('character', pre.length);
range.moveStart('character', pre.length);
range.select();
}
pre = pre.replace(strategy.match, newSubstr);
this.$el.val(pre + post);
this.el.focus();
var range = this.el.createTextRange();
range.collapse(true);
range.moveEnd('character', pre.length);
range.moveStart('character', pre.length);
range.select();
},
getTextFromHeadToCaret: function () {
@ -1032,7 +1160,7 @@ if (typeof jQuery === 'undefined') {
// Update the content with the given value and strategy.
// When an dropdown item is selected, it is executed.
select: function (value, strategy) {
select: function (value, strategy, e) {
var pre = this.getTextFromHeadToCaret();
var sel = window.getSelection()
var range = sel.getRangeAt(0);
@ -1040,20 +1168,41 @@ if (typeof jQuery === 'undefined') {
selection.selectNodeContents(range.startContainer);
var content = selection.toString();
var post = content.substring(range.startOffset);
var newSubstr = strategy.replace(value);
if ($.isArray(newSubstr)) {
post = newSubstr[1] + post;
newSubstr = newSubstr[0];
var newSubstr = strategy.replace(value, e);
if (typeof newSubstr !== 'undefined') {
if ($.isArray(newSubstr)) {
post = newSubstr[1] + post;
newSubstr = newSubstr[0];
}
pre = pre.replace(strategy.match, newSubstr);
range.selectNodeContents(range.startContainer);
range.deleteContents();
// create temporary elements
var preWrapper = document.createElement("div");
preWrapper.innerHTML = pre;
var postWrapper = document.createElement("div");
postWrapper.innerHTML = post;
// create the fragment thats inserted
var fragment = document.createDocumentFragment();
var childNode;
var lastOfPre;
while (childNode = preWrapper.firstChild) {
lastOfPre = fragment.appendChild(childNode);
}
while (childNode = postWrapper.firstChild) {
fragment.appendChild(childNode);
}
// insert the fragment & jump behind the last node in "pre"
range.insertNode(fragment);
range.setStartAfter(lastOfPre);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
pre = pre.replace(strategy.match, newSubstr);
range.selectNodeContents(range.startContainer);
range.deleteContents();
var node = document.createTextNode(pre + post);
range.insertNode(node);
range.setStart(node, pre.length);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
},
// Private methods
@ -1079,8 +1228,7 @@ if (typeof jQuery === 'undefined') {
position.left -= this.$el.offset().left;
position.top += $node.height() - this.$el.offset().top;
position.lineHeight = $node.height();
var dir = this.$el.attr('dir') || this.$el.css('direction');
if (dir === 'rtl') { position.left -= this.listView.$el.width(); }
$node.remove();
return position;
},
@ -1102,3 +1250,152 @@ if (typeof jQuery === 'undefined') {
$.fn.textcomplete.ContentEditable = ContentEditable;
}(jQuery);
// The MIT License (MIT)
//
// Copyright (c) 2015 Jonathan Ong me@jongleberry.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// https://github.com/component/textarea-caret-position
(function ($) {
// The properties that we copy into a mirrored div.
// Note that some browsers, such as Firefox,
// do not concatenate properties, i.e. padding-top, bottom etc. -> padding,
// so we have to do every single property specifically.
var properties = [
'direction', // RTL support
'boxSizing',
'width', // on Chrome and IE, exclude the scrollbar, so the mirror div wraps exactly as the textarea does
'height',
'overflowX',
'overflowY', // copy the scrollbar for IE
'borderTopWidth',
'borderRightWidth',
'borderBottomWidth',
'borderLeftWidth',
'borderStyle',
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
// https://developer.mozilla.org/en-US/docs/Web/CSS/font
'fontStyle',
'fontVariant',
'fontWeight',
'fontStretch',
'fontSize',
'fontSizeAdjust',
'lineHeight',
'fontFamily',
'textAlign',
'textTransform',
'textIndent',
'textDecoration', // might not make a difference, but better be safe
'letterSpacing',
'wordSpacing',
'tabSize',
'MozTabSize'
];
var isBrowser = (typeof window !== 'undefined');
var isFirefox = (isBrowser && window.mozInnerScreenX != null);
function getCaretCoordinates(element, position, options) {
if(!isBrowser) {
throw new Error('textarea-caret-position#getCaretCoordinates should only be called in a browser');
}
var debug = options && options.debug || false;
if (debug) {
var el = document.querySelector('#input-textarea-caret-position-mirror-div');
if ( el ) { el.parentNode.removeChild(el); }
}
// mirrored div
var div = document.createElement('div');
div.id = 'input-textarea-caret-position-mirror-div';
document.body.appendChild(div);
var style = div.style;
var computed = window.getComputedStyle? getComputedStyle(element) : element.currentStyle; // currentStyle for IE < 9
// default textarea styles
style.whiteSpace = 'pre-wrap';
if (element.nodeName !== 'INPUT')
style.wordWrap = 'break-word'; // only for textarea-s
// position off-screen
style.position = 'absolute'; // required to return coordinates properly
if (!debug)
style.visibility = 'hidden'; // not 'display: none' because we want rendering
// transfer the element's properties to the div
properties.forEach(function (prop) {
style[prop] = computed[prop];
});
if (isFirefox) {
// Firefox lies about the overflow property for textareas: https://bugzilla.mozilla.org/show_bug.cgi?id=984275
if (element.scrollHeight > parseInt(computed.height))
style.overflowY = 'scroll';
} else {
style.overflow = 'hidden'; // for Chrome to not render a scrollbar; IE keeps overflowY = 'scroll'
}
div.textContent = element.value.substring(0, position);
// the second special handling for input type="text" vs textarea: spaces need to be replaced with non-breaking spaces - http://stackoverflow.com/a/13402035/1269037
if (element.nodeName === 'INPUT')
div.textContent = div.textContent.replace(/\s/g, '\u00a0');
var span = document.createElement('span');
// Wrapping must be replicated *exactly*, including when a long word gets
// onto the next line, with whitespace at the end of the line before (#7).
// The *only* reliable way to do that is to copy the *entire* rest of the
// textarea's content into the <span> created at the caret position.
// for inputs, just '.' would be enough, but why bother?
span.textContent = element.value.substring(position) || '.'; // || because a completely empty faux span doesn't render at all
div.appendChild(span);
var coordinates = {
top: span.offsetTop + parseInt(computed['borderTopWidth']),
left: span.offsetLeft + parseInt(computed['borderLeftWidth'])
};
if (debug) {
span.style.backgroundColor = '#aaa';
} else {
document.body.removeChild(div);
}
return coordinates;
}
$.fn.textcomplete.getCaretCoordinates = getCaretCoordinates;
}(jQuery));
return jQuery;
}));

File diff suppressed because one or more lines are too long

View File

@ -443,6 +443,32 @@ function NavUpdate() {
timer = setTimeout(NavUpdate, updateInterval);
}
function contextualHelp() {
var container = $("#contextual-help-content");
if(container.hasClass('contextual-help-content-open')) {
container.removeClass('contextual-help-content-open');
$('main').css('top', '')
}
else {
container.addClass('contextual-help-content-open');
var mainTop = container.outerHeight(true);
$('main').css('top', mainTop + 'px');
}
}
function contextualHelpFocus(target, openSidePanel) {
if (openSidePanel) {
$("main").addClass('region_1-on'); // Open the side panel to highlight element
}
else {
$("main").removeClass('region_1-on');
}
$('html,body').animate({ scrollTop: $(target).offset().top - $('nav').outerHeight(true) - $('#contextual-help-content').outerHeight(true)}, 'slow');
for (i = 0; i < 3; i++) {
$(target).fadeTo('slow', 0.1).fadeTo('slow', 1.0);
}
}
function updatePageItems(mode, data) {

View File

@ -21,7 +21,7 @@ head_add_js('spin.js');
head_add_js('jquery.spin.js');
head_add_js('jquery.textinputs.js');
head_add_js('autocomplete.js');
head_add_js('library/jquery-textcomplete/jquery.textcomplete.js');
head_add_js('library/jquery-textcomplete/jquery.textcomplete.min.js');
//head_add_js('library/colorbox/jquery.colorbox.js');
head_add_js('library/jquery.timeago.js');
head_add_js('library/readmore.js/readmore.js');

View File

@ -56,4 +56,8 @@
top: 30px;
right: 15px;
}
.contextual-help-content-open {
top: 32px;
}
}

View File

@ -201,29 +201,26 @@ header #banner #logo-text {
}
/* contextual help */
.help-content {
background: $comment_item_colour;
color: $font_colour;
position: fixed;
top: -50%;
left: 0px;
width: 100%;
max-height: 50%;
padding: 20px;
/*transition: top 300ms cubic-bezier(0.17, 0.04, 0.03, 0.94);*/
border-bottom: #CCC 1px solid;
overflow: auto;
.contextual-help-content {
display: none;
}
.help-content-open {
.contextual-help-content-open {
display: block;
position: fixed;
top: 51px;
max-height: 50%;
background: $comment_item_colour;
padding: 20px;
border-bottom: #ccc 1px solid;
overflow: auto;
-moz-box-shadow: 0px 3px 3px rgba(0,0,0,0.2);
-webkit-box-shadow: 0px 3px 3px rgba(0,0,0,0.2);
box-shadow: 0px 3px 3px rgba(0,0,0,0.2);
/*transition: top 300ms cubic-bezier(0.17, 0.04, 0.03, 0.94);*/
}
.help-content dd {
.contextual-help-content dd {
margin-bottom: 1em;
}
/* contextual help end */
@ -1608,6 +1605,7 @@ nav ul li .notify-unseen
}
blockquote {
display: inline-block;
font-size: $font_size;
font-style: italic;
border-left: 3px solid #ccc;
@ -1703,10 +1701,9 @@ nav .badge.mail-update:hover {
#expand-aside,
#expand-tabs,
#help_nav_btn_collapsed {
#context-help-btn {
color: $nav_active_icon_colour;
padding: 7px 10px;
text-decoration: none;
}
.nav-tabs.nav-justified {

View File

@ -11,9 +11,11 @@
<button id="expand-aside" type="button" class="navbar-toggle" data-toggle="offcanvas" data-target="#region_1">
<i class="icon-circle-arrow-right" id="expand-aside-icon"></i>
</button>
<a class="navbar-toggle" target="hubzilla-help" href="{{$nav.help.0}}" title="{{$nav.help.3}}" id="{{$nav.help.4}}_collapsed"{{if $nav.help.6}} onclick="return false;"{{/if}}>
{{if $nav.help.6}}<i class="icon-question-sign"></i>{{else}}<i class="icon-question"></i>{{/if}}
</a>
{{if $nav.help.6}}
<button id="context-help-btn"class="navbar-toggle" type="button" onclick="contextualHelp(); return false;">
<i class="icon-question-sign"></i>
</button>
{{/if}}
{{if $userinfo}}
<img class="dropdown-toggle fakelink" data-toggle="dropdown" id="avatar" src="{{$userinfo.icon}}" alt="{{$userinfo.name}}"><span class="caret" id="usermenu-caret"></span>
{{if $localuser}}
@ -34,6 +36,10 @@
<li role="presentation" class="divider"></li>
<li role="presentation"><a href="{{$nav.admin.0}}" title="{{$nav.admin.3}}" role="menuitem" id="{{$nav.admin.4}}">{{$nav.admin.1}}</a></li>
{{/if}}
{{if $nav.help.6}}
<li role="presentation" class="divider"></li>
<li role="presentation"><a href="{{$nav.help.0}}" title="{{$nav.help.3}}" role="menuitem" id="{{$nav.help.4}}">{{$nav.help.1}}</a></li>
{{/if}}
{{if $nav.logout}}
<li role="presentation" class="divider"></li>
<li role="presentation"><a href="{{$nav.logout.0}}" title="{{$nav.logout.3}}" role="menuitem" id="{{$nav.logout.4}}">{{$nav.logout.1}}</a></li>
@ -191,16 +197,16 @@
{{/if}}
{{if $nav.help}}
<li class="{{$sel.help}} hidden-xs">
<a class="{{$nav.help.2}}" target="hubzilla-help" href="{{$nav.help.0}}" title="{{$nav.help.3}}" id="{{$nav.help.4}}"{{if $nav.help.6}} onclick="return false;"{{/if}}>{{if $nav.help.6}}<i class="icon-question-sign"></i>{{else}}<i class="icon-question"></i>{{/if}}</a>
<li class="{{$sel.help}}{{if $nav.help.6}} hidden-xs{{/if}}">
<a class="{{$nav.help.2}}" target="hubzilla-help" href="{{$nav.help.0}}" title="{{$nav.help.3}}" id="{{$nav.help.4}}"{{if $nav.help.6}} onclick="contextualHelp(); return false;"{{/if}}>{{if $nav.help.6}}<i class="icon-question-sign"></i>{{else}}<i class="icon-question"></i>{{/if}}</a>
</li>
{{/if}}
</ul>
</div>
</div>
{{if $nav.help.6}}
<div id="help-content" class="help-content">
<div id="contextual-help-content" class="contextual-help-content">
{{$nav.help.5}}
<p class="pull-right"><a href="{{$nav.help.0}}">Click here for more documentation...</a></p>
<button type="button" class="close" onclick="contextualHelp();">×</button>
</div>
{{/if}}

View File

@ -1,49 +0,0 @@
<script>
/* contextual help */
{{if $enable_context_help}}
$('.help-content').css('top', '-' + $('#help-content').height() + 'px')
$(document).mouseup(function (e)
{
e.preventDefault;
var container = $("#help-content");
if ((!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0 // ... nor a descendant of the container
&& container.hasClass('help-content-open'))
||
(
($('#help_nav_btn, #help_nav_btn_collapsed').is(e.target) || $('#help_nav_btn, #help_nav_btn_collapsed').has(e.target).length !== 0)
&& container.hasClass('help-content-open')
)) {
container.removeClass('help-content-open');
$('main').removeClass('help-content-open');
$('main').css('top', '')
}
else if (($('#help_nav_btn, #help_nav_btn_collapsed').is(e.target) || $('#help_nav_btn, #help_nav_btn_collapsed').has(e.target).length !== 0)
&& !container.hasClass('help-content-open')) {
$('#help-content').addClass('help-content-open');
$('main').removeClass('help-content-open');
var mainTop = $('#navbar-collapse-1').height();
if ($('#navbar-collapse-1').outerHeight(true) < $('#help-content').height()) {
mainTop = $('#help-content').outerHeight(true);
}
$('main').css('top', mainTop + 'px');
}
});
{{/if}}
var contextualHelpFocus = function (target, openSidePanel) {
if (openSidePanel) {
$("main").addClass('region_1-on'); // Open the side panel to highlight element
} else {
$("main").removeClass('region_1-on');
}
// Animate the page scroll to the element and then pulse the element to direct attention
$('html,body').animate({scrollTop: $(target).offset().top - $('#navbar-collapse-1').height() - $('#help-content').height() - 50}, 'slow');
for (i = 0; i < 3; i++) {
$(target).fadeTo('slow', 0.1).fadeTo('slow', 1.0);
}
}
</script>