mirror of
https://github.com/e107inc/e107.git
synced 2025-08-02 04:40:44 +02:00
Issue #991: Removed all Selectize JS code from PHP. Additional option (settings) for e107::js(). Integrates Selectize.js using e107::js(settings) and JavaScript behaviors with jQuery Once.
This commit is contained in:
@@ -348,6 +348,10 @@ if (abs($_serverTime - $lastSet) > 120)
|
|||||||
// </script>\n";
|
// </script>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// All JavaScript settings are placed in the footer of the page with the library weight so that inline scripts appear
|
||||||
|
// afterwards.
|
||||||
|
e107::getJs()->renderJs('settings');
|
||||||
|
|
||||||
e107::getJs()->renderJs('footer_inline', true);
|
e107::getJs()->renderJs('footer_inline', true);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@@ -326,6 +326,10 @@ e107::getJs()->renderJs('footer', true);
|
|||||||
|
|
||||||
e107::getJs()->renderCached('js');
|
e107::getJs()->renderCached('js');
|
||||||
|
|
||||||
|
// All JavaScript settings are placed in the footer of the page with the library weight so that inline scripts appear
|
||||||
|
// afterwards.
|
||||||
|
e107::getJs()->renderJs('settings');
|
||||||
|
|
||||||
// [JSManager] Load JS Footer inline code by priority
|
// [JSManager] Load JS Footer inline code by priority
|
||||||
e107::getJs()->renderJs('footer_inline', true);
|
e107::getJs()->renderJs('footer_inline', true);
|
||||||
|
|
||||||
|
@@ -1668,6 +1668,10 @@ class e107
|
|||||||
|
|
||||||
switch ($type)
|
switch ($type)
|
||||||
{
|
{
|
||||||
|
case 'settings':
|
||||||
|
$jshandler->jsSettings($data);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'core':
|
case 'core':
|
||||||
// data is e.g. 'core/tabs.js'
|
// data is e.g. 'core/tabs.js'
|
||||||
if(null !== $zone) $jshandler->requireCoreLib($data, $zone);
|
if(null !== $zone) $jshandler->requireCoreLib($data, $zone);
|
||||||
|
@@ -1954,6 +1954,137 @@ class e_parse extends e_parser
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a PHP variable into its JavaScript equivalent.
|
||||||
|
* We use HTML-safe strings, with several characters escaped.
|
||||||
|
*
|
||||||
|
* @param mixed $var
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function toJSON($var)
|
||||||
|
{
|
||||||
|
// The PHP version cannot change within a request.
|
||||||
|
static $php530;
|
||||||
|
|
||||||
|
if(!isset($php530))
|
||||||
|
{
|
||||||
|
$php530 = version_compare(PHP_VERSION, '5.3.0', '>=');
|
||||||
|
}
|
||||||
|
|
||||||
|
if($php530)
|
||||||
|
{
|
||||||
|
// Encode <, >, ', &, and " using the json_encode() options parameter.
|
||||||
|
return json_encode($var, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->toJSONhelper($var);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encodes a PHP variable to HTML-safe JSON for PHP versions below 5.3.0.
|
||||||
|
*
|
||||||
|
* @param mixed $var
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function toJSONhelper($var)
|
||||||
|
{
|
||||||
|
switch(gettype($var))
|
||||||
|
{
|
||||||
|
case 'boolean':
|
||||||
|
return $var ? 'true' : 'false'; // Lowercase necessary!
|
||||||
|
|
||||||
|
case 'integer':
|
||||||
|
case 'double':
|
||||||
|
return $var;
|
||||||
|
|
||||||
|
case 'resource':
|
||||||
|
case 'string':
|
||||||
|
// Always use Unicode escape sequences (\u0022) over JSON escape
|
||||||
|
// sequences (\") to prevent browsers interpreting these as
|
||||||
|
// special characters.
|
||||||
|
$replace_pairs = array(
|
||||||
|
// ", \ and U+0000 - U+001F must be escaped according to RFC 4627.
|
||||||
|
'\\' => '\u005C',
|
||||||
|
'"' => '\u0022',
|
||||||
|
"\x00" => '\u0000',
|
||||||
|
"\x01" => '\u0001',
|
||||||
|
"\x02" => '\u0002',
|
||||||
|
"\x03" => '\u0003',
|
||||||
|
"\x04" => '\u0004',
|
||||||
|
"\x05" => '\u0005',
|
||||||
|
"\x06" => '\u0006',
|
||||||
|
"\x07" => '\u0007',
|
||||||
|
"\x08" => '\u0008',
|
||||||
|
"\x09" => '\u0009',
|
||||||
|
"\x0a" => '\u000A',
|
||||||
|
"\x0b" => '\u000B',
|
||||||
|
"\x0c" => '\u000C',
|
||||||
|
"\x0d" => '\u000D',
|
||||||
|
"\x0e" => '\u000E',
|
||||||
|
"\x0f" => '\u000F',
|
||||||
|
"\x10" => '\u0010',
|
||||||
|
"\x11" => '\u0011',
|
||||||
|
"\x12" => '\u0012',
|
||||||
|
"\x13" => '\u0013',
|
||||||
|
"\x14" => '\u0014',
|
||||||
|
"\x15" => '\u0015',
|
||||||
|
"\x16" => '\u0016',
|
||||||
|
"\x17" => '\u0017',
|
||||||
|
"\x18" => '\u0018',
|
||||||
|
"\x19" => '\u0019',
|
||||||
|
"\x1a" => '\u001A',
|
||||||
|
"\x1b" => '\u001B',
|
||||||
|
"\x1c" => '\u001C',
|
||||||
|
"\x1d" => '\u001D',
|
||||||
|
"\x1e" => '\u001E',
|
||||||
|
"\x1f" => '\u001F',
|
||||||
|
// Prevent browsers from interpreting these as as special.
|
||||||
|
"'" => '\u0027',
|
||||||
|
'<' => '\u003C',
|
||||||
|
'>' => '\u003E',
|
||||||
|
'&' => '\u0026',
|
||||||
|
// Prevent browsers from interpreting the solidus as special and
|
||||||
|
// non-compliant JSON parsers from interpreting // as a comment.
|
||||||
|
'/' => '\u002F',
|
||||||
|
// While these are allowed unescaped according to ECMA-262, section
|
||||||
|
// 15.12.2, they cause problems in some JSON parsers.
|
||||||
|
"\xe2\x80\xa8" => '\u2028', // U+2028, Line Separator.
|
||||||
|
"\xe2\x80\xa9" => '\u2029', // U+2029, Paragraph Separator.
|
||||||
|
);
|
||||||
|
|
||||||
|
return '"' . strtr($var, $replace_pairs) . '"';
|
||||||
|
|
||||||
|
case 'array':
|
||||||
|
// Arrays in JSON can't be associative. If the array is empty or if it
|
||||||
|
// has sequential whole number keys starting with 0, it's not associative
|
||||||
|
// so we can go ahead and convert it as an array.
|
||||||
|
if(empty($var) || array_keys($var) === range(0, sizeof($var) - 1))
|
||||||
|
{
|
||||||
|
$output = array();
|
||||||
|
foreach($var as $v)
|
||||||
|
{
|
||||||
|
$output[] = $this->toJSONhelper($v);
|
||||||
|
}
|
||||||
|
return '[ ' . implode(', ', $output) . ' ]';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Otherwise, fall through to convert the array as an object.
|
||||||
|
case 'object':
|
||||||
|
$output = array();
|
||||||
|
foreach($var as $k => $v)
|
||||||
|
{
|
||||||
|
$output[] = $this->toJSONhelper(strval($k)) . ':' . $this->toJSONhelper($v);
|
||||||
|
}
|
||||||
|
return '{' . implode(', ', $output) . '}';
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Text for RSS/XML use.
|
* Convert Text for RSS/XML use.
|
||||||
*
|
*
|
||||||
|
@@ -422,109 +422,20 @@ class e_form
|
|||||||
e107::css('core', 'selectize/css/selectize.bootstrap2.css', 'jquery');
|
e107::css('core', 'selectize/css/selectize.bootstrap2.css', 'jquery');
|
||||||
}
|
}
|
||||||
|
|
||||||
$ac = $options['selectize'];
|
// Load selectize behavior.
|
||||||
$fieldID = vartrue($options['id'], $this->name2id($name));
|
e107::js('core', 'selectize/js/selectize.init.js', 'jquery');
|
||||||
|
|
||||||
// TODO: better method to create suffix as unique identifier.
|
$jsSettings = array(
|
||||||
$optionSuffix = $fieldID . vartrue($options['selectize']['e_editable']);
|
'id' => vartrue($options['id'], $this->name2id($name)),
|
||||||
$optionSuffix = md5($optionSuffix);
|
'options' => $options['selectize'],
|
||||||
|
// Multilingual support.
|
||||||
|
'strings' => array(
|
||||||
|
'anonymous' => LAN_ANONYMOUS,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// We need to declare an options array with unique ID for the selectize.js field, because we have to store
|
// Merge field settings with other selectize field settings.
|
||||||
// the latest default values, because if the selectize() would be reinitialized, e.g. in x-editable popover,
|
e107::js('settings', array('selectize' => array($jsSettings)));
|
||||||
// we have to get the latest value(s).
|
|
||||||
$jsOptions = 'var options' . $optionSuffix . ' = ';
|
|
||||||
$jsOptions .= (vartrue($ac['options']) ? json_encode($ac['options']) : "[]") . ";\n";
|
|
||||||
|
|
||||||
// TODO: more options and callbacks.
|
|
||||||
$js = "$('#" . $fieldID . "').selectize({
|
|
||||||
// General options.
|
|
||||||
items: " . (vartrue($ac['items']) ? json_encode($ac['items']) : '[]') . ",
|
|
||||||
delimiter: '" . (vartrue($ac['delimiter'], ',')) . "',
|
|
||||||
diacritics: " . (vartrue($ac['diacritics'], true) ? 'true' : 'false') . ",
|
|
||||||
create: " . (vartrue($ac['create'], false) ? 'true' : 'false') . ",
|
|
||||||
createOnBlur: " . (vartrue($ac['createOnBlur'], true) ? 'true' : 'false') . ",
|
|
||||||
highlight: " . (vartrue($ac['highlight'], false) ? 'true' : 'false') . ",
|
|
||||||
persist: " . (vartrue($ac['persist'], false) ? 'true' : 'false') . ",
|
|
||||||
openOnFocus: " . (vartrue($ac['openOnFocus'], false) ? 'true' : 'false') . ",
|
|
||||||
maxOptions: " . vartrue($ac['maxOptions'], 'null') . ",
|
|
||||||
maxItems: " . vartrue($ac['maxItems'], 'null') . ",
|
|
||||||
hideSelected: " . (vartrue($ac['hideSelected'], false) ? 'true' : 'false') . ",
|
|
||||||
closeAfterSelect: " . (vartrue($ac['closeAfterSelect'], true) ? 'true' : 'false') . ",
|
|
||||||
allowEmptyOption: " . (vartrue($ac['allowEmptyOption'], false) ? 'true' : 'false') . ",
|
|
||||||
scrollDuration: " . vartrue($ac['scrollDuration'], 60) . ",
|
|
||||||
loadThrottle: " . vartrue($ac['loadThrottle'], 300) . ",
|
|
||||||
loadingClass: '" . vartrue($ac['loadingClass'], 'loading') . "',
|
|
||||||
preload: " . (vartrue($ac['preload'], false) ? 'true' : 'false') . ",
|
|
||||||
dropdownParent: " . vartrue($ac['dropdownParent'], 'null') . ",
|
|
||||||
addPrecedence: " . (vartrue($ac['addPrecedence'], false) ? 'true' : 'false') . ",
|
|
||||||
selectOnTab: " . (vartrue($ac['selectOnTab'], false) ? 'true' : 'false') . ",
|
|
||||||
mode: '" . (vartrue($ac['mode'], 'multi')) . "',
|
|
||||||
plugins: " . (vartrue($ac['plugins']) ? json_encode($ac['plugins']) : '[]') . ",
|
|
||||||
|
|
||||||
// Data / Searching.
|
|
||||||
options: options" . $optionSuffix . ",
|
|
||||||
valueField: '" . vartrue($ac['valueField'], 'value') . "',
|
|
||||||
labelField: '" . vartrue($ac['labelField'], 'label') . "',
|
|
||||||
searchField: '" . vartrue($ac['searchField'], 'label') . "',
|
|
||||||
|
|
||||||
// Callbacks.
|
|
||||||
load: function(query, callback) {
|
|
||||||
var loadPath = '" . vartrue($ac['loadPath'], '') . "';
|
|
||||||
if (loadPath == '') return callback([]);
|
|
||||||
if (!query.length) return callback([]);
|
|
||||||
$.ajax({
|
|
||||||
url: loadPath,
|
|
||||||
type: 'POST',
|
|
||||||
dataType: 'json',
|
|
||||||
data: {
|
|
||||||
q: query,
|
|
||||||
l: " . vartrue($ac['maxOptions'], 10) . "
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
callback([]);
|
|
||||||
},
|
|
||||||
success: function(data) {
|
|
||||||
// Update items in options array of this field.
|
|
||||||
options" . $optionSuffix . " = data;
|
|
||||||
callback(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});";
|
|
||||||
|
|
||||||
// We have to generate JS for x-editable field, so we have to initialize selectize.js after popover opens.
|
|
||||||
if(vartrue($options['selectize']['e_editable']))
|
|
||||||
{
|
|
||||||
// TODO: instead of setTimeout, we should use an x-editable callback.
|
|
||||||
$click = "$('#" . $options['selectize']['e_editable'] . "').click(function(){
|
|
||||||
// Attach success callback for replacing user id with name.
|
|
||||||
$.fn.editable.defaults.success = function(response, newValue) {
|
|
||||||
if(response.status == 'error') return;
|
|
||||||
if ($('#" . $options['selectize']['e_editable'] . "').hasClass('editable-userpicker')) {
|
|
||||||
$('#" . $options['selectize']['e_editable'] . "').hide();
|
|
||||||
options" . $optionSuffix . " = options" . $optionSuffix . " || [];
|
|
||||||
userName = '" . LAN_ANONYMOUS . "';
|
|
||||||
$.each(options" . $optionSuffix . ", function(key, value) {
|
|
||||||
if (value." . vartrue($ac['valueField'], 'value') . " == newValue) {
|
|
||||||
userName = value." . vartrue($ac['labelField'], 'label') . ";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setTimeout(function(){
|
|
||||||
$('#" . $options['selectize']['e_editable'] . "').html(userName).show();
|
|
||||||
$.fn.editable.defaults.success = function(response, newValue) {}
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
setTimeout(function(){ " . $js . " }, 300);
|
|
||||||
})";
|
|
||||||
|
|
||||||
e107::js('footer-inline', "$(document).ready(function(){" . $jsOptions . $click . "});");
|
|
||||||
}
|
|
||||||
// We have to render JS for a simple form element.
|
|
||||||
else
|
|
||||||
{
|
|
||||||
e107::js('footer-inline', "$(document).ready(function(){" . $jsOptions . $js . "});");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove typeahead.
|
// TODO: remove typeahead.
|
||||||
|
@@ -45,7 +45,10 @@ class e_jsmanager
|
|||||||
// "http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js",
|
// "http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js",
|
||||||
// "http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"
|
// "http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"
|
||||||
// "http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"
|
// "http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"
|
||||||
"https://cdn.jsdelivr.net/jquery/2.1.4/jquery.min.js"
|
"https://cdn.jsdelivr.net/jquery/2.1.4/jquery.min.js",
|
||||||
|
// jQuery Once filters out all elements that had the same filter applied on them before. It can be used to
|
||||||
|
// ensure that a function is only applied once to an element. jQuery Once is used in e107.behaviors.
|
||||||
|
"https://cdnjs.cloudflare.com/ajax/libs/jquery-once/2.1.1/jquery.once.min.js"
|
||||||
// ,
|
// ,
|
||||||
// "http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/jquery-ui.min.js",
|
// "http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/jquery-ui.min.js",
|
||||||
// "http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/themes/base/jquery-ui.css",
|
// "http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/themes/base/jquery-ui.css",
|
||||||
@@ -66,6 +69,15 @@ class e_jsmanager
|
|||||||
|
|
||||||
|
|
||||||
protected $_core_prefs = array();
|
protected $_core_prefs = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to store JavaScript options will be rendered in footer as JSON object.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $_e_js_settings = array(
|
||||||
|
'basePath' => e_HTTP,
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Core JS library files, loaded via e_jslib.php
|
* Core JS library files, loaded via e_jslib.php
|
||||||
@@ -243,6 +255,9 @@ class e_jsmanager
|
|||||||
{
|
{
|
||||||
$this->_libraries['jquery'] = array(
|
$this->_libraries['jquery'] = array(
|
||||||
"https://cdn.jsdelivr.net/jquery/2.1.4/jquery.min.js",
|
"https://cdn.jsdelivr.net/jquery/2.1.4/jquery.min.js",
|
||||||
|
// jQuery Once filters out all elements that had the same filter applied on them before. It can be used
|
||||||
|
// to ensure that a function is only applied once to an element. jQuery Once is used in e107.behaviors.
|
||||||
|
"https://cdnjs.cloudflare.com/ajax/libs/jquery-once/2.1.1/jquery.once.min.js",
|
||||||
"https://cdn.jsdelivr.net/jquery.ui/1.11.4/jquery-ui.min.js",
|
"https://cdn.jsdelivr.net/jquery.ui/1.11.4/jquery-ui.min.js",
|
||||||
"https://cdn.jsdelivr.net/jquery.ui/1.11.4/themes/smoothness/jquery-ui.min.css"
|
"https://cdn.jsdelivr.net/jquery.ui/1.11.4/themes/smoothness/jquery-ui.min.css"
|
||||||
);
|
);
|
||||||
@@ -634,6 +649,18 @@ class e_jsmanager
|
|||||||
$this->addJs('footer_inline', $js_content, $priority);
|
$this->addJs('footer_inline', $js_content, $priority);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add JS settings to site footer
|
||||||
|
*
|
||||||
|
* @param array $js_settings
|
||||||
|
* @return e_jsmanager
|
||||||
|
*/
|
||||||
|
public function jsSettings(array $js_settings)
|
||||||
|
{
|
||||||
|
$this->addJs('settings', $js_settings);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function setDependency($dep)
|
function setDependency($dep)
|
||||||
@@ -816,7 +843,7 @@ class e_jsmanager
|
|||||||
// FIXME - this could break something after CSS support was added, move it to separate method(s), recursion by type!
|
// FIXME - this could break something after CSS support was added, move it to separate method(s), recursion by type!
|
||||||
// Causes the css error on jquery-ui as a css file is loaded as a js.
|
// Causes the css error on jquery-ui as a css file is loaded as a js.
|
||||||
|
|
||||||
if(is_array($file_path) )
|
if(is_array($file_path) && $type != 'settings')
|
||||||
{
|
{
|
||||||
// print_a($file_path);
|
// print_a($file_path);
|
||||||
foreach ($file_path as $fp => $loc)
|
foreach ($file_path as $fp => $loc)
|
||||||
@@ -960,6 +987,11 @@ class e_jsmanager
|
|||||||
return $this;
|
return $this;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'settings':
|
||||||
|
$this->_e_js_settings = array_merge_recursive($this->_e_js_settings, $file_path);
|
||||||
|
return $this;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return $this;
|
return $this;
|
||||||
break;
|
break;
|
||||||
@@ -985,7 +1017,7 @@ class e_jsmanager
|
|||||||
* @param boolean $return
|
* @param boolean $return
|
||||||
* @return string JS content - only if $return is true
|
* @return string JS content - only if $return is true
|
||||||
*/
|
*/
|
||||||
public function renderJs($mod, $zone, $external = true, $return = false)
|
public function renderJs($mod, $zone = null, $external = true, $return = false)
|
||||||
{
|
{
|
||||||
if($return)
|
if($return)
|
||||||
{
|
{
|
||||||
@@ -994,6 +1026,15 @@ class e_jsmanager
|
|||||||
|
|
||||||
switch($mod)
|
switch($mod)
|
||||||
{
|
{
|
||||||
|
case 'settings':
|
||||||
|
$tp = e107::getParser();
|
||||||
|
$options = $this->arrayMergeDeepArray(array($this->_e_js_settings));
|
||||||
|
$json = $tp->toJSON($options);
|
||||||
|
$js = 'jQuery.extend(e107.settings, ' . $json . ');';
|
||||||
|
echo '<script>' . $js . '</script>';
|
||||||
|
echo "\n";
|
||||||
|
break;
|
||||||
|
|
||||||
case 'framework': // CDN frameworks - rendered before consolidation script (if enabled)
|
case 'framework': // CDN frameworks - rendered before consolidation script (if enabled)
|
||||||
$fw = array();
|
$fw = array();
|
||||||
foreach ($this->_libraries as $lib)
|
foreach ($this->_libraries as $lib)
|
||||||
@@ -1109,6 +1150,36 @@ class e_jsmanager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges multiple arrays, recursively, and returns the merged array.
|
||||||
|
*/
|
||||||
|
public function arrayMergeDeepArray($arrays) {
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
foreach ($arrays as $array) {
|
||||||
|
foreach ($array as $key => $value) {
|
||||||
|
// Renumber integer keys as array_merge_recursive() does. Note that PHP
|
||||||
|
// automatically converts array keys that are integer strings (e.g., '1')
|
||||||
|
// to integers.
|
||||||
|
if (is_integer($key)) {
|
||||||
|
$result[] = $value;
|
||||||
|
}
|
||||||
|
// Recurse when both values are arrays.
|
||||||
|
elseif (isset($result[$key]) && is_array($result[$key]) && is_array($value)) {
|
||||||
|
$result[$key] = $this->arrayMergeDeepArray(array($result[$key], $value));
|
||||||
|
}
|
||||||
|
// Otherwise, use the latter value, overriding any previous value.
|
||||||
|
else {
|
||||||
|
$result[$key] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render JS/CSS file array
|
* Render JS/CSS file array
|
||||||
*
|
*
|
||||||
|
@@ -1,9 +1,126 @@
|
|||||||
// handle secured json string - the Prototype implementation
|
var e107 = e107 || {'settings': {}, 'behaviors': {}};
|
||||||
|
|
||||||
|
// Allow other JavaScript libraries to use $.
|
||||||
|
// TODO: Use jQuery.noConflict(), but for this, need to rewrite all e107 javascript to use wrapper: (function ($) { ... })(jQuery);
|
||||||
|
// jQuery.noConflict();
|
||||||
|
|
||||||
|
(function ($) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach all registered behaviors to a page element.
|
||||||
|
*
|
||||||
|
* Behaviors are event-triggered actions that attach to page elements, enhancing
|
||||||
|
* default non-JavaScript UIs. Behaviors are registered in the e107.behaviors
|
||||||
|
* object using the method 'attach' and optionally also 'detach' as follows:
|
||||||
|
* @code
|
||||||
|
* e107.behaviors.behaviorName = {
|
||||||
|
* attach: function (context, settings) {
|
||||||
|
* ...
|
||||||
|
* },
|
||||||
|
* detach: function (context, settings, trigger) {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* };
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* e107.attachBehaviors is added below to the jQuery ready event and so
|
||||||
|
* runs on initial page load. Developers implementing Ajax in their
|
||||||
|
* solutions should also call this function after new page content has been
|
||||||
|
* loaded, feeding in an element to be processed, in order to attach all
|
||||||
|
* behaviors to the new content.
|
||||||
|
*
|
||||||
|
* Behaviors should use
|
||||||
|
* @code
|
||||||
|
* $(selector).once('behavior-name', function () {
|
||||||
|
* ...
|
||||||
|
* });
|
||||||
|
* @endcode
|
||||||
|
* to ensure the behavior is attached only once to a given element. (Doing so
|
||||||
|
* enables the reprocessing of given elements, which may be needed on occasion
|
||||||
|
* despite the ability to limit behavior attachment to a particular element.)
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* An element to attach behaviors to. If none is given, the document element
|
||||||
|
* is used.
|
||||||
|
* @param settings
|
||||||
|
* An object containing settings for the current context. If none given, the
|
||||||
|
* global e107.settings object is used.
|
||||||
|
*/
|
||||||
|
e107.attachBehaviors = function (context, settings) {
|
||||||
|
context = context || document;
|
||||||
|
settings = settings || e107.settings;
|
||||||
|
// Execute all of them.
|
||||||
|
$.each(e107.behaviors, function () {
|
||||||
|
if ($.isFunction(this.attach)) {
|
||||||
|
this.attach(context, settings);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detach registered behaviors from a page element.
|
||||||
|
*
|
||||||
|
* Developers implementing AHAH/Ajax in their solutions should call this
|
||||||
|
* function before page content is about to be removed, feeding in an element
|
||||||
|
* to be processed, in order to allow special behaviors to detach from the
|
||||||
|
* content.
|
||||||
|
*
|
||||||
|
* Such implementations should look for the class name that was added in their
|
||||||
|
* corresponding e107.behaviors.behaviorName.attach implementation, i.e.
|
||||||
|
* behaviorName-processed, to ensure the behavior is detached only from
|
||||||
|
* previously processed elements.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* An element to detach behaviors from. If none is given, the document element
|
||||||
|
* is used.
|
||||||
|
* @param settings
|
||||||
|
* An object containing settings for the current context. If none given, the
|
||||||
|
* global e107.settings object is used.
|
||||||
|
* @param trigger
|
||||||
|
* A string containing what's causing the behaviors to be detached. The
|
||||||
|
* possible triggers are:
|
||||||
|
* - unload: (default) The context element is being removed from the DOM.
|
||||||
|
* - move: The element is about to be moved within the DOM (for example,
|
||||||
|
* during a tabledrag row swap). After the move is completed,
|
||||||
|
* e107.attachBehaviors() is called, so that the behavior can undo
|
||||||
|
* whatever it did in response to the move. Many behaviors won't need to
|
||||||
|
* do anything simply in response to the element being moved, but because
|
||||||
|
* IFRAME elements reload their "src" when being moved within the DOM,
|
||||||
|
* behaviors bound to IFRAME elements (like WYSIWYG editors) may need to
|
||||||
|
* take some action.
|
||||||
|
* - serialize: E.g. when an Ajax form is submitted, this is called with the
|
||||||
|
* form as the context. This provides every behavior within the form an
|
||||||
|
* opportunity to ensure that the field elements have correct content
|
||||||
|
* in them before the form is serialized. The canonical use-case is so
|
||||||
|
* that WYSIWYG editors can update the hidden textarea to which they are
|
||||||
|
* bound.
|
||||||
|
*
|
||||||
|
* @see e107.attachBehaviors
|
||||||
|
*/
|
||||||
|
e107.detachBehaviors = function (context, settings, trigger) {
|
||||||
|
context = context || document;
|
||||||
|
settings = settings || e107.settings;
|
||||||
|
trigger = trigger || 'unload';
|
||||||
|
// Execute all of them.
|
||||||
|
$.each(e107.behaviors, function () {
|
||||||
|
if ($.isFunction(this.detach)) {
|
||||||
|
this.detach(context, settings, trigger);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Attach all behaviors.
|
||||||
|
$(function () {
|
||||||
|
e107.attachBehaviors(document, e107.settings);
|
||||||
|
});
|
||||||
|
|
||||||
|
})(jQuery);
|
||||||
|
|
||||||
$.ajaxSetup({
|
$.ajaxSetup({
|
||||||
dataFilter: function(data, type) {
|
dataFilter: function (data, type) {
|
||||||
if(type != 'json' || !data) return data;
|
if (type != 'json' || !data) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
return data.replace(/^\/\*-secure-([\s\S]*)\*\/\s*$/, '$1');
|
return data.replace(/^\/\*-secure-([\s\S]*)\*\/\s*$/, '$1');
|
||||||
},
|
},
|
||||||
cache: false // Was Really NEeded!
|
cache: false // Was Really NEeded!
|
||||||
|
173
e107_web/js/selectize/js/selectize.init.js
Normal file
173
e107_web/js/selectize/js/selectize.init.js
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
(function ($) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Behavior to initialize autocomplete fields with selectize.js
|
||||||
|
*
|
||||||
|
* @type {{attach: e107.behaviors.selectizeInit.attach}}
|
||||||
|
*/
|
||||||
|
e107.behaviors.selectizeInit = {
|
||||||
|
attach: function (context, settings) {
|
||||||
|
if (e107.settings.selectize) {
|
||||||
|
$.each(e107.settings.selectize, function (index, item) {
|
||||||
|
var key = item.id;
|
||||||
|
|
||||||
|
// Inline, popup editor. Initialize selectize after opening popup.
|
||||||
|
if (item.options.e_editable) {
|
||||||
|
$(context).find('#' + item.options.e_editable).once('selectize-editable-init').each(function () {
|
||||||
|
var $eEditable = $('#' + item.options.e_editable);
|
||||||
|
|
||||||
|
$eEditable.click(function () {
|
||||||
|
// Attach success callback for replacing user id with name.
|
||||||
|
$.fn.editable.defaults.success = function (response, newValue) {
|
||||||
|
if (response.status == 'error') return;
|
||||||
|
if ($eEditable.hasClass('editable-userpicker')) {
|
||||||
|
$eEditable.hide();
|
||||||
|
var options = item.options.options ? item.options.options : [];
|
||||||
|
var userName = item.strings.anonymous ? item.strings.anonymous : '';
|
||||||
|
var valueField = item.options.valueField ? item.options.valueField : 'value';
|
||||||
|
var labelField = item.options.labelField ? item.options.labelField : 'label';
|
||||||
|
$.each(options, function (key, value) {
|
||||||
|
if (value[valueField] == newValue) {
|
||||||
|
userName = value[labelField];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setTimeout(function () {
|
||||||
|
$eEditable.html(userName).show();
|
||||||
|
$.fn.editable.defaults.success = function (response, newValue) {
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
$(context).find('#' + key).once('selectize-editable-init').each(function () {
|
||||||
|
var $item = $(this);
|
||||||
|
|
||||||
|
$item.selectize({
|
||||||
|
// General options.
|
||||||
|
items: item.options.items ? item.options.items : [],
|
||||||
|
delimiter: item.options.delimiter ? item.options.delimiter : ',',
|
||||||
|
diacritics: item.options.diacritics ? item.options.diacritics : false,
|
||||||
|
create: item.options.create ? item.options.create : false,
|
||||||
|
createOnBlur: item.options.createOnBlur ? item.options.createOnBlur : false,
|
||||||
|
highlight: item.options.highlight ? item.options.highlight : false,
|
||||||
|
persist: item.options.persist ? item.options.persist : false,
|
||||||
|
openOnFocus: item.options.openOnFocus ? item.options.openOnFocus : false,
|
||||||
|
maxOptions: item.options.maxOptions ? item.options.maxOptions : null,
|
||||||
|
maxItems: item.options.maxItems ? item.options.maxItems : null,
|
||||||
|
hideSelected: item.options.hideSelected ? item.options.hideSelected : false,
|
||||||
|
closeAfterSelect: item.options.closeAfterSelect ? item.options.closeAfterSelect : false,
|
||||||
|
allowEmptyOption: item.options.allowEmptyOption ? item.options.allowEmptyOption : false,
|
||||||
|
scrollDuration: item.options.scrollDuration ? item.options.scrollDuration : 60,
|
||||||
|
loadThrottle: item.options.loadThrottle ? item.options.loadThrottle : 300,
|
||||||
|
loadingClass: item.options.loadingClass ? item.options.loadingClass : 'loading',
|
||||||
|
preload: item.options.preload ? item.options.preload : false,
|
||||||
|
dropdownParent: item.options.dropdownParent ? item.options.dropdownParent : null,
|
||||||
|
addPrecedence: item.options.addPrecedence ? item.options.addPrecedence : false,
|
||||||
|
selectOnTab: item.options.selectOnTab ? item.options.selectOnTab : false,
|
||||||
|
mode: item.options.mode ? item.options.mode : 'multi',
|
||||||
|
plugins: item.options.plugins ? item.options.plugins : [],
|
||||||
|
|
||||||
|
// Data / Searching.
|
||||||
|
options: item.options.options ? item.options.options : [],
|
||||||
|
valueField: item.options.valueField ? item.options.valueField : 'value',
|
||||||
|
labelField: item.options.labelField ? item.options.labelField : 'label',
|
||||||
|
searchField: item.options.searchField ? item.options.searchField : 'label',
|
||||||
|
|
||||||
|
// Callbacks.
|
||||||
|
load: function (query, callback) {
|
||||||
|
var loadPath = item.options.loadPath ? item.options.loadPath : '';
|
||||||
|
if (loadPath == '') return callback([]);
|
||||||
|
if (!query.length) return callback([]);
|
||||||
|
$.ajax({
|
||||||
|
url: loadPath,
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: {
|
||||||
|
q: query,
|
||||||
|
l: item.options.maxOptions ? item.options.maxOptions : 10
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
callback([]);
|
||||||
|
},
|
||||||
|
success: function (data) {
|
||||||
|
// Update items in options array of this field.
|
||||||
|
item.options.options = data;
|
||||||
|
callback(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$(context).find('#' + key).once('selectize-init').each(function () {
|
||||||
|
var $item = $(this);
|
||||||
|
|
||||||
|
$item.selectize({
|
||||||
|
// General options.
|
||||||
|
items: item.options.items ? item.options.items : [],
|
||||||
|
delimiter: item.options.delimiter ? item.options.delimiter : ',',
|
||||||
|
diacritics: item.options.diacritics ? item.options.diacritics : false,
|
||||||
|
create: item.options.create ? item.options.create : false,
|
||||||
|
createOnBlur: item.options.createOnBlur ? item.options.createOnBlur : false,
|
||||||
|
highlight: item.options.highlight ? item.options.highlight : false,
|
||||||
|
persist: item.options.persist ? item.options.persist : false,
|
||||||
|
openOnFocus: item.options.openOnFocus ? item.options.openOnFocus : false,
|
||||||
|
maxOptions: item.options.maxOptions ? item.options.maxOptions : null,
|
||||||
|
maxItems: item.options.maxItems ? item.options.maxItems : null,
|
||||||
|
hideSelected: item.options.hideSelected ? item.options.hideSelected : false,
|
||||||
|
closeAfterSelect: item.options.closeAfterSelect ? item.options.closeAfterSelect : false,
|
||||||
|
allowEmptyOption: item.options.allowEmptyOption ? item.options.allowEmptyOption : false,
|
||||||
|
scrollDuration: item.options.scrollDuration ? item.options.scrollDuration : 60,
|
||||||
|
loadThrottle: item.options.loadThrottle ? item.options.loadThrottle : 300,
|
||||||
|
loadingClass: item.options.loadingClass ? item.options.loadingClass : 'loading',
|
||||||
|
preload: item.options.preload ? item.options.preload : false,
|
||||||
|
dropdownParent: item.options.dropdownParent ? item.options.dropdownParent : null,
|
||||||
|
addPrecedence: item.options.addPrecedence ? item.options.addPrecedence : false,
|
||||||
|
selectOnTab: item.options.selectOnTab ? item.options.selectOnTab : false,
|
||||||
|
mode: item.options.mode ? item.options.mode : 'multi',
|
||||||
|
plugins: item.options.plugins ? item.options.plugins : [],
|
||||||
|
|
||||||
|
// Data / Searching.
|
||||||
|
options: item.options.options ? item.options.options : [],
|
||||||
|
valueField: item.options.valueField ? item.options.valueField : 'value',
|
||||||
|
labelField: item.options.labelField ? item.options.labelField : 'label',
|
||||||
|
searchField: item.options.searchField ? item.options.searchField : 'label',
|
||||||
|
|
||||||
|
// Callbacks.
|
||||||
|
load: function (query, callback) {
|
||||||
|
var loadPath = item.options.loadPath ? item.options.loadPath : '';
|
||||||
|
if (loadPath == '') return callback([]);
|
||||||
|
if (!query.length) return callback([]);
|
||||||
|
$.ajax({
|
||||||
|
url: loadPath,
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: {
|
||||||
|
q: query,
|
||||||
|
l: item.options.maxOptions ? item.options.maxOptions : 10
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
callback([]);
|
||||||
|
},
|
||||||
|
success: function (data) {
|
||||||
|
// Update items in options array of this field.
|
||||||
|
item.options.options = data;
|
||||||
|
callback(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})(jQuery);
|
Reference in New Issue
Block a user