diff --git a/e107_admin/footer.php b/e107_admin/footer.php
index a388c6773..553339423 100644
--- a/e107_admin/footer.php
+++ b/e107_admin/footer.php
@@ -348,6 +348,10 @@ if (abs($_serverTime - $lastSet) > 120)
// \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);
//
diff --git a/e107_core/templates/footer_default.php b/e107_core/templates/footer_default.php
index b061d1f85..045695121 100644
--- a/e107_core/templates/footer_default.php
+++ b/e107_core/templates/footer_default.php
@@ -326,6 +326,10 @@ e107::getJs()->renderJs('footer', true);
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
e107::getJs()->renderJs('footer_inline', true);
diff --git a/e107_core/templates/membersonly_template.php b/e107_core/templates/membersonly_template.php
index 97a57e312..e2010fe27 100755
--- a/e107_core/templates/membersonly_template.php
+++ b/e107_core/templates/membersonly_template.php
@@ -36,7 +36,7 @@ $MEMBERSONLY_END = "
";
";
- $MEMBERSONLY_TEMPLATE['default']['footer'] = "";
diff --git a/e107_handlers/e107_class.php b/e107_handlers/e107_class.php
index a71ca63d7..4c51a853e 100644
--- a/e107_handlers/e107_class.php
+++ b/e107_handlers/e107_class.php
@@ -1668,6 +1668,10 @@ class e107
switch ($type)
{
+ case 'settings':
+ $jshandler->jsSettings($data);
+ break;
+
case 'core':
// data is e.g. 'core/tabs.js'
if(null !== $zone) $jshandler->requireCoreLib($data, $zone);
diff --git a/e107_handlers/e_parse_class.php b/e107_handlers/e_parse_class.php
index 76e3b6629..4ce2f1b4a 100644
--- a/e107_handlers/e_parse_class.php
+++ b/e107_handlers/e_parse_class.php
@@ -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.
*
diff --git a/e107_handlers/form_handler.php b/e107_handlers/form_handler.php
index f5104504d..c88d58166 100644
--- a/e107_handlers/form_handler.php
+++ b/e107_handlers/form_handler.php
@@ -422,109 +422,20 @@ class e_form
e107::css('core', 'selectize/css/selectize.bootstrap2.css', 'jquery');
}
- $ac = $options['selectize'];
- $fieldID = vartrue($options['id'], $this->name2id($name));
+ // Load selectize behavior.
+ e107::js('core', 'selectize/js/selectize.init.js', 'jquery');
- // TODO: better method to create suffix as unique identifier.
- $optionSuffix = $fieldID . vartrue($options['selectize']['e_editable']);
- $optionSuffix = md5($optionSuffix);
+ $jsSettings = array(
+ 'id' => vartrue($options['id'], $this->name2id($name)),
+ '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
- // the latest default values, because if the selectize() would be reinitialized, e.g. in x-editable popover,
- // 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 . "});");
- }
+ // Merge field settings with other selectize field settings.
+ e107::js('settings', array('selectize' => array($jsSettings)));
}
// TODO: remove typeahead.
@@ -3801,9 +3712,13 @@ class e_form
// Inline Editing.
if(!vartrue($attributes['noedit']) && vartrue($parms['editable']) && !vartrue($parms['link'])) // avoid bad markup, better solution coming up
{
- $tpl = $this->userpicker($field, '', $ttl, $id, array('selectize' => array('e_editable' => $field . '_' . $row_id)));
+ // Need a Unique Field ID to store field settings using e107::js('settings').
+ $fieldID = $this->name2id($field . '_' . microtime(true));
+ // Unique ID for each rows.
+ $eEditableID = $this->name2id($fieldID . '_' . $row_id);
+ $tpl = $this->userpicker($field, '', $ttl, $id, array('id' => $fieldID, 'selectize' => array('e_editable' => $eEditableID)));
$mode = preg_replace('/[^\w]/', '', vartrue($_GET['mode'], ''));
- $value = "" . $ttl . "";
+ $value = "" . $ttl . "";
}
break;
diff --git a/e107_handlers/js_manager.php b/e107_handlers/js_manager.php
index 9536606b1..c047f1d4b 100644
--- a/e107_handlers/js_manager.php
+++ b/e107_handlers/js_manager.php
@@ -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.3/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/themes/base/jquery-ui.css",
@@ -66,6 +69,15 @@ class e_jsmanager
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
@@ -243,6 +255,9 @@ class e_jsmanager
{
$this->_libraries['jquery'] = array(
"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/themes/smoothness/jquery-ui.min.css"
);
@@ -634,6 +649,18 @@ class e_jsmanager
$this->addJs('footer_inline', $js_content, $priority);
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)
@@ -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!
// 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);
foreach ($file_path as $fp => $loc)
@@ -960,6 +987,11 @@ class e_jsmanager
return $this;
break;
+ case 'settings':
+ $this->_e_js_settings = array_merge_recursive($this->_e_js_settings, $file_path);
+ return $this;
+ break;
+
default:
return $this;
break;
@@ -985,7 +1017,7 @@ class e_jsmanager
* @param boolean $return
* @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)
{
@@ -994,6 +1026,15 @@ class e_jsmanager
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 '';
+ echo "\n";
+ break;
+
case 'framework': // CDN frameworks - rendered before consolidation script (if enabled)
$fw = array();
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
*
diff --git a/e107_web/js/core/all.jquery.js b/e107_web/js/core/all.jquery.js
index 07ab2da55..9f27ee9b4 100644
--- a/e107_web/js/core/all.jquery.js
+++ b/e107_web/js/core/all.jquery.js
@@ -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({
- dataFilter: function(data, type) {
- if(type != 'json' || !data) return data;
+ dataFilter: function (data, type) {
+ if (type != 'json' || !data) {
+ return data;
+ }
return data.replace(/^\/\*-secure-([\s\S]*)\*\/\s*$/, '$1');
},
cache: false // Was Really NEeded!
diff --git a/e107_web/js/selectize/js/selectize.init.js b/e107_web/js/selectize/js/selectize.init.js
new file mode 100644
index 000000000..83e0825b5
--- /dev/null
+++ b/e107_web/js/selectize/js/selectize.init.js
@@ -0,0 +1,130 @@
+(function ($) {
+
+ /**
+ * Behavior to initialize click event on inline edit (selectize) fields.
+ *
+ * @type {{attach: e107.behaviors.selectizeEditableInit.attach}}
+ */
+ e107.behaviors.selectizeEditableInit = {
+ attach: function (context, settings) {
+ if (e107.settings.selectize) {
+ $.each(e107.settings.selectize, function (index, item) {
+ // 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 () {
+ // After inline editing popup opened, run behaviors to initialize selectize.js.
+ e107.attachBehaviors();
+ }, 300);
+ });
+ });
+ }
+ });
+ }
+ }
+ };
+
+ /**
+ * 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) {
+ $(context).find('#' + item.id).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.
+ e107.settings.selectize[index].options.options = data;
+ callback(data);
+ }
+ });
+ }
+ });
+ });
+
+ });
+ }
+ }
+ };
+
+})(jQuery);