mirror of
https://github.com/Piwigo/Piwigo.git
synced 2026-05-06 13:32:52 +02:00
remplace FCBKcomplete by TokenInput
git-svn-id: http://piwigo.org/svn/trunk@10970 68402e56-0260-453c-a942-63ccdbb3a9ee
This commit is contained in:
@@ -2106,8 +2106,8 @@ function get_fckb_taglist($query)
|
||||
array_push(
|
||||
$taglist,
|
||||
array(
|
||||
'key' => $row['tag_name'],
|
||||
'value' => '~~'.$row['tag_id'].'~~',
|
||||
'name' => $row['tag_name'],
|
||||
'id' => '~~'.$row['tag_id'].'~~',
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -2123,6 +2123,7 @@ function get_fckb_tag_ids($raw_tags)
|
||||
// or "1234" (numeric characters only)
|
||||
|
||||
$tag_ids = array();
|
||||
$raw_tags = explode(',',$raw_tags);
|
||||
|
||||
foreach ($raw_tags as $raw_tag)
|
||||
{
|
||||
|
||||
@@ -5,21 +5,26 @@
|
||||
pwg_initialization_datepicker("#date_creation_day", "#date_creation_month", "#date_creation_year", "#date_creation_linked_date", "#date_creation_action_set");
|
||||
{/literal}{/footer_script}
|
||||
|
||||
{combine_script id='jquery.fcbkcomplete' load='footer' require='jquery' path='themes/default/js/plugins/jquery.fcbkcomplete.js'}
|
||||
{combine_script id='jquery.tokeninput' load='footer' require='jquery' path='themes/default/js/plugins/jquery.tokeninput.js'}
|
||||
{combine_script id='jquery.progressBar' load='footer' path='themes/default/js/plugins/jquery.progressbar.min.js'}
|
||||
{combine_script id='jquery.ajaxmanager' load='footer' path='themes/default/js/plugins/jquery.ajaxmanager.js'}
|
||||
|
||||
{footer_script require='jquery.fcbkcomplete'}{literal}
|
||||
{footer_script require='jquery.tokeninput'}{literal}
|
||||
jQuery(document).ready(function() {
|
||||
jQuery("#tags").fcbkcomplete({
|
||||
json_url: "admin.php?fckb_tags=1",
|
||||
cache: false,
|
||||
filter_case: false,
|
||||
filter_hide: true,
|
||||
firstselected: true,
|
||||
filter_selected: true,
|
||||
maxitems: 100,
|
||||
newel: true
|
||||
jQuery.getJSON('admin.php?fckb_tags=1', function(data) {
|
||||
jQuery("#tags").tokenInput(
|
||||
data,
|
||||
{
|
||||
{/literal}
|
||||
hintText: '{'Type in a search term'|@translate}',
|
||||
noResultsText: '{'No results'|@translate}',
|
||||
searchingText: '{'Searching...'|@translate}',
|
||||
animateDropdown: false,
|
||||
preventDuplicates: true,
|
||||
allowCreation: true
|
||||
{literal}
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
{/literal}{/footer_script}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
{include file='include/datepicker.inc.tpl'}
|
||||
{include file='include/colorbox.inc.tpl'}
|
||||
|
||||
{combine_script id='jquery.fcbkcomplete' load='async' require='jquery' path='themes/default/js/plugins/jquery.fcbkcomplete.js'}
|
||||
{footer_script require='jquery.fcbkcomplete'}
|
||||
{combine_script id='jquery.tokeninput' load='async' require='jquery' path='themes/default/js/plugins/jquery.tokeninput.js'}
|
||||
{footer_script require='jquery.tokeninput'}
|
||||
var tag_boxes_selector = "";
|
||||
{foreach from=$elements item=element name=element}
|
||||
{if $smarty.foreach.element.first}
|
||||
@@ -15,16 +15,21 @@ prefix = ", ";
|
||||
{/foreach}
|
||||
{literal}
|
||||
jQuery(document).ready(function() {
|
||||
$(tag_boxes_selector).fcbkcomplete({
|
||||
json_url: "admin.php?fckb_tags=1",
|
||||
cache: false,
|
||||
filter_case: false,
|
||||
filter_hide: true,
|
||||
firstselected: true,
|
||||
filter_selected: true,
|
||||
maxitems: 100,
|
||||
newel: true
|
||||
});
|
||||
jQuery.getJSON('admin.php?fckb_tags=1', function(data) {
|
||||
jQuery(tag_boxes_selector).tokenInput(
|
||||
data,
|
||||
{
|
||||
{/literal}
|
||||
hintText: '{'Type in a search term'|@translate}',
|
||||
noResultsText: '{'No results'|@translate}',
|
||||
searchingText: '{'Searching...'|@translate}',
|
||||
animateDropdown: false,
|
||||
preventDuplicates: true,
|
||||
allowCreation: true
|
||||
{literal}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$("a.preview-box").colorbox();
|
||||
});
|
||||
@@ -112,7 +117,7 @@ jQuery(document).ready(function() {
|
||||
|
||||
<select id="tags-{$element.ID}" name="tags-{$element.ID}">
|
||||
{foreach from=$element.TAGS item=tag}
|
||||
<option value="{$tag.value}" class="selected">{$tag.key}</option>
|
||||
<option value="{$tag.id}" class="selected">{$tag.name}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
|
||||
|
||||
@@ -2,19 +2,24 @@
|
||||
{include file='include/dbselect.inc.tpl'}
|
||||
{include file='include/datepicker.inc.tpl'}
|
||||
|
||||
{combine_script id='jquery.fcbkcomplete' load='async' require='jquery' path='themes/default/js/plugins/jquery.fcbkcomplete.js'}
|
||||
{footer_script require='jquery.fcbkcomplete'}{literal}
|
||||
{combine_script id='jquery.tokeninput' load='async' require='jquery' path='themes/default/js/plugins/jquery.tokeninput.js'}
|
||||
{footer_script require='jquery.tokeninput'}{literal}
|
||||
jQuery(document).ready(function() {
|
||||
jQuery("#tags").fcbkcomplete({
|
||||
json_url: "admin.php?fckb_tags=1",
|
||||
cache: false,
|
||||
filter_case: false,
|
||||
filter_hide: true,
|
||||
firstselected: true,
|
||||
filter_selected: true,
|
||||
maxitems: 100,
|
||||
newel: true
|
||||
});
|
||||
jQuery.getJSON('admin.php?fckb_tags=1', function(data) {
|
||||
jQuery("#tags").tokenInput(
|
||||
data,
|
||||
{
|
||||
{/literal}
|
||||
hintText: '{'Type in a search term'|@translate}',
|
||||
noResultsText: '{'No results'|@translate}',
|
||||
searchingText: '{'Searching...'|@translate}',
|
||||
animateDropdown: false,
|
||||
preventDuplicates: true,
|
||||
allowCreation: true
|
||||
{literal}
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
{/literal}{/footer_script}
|
||||
|
||||
@@ -137,7 +142,7 @@ pwg_initialization_datepicker("#date_creation_day", "#date_creation_month", "#da
|
||||
<td>
|
||||
<select id="tags" name="tags">
|
||||
{foreach from=$tags item=tag}
|
||||
<option value="{$tag.value}" class="selected">{$tag.key}</option>
|
||||
<option value="{$tag.id}" class="selected">{$tag.name}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</td>
|
||||
|
||||
@@ -585,50 +585,6 @@ img.ui-datepicker-trigger {
|
||||
margin:-3px 5px 2px 5px;
|
||||
}
|
||||
|
||||
/* jQuery FCBKcomplete */
|
||||
/* TextboxList sample CSS */
|
||||
ul.holder { margin: 0; border: 1px solid #999; overflow: hidden; height: auto !important; height: 1%; padding: 4px 5px 0; }
|
||||
*:first-child+html ul.holder { padding-bottom: 2px; } * html ul.holder { padding-bottom: 2px; } /* ie7 and below */
|
||||
ul.holder li { float: left; list-style-type: none; margin: 0 5px 4px 0; white-space:nowrap;}
|
||||
ul.holder li.bit-box, ul.holder li.bit-input input { font: 11px "Lucida Grande", "Verdana"; }
|
||||
ul.holder li.bit-box { -moz-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; border: 1px solid #CAD8F3; background: #DEE7F8; padding: 1px 5px 2px; }
|
||||
ul.holder li.bit-box-focus { border-color: #598BEC; background: #598BEC; color: #fff; }
|
||||
ul.holder li.bit-input input { width: auto; overflow:visible; margin: 0; border: 0px; outline: 0; padding: 3px 0px 2px; } /* no left/right padding here please */
|
||||
ul.holder li.bit-input input.smallinput { width: 20px; }
|
||||
|
||||
/* Facebook demo CSS */
|
||||
#add { border: 1px solid #999; width: 550px; margin: 50px; padding: 20px 30px 10px; }
|
||||
form ol li { list-style-type: none; }
|
||||
form ol { font: 11px "Lucida Grande", "Verdana"; margin: 0; padding: 0; }
|
||||
form ol li.input-text { margin-bottom: 10px; list-style-type: none; padding-bottom: 10px; }
|
||||
form ol li.input-text label { font-weight: bold; cursor: pointer; display: block; font-size: 13px; margin-bottom: 10px; }
|
||||
form ol li.input-text input { width: 500px; padding: 5px 5px 6px; font: 11px "Lucida Grande", "Verdana"; border: 1px solid #999; }
|
||||
form ul.holder { width: 500px; }
|
||||
form ul { margin: 0 !important }
|
||||
ul.holder li.bit-box, #apple-list ul.holder li.bit-box { padding-right: 15px; position: relative; z-index:1000;}
|
||||
#apple-list ul.holder li.bit-input { margin: 0; }
|
||||
#apple-list ul.holder li.bit-input input.smallinput { width: 5px; }
|
||||
ul.holder li.bit-hover { background: #BBCEF1; border: 1px solid #6D95E0; }
|
||||
ul.holder li.bit-box-focus { border-color: #598BEC; background: #598BEC; color: #fff; }
|
||||
ul.holder li.bit-box a.closebutton { position: absolute; right: 4px; top: 5px; display: block; width: 7px; height: 7px; font-size: 1px; background: url(icon/fcbkcomplete_close.gif); }
|
||||
ul.holder li.bit-box a.closebutton:hover { background-position: 7px; }
|
||||
ul.holder li.bit-box-focus a.closebutton, ul.holder li.bit-box-focus a.closebutton:hover { background-position: bottom; }
|
||||
|
||||
/* Autocompleter */
|
||||
|
||||
.facebook-auto { display: none; position: absolute; width: 512px; background: #eee; }
|
||||
.facebook-auto .default { padding: 5px 7px; border: 1px solid #ccc; border-width: 0 1px 1px;font-family:"Lucida Grande","Verdana"; font-size:11px; }
|
||||
.facebook-auto ul { display: none; margin: 0; padding: 0; overflow: auto; position:absolute; z-index:9999}
|
||||
.facebook-auto ul li { padding: 5px 12px; z-index: 1000; cursor: pointer; margin: 0; list-style-type: none; border: 1px solid #ccc; border-width: 0 1px 1px; font: 11px "Lucida Grande", "Verdana"; background-color: #eee }
|
||||
.facebook-auto ul li em { font-weight: bold; font-style: normal; background: #ccc; }
|
||||
.facebook-auto ul li.auto-focus { background: #4173CC; color: #fff; }
|
||||
.facebook-auto ul li.auto-focus em { background: none; }
|
||||
.deleted { background-color:#4173CC !important; color:#ffffff !important;}
|
||||
.hidden { display:none;}
|
||||
|
||||
#demo ul.holder li.bit-input input { padding: 2px 0 1px; border: 1px solid #999; }
|
||||
.ie6fix {height:1px;width:1px; position:absolute;top:0px;left:0px;z-index:1;}
|
||||
|
||||
/* Add photos, direct mode */
|
||||
#uploadBoxes P {
|
||||
margin:0;
|
||||
@@ -1056,4 +1012,22 @@ LEGEND {
|
||||
#batchManagerGlobal a.removeFilter:hover {background: url(icon/remove_filter_hover.png); border:none;}
|
||||
#batchManagerGlobal .removeFilter span {display:none}
|
||||
#batchManagerGlobal #applyFilterBlock {margin-top:20px;}
|
||||
#batchManagerGlobal .useFilterCheckbox {display:none}
|
||||
#batchManagerGlobal .useFilterCheckbox {display:none}
|
||||
|
||||
|
||||
/* TokenInput (with Facebook style) */
|
||||
ul.token-input-list {overflow: hidden; height: auto !important; height: 1%;width: 400px;border: 1px solid #8496ba;cursor: text;font-size: 12px;font-family: Verdana;min-height: 1px;z-index: 999;margin: 0;padding: 0;background-color: #fff;list-style-type: none;clear: left;}
|
||||
ul.token-input-list li input {border: 0;width: 100px;padding: 3px 8px;background-color: white;margin: 2px 0;-webkit-appearance: caret;}
|
||||
li.token-input-token {overflow: hidden; height: auto !important; height: 15px;margin: 3px;padding: 1px 3px;background-color: #eff2f7;color: #000;cursor: default;border: 1px solid #ccd5e4;font-size: 11px;border-radius: 5px;-moz-border-radius: 5px;-webkit-border-radius: 5px;float: left;white-space: nowrap;}
|
||||
li.token-input-token p {display: inline;padding: 0;margin: 0;}
|
||||
li.token-input-token span {color: #a6b3cf;margin-left: 5px;font-weight: bold;cursor: pointer;}
|
||||
li.token-input-selected-token {background-color: #5670a6;border: 1px solid #3b5998;color: #fff;}
|
||||
li.token-input-input-token {float: left;margin: 0;padding: 0;list-style-type: none;}
|
||||
div.token-input-dropdown {position: absolute;width: 400px;background-color: #fff;overflow: hidden;border-left: 1px solid #ccc;border-right: 1px solid #ccc;border-bottom: 1px solid #ccc;cursor: default;font-size: 11px;font-family: Verdana;z-index: 1;}
|
||||
div.token-input-dropdown p {margin: 0;padding: 5px;font-weight: bold;color: #777;}
|
||||
div.token-input-dropdown ul {margin: 0;padding: 0;}
|
||||
div.token-input-dropdown ul li {background-color: #fff;padding: 3px;margin: 0;list-style-type: none;}
|
||||
div.token-input-dropdown ul li.token-input-dropdown-item {background-color: #fff;}
|
||||
div.token-input-dropdown ul li.token-input-dropdown-item2 {background-color: #fff;}
|
||||
div.token-input-dropdown ul li em {font-weight: bold;font-style: normal;}
|
||||
div.token-input-dropdown ul li.token-input-selected-dropdown-item {background-color: #3b5998;color: #fff;}
|
||||
@@ -445,6 +445,7 @@ $lang['No photo in the current set.'] = 'No photo in the current set.';
|
||||
$lang['No photo in this album'] = "No photo in this album";
|
||||
$lang['No photo selected, %d photos in current set'] = 'No photo selected, %d photos in current set';
|
||||
$lang['No photo selected, no action possible.'] = 'No photo selected, no action possible.';
|
||||
$lang['No results'] = "No results";
|
||||
$lang['No user to send notifications by mail.'] = "No user to be notified by mail.";
|
||||
$lang['no write access'] = "no write access";
|
||||
$lang['none'] = "none";
|
||||
@@ -579,6 +580,7 @@ $lang['Save page visits by guests'] = "Record pages visited by guests";
|
||||
$lang['Save page visits by users'] = "Record pages visited by users";
|
||||
$lang['Save Settings'] = 'Save Settings';
|
||||
$lang['Save to permalink history'] = "Save to permalinks history";
|
||||
$lang['Searching...'] = "Searching...";
|
||||
$lang['Search for new images in the directories'] = "Search for new images in the directories";
|
||||
$lang['Section'] = "Section";
|
||||
$lang['See you soon,'] = "See you soon,";
|
||||
@@ -695,6 +697,7 @@ $lang['Tools'] = "Tools";
|
||||
$lang['total time'] = "total time";
|
||||
$lang['Type here the author name'] = 'Type here the author name';
|
||||
$lang['Type here the title'] = 'Type here the title';
|
||||
$lang['Type in a search term'] = "Type in a search term";
|
||||
$lang['Unable to check for upgrade.'] = "Unable to check for upgrade.";
|
||||
$lang['Uncheck all'] = "Uncheck all";
|
||||
$lang['Uninstall'] = "Uninstall";
|
||||
|
||||
@@ -842,4 +842,7 @@ $lang['Follow Orientation'] = "Respecter l'orientation";
|
||||
$lang['If you want to regenerate thumbnails, please go to the <a href="%s">Batch Manager</a>.'] = 'Si vous voulez régénérer des miniatures, merci de vous rendre dans la <a href="%s">Gestion par lot</a>.';
|
||||
$lang['Graphics Library'] = 'Bibliothèque graphique';
|
||||
$lang['Show menubar'] = "Afficher le menu";
|
||||
$lang['No results'] = "Pas de résultat";
|
||||
$lang['Type in a search term'] = "Entrez un terme de recherche";
|
||||
$lang['Searching...'] = "Recherche...";
|
||||
?>
|
||||
@@ -1044,6 +1044,7 @@ if ($metadata_showable and pwg_get_session_var('show_metadata') <> null )
|
||||
$themeconf = $template->get_template_vars('themeconf');
|
||||
if ($conf['picture_menu'] AND (!isset($themeconf['hide_menu_on']) OR !in_array('thePicturePage', $themeconf['hide_menu_on'])))
|
||||
{
|
||||
if (!isset($page['start'])) $page['start'] = 0;
|
||||
include( PHPWG_ROOT_PATH.'include/menubar.inc.php');
|
||||
if (is_admin()) $template->assign('U_ADMIN', $url_admin); // overwrited by the menu
|
||||
}
|
||||
|
||||
@@ -1,645 +0,0 @@
|
||||
/**
|
||||
FCBKcomplete 2.7.5
|
||||
- Jquery version required: 1.2.x, 1.3.x, 1.4.x
|
||||
|
||||
Based on TextboxList by Guillermo Rauch http://devthought.com/
|
||||
|
||||
Changelog:
|
||||
- 2.00 new version of fcbkcomplete
|
||||
|
||||
- 2.01 fixed bugs & added features
|
||||
fixed filter bug for preadded items
|
||||
focus on the input after selecting tag
|
||||
the element removed pressing backspace when the element is selected
|
||||
input tag in the control has a border in IE7
|
||||
added iterate over each match and apply the plugin separately
|
||||
set focus on the input after selecting tag
|
||||
|
||||
- 2.02 fixed fist element selected bug
|
||||
fixed defaultfilter error bug
|
||||
|
||||
- 2.5 removed selected="selected" attribute due ie bug
|
||||
element search algorithm changed
|
||||
better performance fix added
|
||||
fixed many small bugs
|
||||
onselect event added
|
||||
onremove event added
|
||||
|
||||
- 2.6 ie6/7 support fix added
|
||||
added new public method addItem due request
|
||||
added new options "firstselected" that you can set true/false to select first element on dropdown list
|
||||
autoexpand input element added
|
||||
removeItem bug fixed
|
||||
and many more bug fixed
|
||||
fixed public method to use it $("elem").trigger("addItem",[{"title": "test", "value": "test"}]);
|
||||
|
||||
- 2.7 jquery 1.4 compability
|
||||
item lock possability added by adding locked class to preadded option <option value="value" class="selected locked">text</option>
|
||||
maximum item that can be added
|
||||
|
||||
- 2.7.1 bug fixed
|
||||
ajax delay added thanks to http://github.com/dolorian
|
||||
|
||||
- 2.7.2 some minor bug fixed
|
||||
minified version recompacted due some problems
|
||||
|
||||
- 2.7.3 event call fixed thanks to William Parry <williamparry!at!gmail.com>
|
||||
|
||||
- 2.7.4 standart event change call added on addItem, removeItem
|
||||
preSet also check if item have "selected" attribute
|
||||
addItem minor fix
|
||||
|
||||
- 2.7.5 event call removeItem fixed
|
||||
new public method destroy added needed to remove fcbkcomplete element from dome
|
||||
|
||||
*/
|
||||
/* Coded by: emposha <admin@emposha.com> */
|
||||
/* Copyright: Emposha.com <http://www.emposha.com> - Distributed under MIT - Keep this message! */
|
||||
|
||||
/**
|
||||
* json_url - url to fetch json object
|
||||
* cache - use cache
|
||||
* height - maximum number of element shown before scroll will apear
|
||||
* newel - show typed text like a element
|
||||
* firstselected - automaticly select first element from dropdown
|
||||
* filter_case - case sensitive filter
|
||||
* filter_selected - filter selected items from list
|
||||
* complete_text - text for complete page
|
||||
* maxshownitems - maximum numbers that will be shown at dropdown list (less better performance)
|
||||
* onselect - fire event on item select
|
||||
* onremove - fire event on item remove
|
||||
* maxitimes - maximum items that can be added
|
||||
* delay - delay between ajax request (bigger delay, lower server time request)
|
||||
* addontab - add first visible element on tab or enter hit
|
||||
* attachto - after this element fcbkcomplete insert own elements
|
||||
*/
|
||||
jQuery(function($) {
|
||||
$.fn.fcbkcomplete = function(opt) {
|
||||
return this.each(function() {
|
||||
function init() {
|
||||
createFCBK();
|
||||
preSet();
|
||||
addInput(0);
|
||||
}
|
||||
|
||||
function createFCBK() {
|
||||
element.hide();
|
||||
element.attr("multiple", "multiple");
|
||||
if (element.attr("name").indexOf("[]") == -1) {
|
||||
element.attr("name", element.attr("name") + "[]");
|
||||
}
|
||||
|
||||
holder = $(document.createElement("ul"));
|
||||
holder.attr("class", "holder");
|
||||
|
||||
if (options.attachto) {
|
||||
if (typeof(options.attachto) == "object") {
|
||||
options.attachto.append(holder);
|
||||
}
|
||||
else {
|
||||
$(options.attachto).append(holder);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
element.after(holder);
|
||||
}
|
||||
|
||||
complete = $(document.createElement("div"));
|
||||
complete.addClass("facebook-auto");
|
||||
complete.append('<div class="default">' + options.complete_text + "</div>");
|
||||
complete.hover(function() {options.complete_hover = 0;}, function() {options.complete_hover = 1;});
|
||||
|
||||
feed = $(document.createElement("ul"));
|
||||
feed.attr("id", elemid + "_feed");
|
||||
|
||||
complete.prepend(feed);
|
||||
holder.after(complete);
|
||||
feed.css("width", complete.width());
|
||||
}
|
||||
|
||||
function preSet() {
|
||||
element.children("option").each(function(i, option) {
|
||||
option = $(option);
|
||||
if (option.hasClass("selected")) {
|
||||
addItem(option.text(), option.val(), true, option.hasClass("locked"));
|
||||
option.attr("selected", "selected");
|
||||
}
|
||||
cache.push({
|
||||
key: option.text(),
|
||||
value: option.val()
|
||||
});
|
||||
search_string += "" + (cache.length - 1) + ":" + option.text() + ";";
|
||||
});
|
||||
}
|
||||
|
||||
//public method to add new item
|
||||
$(this).bind("addItem",
|
||||
function(event, data) {
|
||||
addItem(data.title, data.value, 0, 0, 0);
|
||||
});
|
||||
|
||||
//public method to remove item
|
||||
$(this).bind("removeItem",
|
||||
function(event, data) {
|
||||
var item = holder.children('li[rel=' + data.value + ']');
|
||||
if (item.length) {
|
||||
removeItem(item);
|
||||
}
|
||||
});
|
||||
|
||||
//public method to remove item
|
||||
$(this).bind("destroy",
|
||||
function(event, data) {
|
||||
holder.remove();
|
||||
complete.remove();
|
||||
element.show();
|
||||
});
|
||||
|
||||
function addItem(title, value, preadded, locked, focusme) {
|
||||
if (!maxItems()) {
|
||||
return false;
|
||||
}
|
||||
var li = document.createElement("li");
|
||||
var txt = document.createTextNode(title);
|
||||
var aclose = document.createElement("a");
|
||||
var liclass = "bit-box" + (locked ? " locked": "");
|
||||
$(li).attr({
|
||||
"class": liclass,
|
||||
"rel": value
|
||||
});
|
||||
$(li).prepend(txt);
|
||||
$(aclose).attr({
|
||||
"class": "closebutton",
|
||||
"href": "#"
|
||||
});
|
||||
|
||||
li.appendChild(aclose);
|
||||
holder.append(li);
|
||||
|
||||
$(aclose).click(function() {
|
||||
removeItem($(this).parent("li"));
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!preadded) {
|
||||
$("#" + elemid + "_annoninput").remove();
|
||||
var _item;
|
||||
addInput(focusme);
|
||||
if (element.children("option[value=" + value + "]").length) {
|
||||
_item = element.children("option[value=" + value + "]");
|
||||
_item.get(0).setAttribute("selected", "selected");
|
||||
_item.attr("selected", "selected");
|
||||
if (!_item.hasClass("selected")) {
|
||||
_item.addClass("selected");
|
||||
}
|
||||
}
|
||||
else{
|
||||
var _item = $(document.createElement("option"));
|
||||
_item.attr("value", value).get(0).setAttribute("selected", "selected");
|
||||
_item.attr("value", value).attr("selected", "selected");
|
||||
_item.attr("value", value).addClass("selected");
|
||||
_item.text(title);
|
||||
element.append(_item);
|
||||
}
|
||||
if (options.onselect) {
|
||||
funCall(options.onselect, _item)
|
||||
}
|
||||
element.change();
|
||||
}
|
||||
holder.children("li.bit-box.deleted").removeClass("deleted");
|
||||
feed.hide();
|
||||
}
|
||||
|
||||
function removeItem(item) {
|
||||
|
||||
if (!item.hasClass('locked')) {
|
||||
item.fadeOut("fast");
|
||||
if (options.onremove) {
|
||||
var _item = element.children("option[value=" + item.attr("rel") + "]");
|
||||
funCall(options.onremove, _item)
|
||||
}
|
||||
element.children('option[value="' + item.attr("rel") + '"]').removeAttr("selected").removeClass("selected");
|
||||
item.remove();
|
||||
element.change();
|
||||
deleting = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function addInput(focusme) {
|
||||
var li = $(document.createElement("li"));
|
||||
var input = $(document.createElement("input"));
|
||||
var getBoxTimeout = 0;
|
||||
|
||||
li.attr({
|
||||
"class": "bit-input",
|
||||
"id": elemid + "_annoninput"
|
||||
});
|
||||
input.attr({
|
||||
"type": "text",
|
||||
"class": "maininput",
|
||||
"size": "1"
|
||||
});
|
||||
holder.append(li.append(input));
|
||||
|
||||
input.focus(function() {
|
||||
complete.fadeIn("fast");
|
||||
});
|
||||
|
||||
input.blur(function() {
|
||||
if (options.complete_hover) {
|
||||
complete.fadeOut("fast");
|
||||
}
|
||||
else {
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
|
||||
holder.click(function() {
|
||||
input.focus();
|
||||
if (feed.length && input.val().length) {
|
||||
feed.show();
|
||||
}
|
||||
else{
|
||||
feed.hide();
|
||||
complete.children(".default").show();
|
||||
}
|
||||
});
|
||||
|
||||
input.keypress(function(event) {
|
||||
if (event.keyCode == 13) {
|
||||
return false;
|
||||
}
|
||||
//auto expand input
|
||||
input.attr("size", input.val().length + 1);
|
||||
});
|
||||
|
||||
input.keydown(function(event) {
|
||||
//prevent to enter some bad chars when input is empty
|
||||
if (event.keyCode == 191) {
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
input.keyup(function(event) {
|
||||
var etext = xssPrevent(input.val());
|
||||
|
||||
if (event.keyCode == 8 && etext.length == 0) {
|
||||
feed.hide();
|
||||
if (!holder.children("li.bit-box:last").hasClass('locked')) {
|
||||
if (holder.children("li.bit-box.deleted").length == 0) {
|
||||
holder.children("li.bit-box:last").addClass("deleted");
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
if (deleting) {
|
||||
return;
|
||||
}
|
||||
deleting = 1;
|
||||
holder.children("li.bit-box.deleted").fadeOut("fast",
|
||||
function() {
|
||||
removeItem($(this));
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event.keyCode != 40 && event.keyCode != 38 && event.keyCode!=37 && event.keyCode!=39 && etext.length != 0) {
|
||||
counter = 0;
|
||||
|
||||
if (options.json_url) {
|
||||
if (options.cache && json_cache) {
|
||||
addMembers(etext);
|
||||
bindEvents();
|
||||
}
|
||||
else{
|
||||
getBoxTimeout++;
|
||||
var getBoxTimeoutValue = getBoxTimeout;
|
||||
setTimeout(function() {
|
||||
if (getBoxTimeoutValue != getBoxTimeout) return;
|
||||
$.getJSON(options.json_url, {tag: etext},
|
||||
function(data) {
|
||||
addMembers(etext, data);
|
||||
json_cache = true;
|
||||
bindEvents();
|
||||
});
|
||||
},
|
||||
options.delay);
|
||||
}
|
||||
}
|
||||
else{
|
||||
addMembers(etext);
|
||||
bindEvents();
|
||||
}
|
||||
complete.children(".default").hide();
|
||||
feed.show();
|
||||
}
|
||||
});
|
||||
if (focusme) {
|
||||
setTimeout(function() {
|
||||
input.focus();
|
||||
complete.children(".default").show();
|
||||
},
|
||||
1);
|
||||
}
|
||||
}
|
||||
|
||||
function addMembers(etext, data) {
|
||||
feed.html('');
|
||||
|
||||
if (!options.cache && data != null) {
|
||||
cache = new Array();
|
||||
search_string = "";
|
||||
}
|
||||
|
||||
addTextItem(etext);
|
||||
|
||||
if (data != null && data.length) {
|
||||
$.each(data,
|
||||
function(i, val) {
|
||||
cache.push({
|
||||
key: val.key,
|
||||
value: val.value
|
||||
});
|
||||
search_string += "" + (cache.length - 1) + ":" + val.key + ";";
|
||||
});
|
||||
}
|
||||
|
||||
var maximum = options.maxshownitems < cache.length ? options.maxshownitems: cache.length;
|
||||
var filter = "i";
|
||||
if (options.filter_case) {
|
||||
filter = "";
|
||||
}
|
||||
|
||||
var myregexp,
|
||||
match;
|
||||
try{
|
||||
myregexp = eval('/(?:^|;)\\s*(\\d+)\\s*:[^;]*?' + etext + '[^;]*/g' + filter);
|
||||
match = myregexp.exec(search_string);
|
||||
}
|
||||
catch(ex) {
|
||||
};
|
||||
|
||||
var content = '';
|
||||
while (match != null && maximum > 0) {
|
||||
var id = match[1];
|
||||
var object = cache[id];
|
||||
if (options.filter_selected && element.children("option[value=" + object.value + "]").hasClass("selected")) {
|
||||
//nothing here...
|
||||
}
|
||||
else{
|
||||
content += '<li rel="' + object.value + '">' + itemIllumination(object.key, etext) + '</li>';
|
||||
counter++;
|
||||
maximum--;
|
||||
}
|
||||
match = myregexp.exec(search_string);
|
||||
}
|
||||
feed.append(content);
|
||||
|
||||
if (options.firstselected) {
|
||||
focuson = feed.children("li:visible:first");
|
||||
focuson.addClass("auto-focus");
|
||||
}
|
||||
|
||||
if (counter > options.height) {
|
||||
feed.css({
|
||||
"height": (options.height * 24) + "px",
|
||||
"overflow": "auto"
|
||||
});
|
||||
}
|
||||
else{
|
||||
feed.css("height", "auto");
|
||||
}
|
||||
}
|
||||
|
||||
function itemIllumination(text, etext) {
|
||||
if (options.filter_case) {
|
||||
try{
|
||||
eval("var text = text.replace(/(.*)(" + etext + ")(.*)/gi,'$1<em>$2</em>$3');");
|
||||
}
|
||||
catch(ex) {
|
||||
};
|
||||
}
|
||||
else{
|
||||
try{
|
||||
eval("var text = text.replace(/(.*)(" + etext.toLowerCase() + ")(.*)/gi,'$1<em>$2</em>$3');");
|
||||
}
|
||||
catch(ex) {
|
||||
};
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function bindFeedEvent() {
|
||||
feed.children("li").mouseover(function() {
|
||||
feed.children("li").removeClass("auto-focus");
|
||||
$(this).addClass("auto-focus");
|
||||
focuson = $(this);
|
||||
});
|
||||
|
||||
feed.children("li").mouseout(function() {
|
||||
$(this).removeClass("auto-focus");
|
||||
focuson = null;
|
||||
});
|
||||
}
|
||||
|
||||
function removeFeedEvent() {
|
||||
feed.children("li").unbind("mouseover");
|
||||
feed.children("li").unbind("mouseout");
|
||||
feed.mousemove(function() {
|
||||
bindFeedEvent();
|
||||
feed.unbind("mousemove");
|
||||
});
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
var maininput = $("#" + elemid + "_annoninput").children(".maininput");
|
||||
bindFeedEvent();
|
||||
feed.children("li").unbind("mousedown");
|
||||
feed.children("li").mousedown(function() {
|
||||
var option = $(this);
|
||||
addItem(option.text(), option.attr("rel"), 0, 0, 1);
|
||||
feed.hide();
|
||||
complete.hide();
|
||||
});
|
||||
|
||||
maininput.unbind("keydown");
|
||||
maininput.keydown(function(event) {
|
||||
if (event.keyCode == 191) {
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.keyCode != 8) {
|
||||
holder.children("li.bit-box.deleted").removeClass("deleted");
|
||||
}
|
||||
|
||||
if ((event.keyCode == 13 || event.keyCode == 9) && checkFocusOn()) {
|
||||
var option = focuson;
|
||||
addItem(option.text(), option.attr("rel"), 0, 0, 1);
|
||||
complete.hide();
|
||||
event.preventDefault();
|
||||
focuson = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((event.keyCode == 13 || event.keyCode == 9) && !checkFocusOn()) {
|
||||
if (options.newel) {
|
||||
var value = xssPrevent($(this).val());
|
||||
addItem(value, value, 0, 0, 1);
|
||||
complete.hide();
|
||||
event.preventDefault();
|
||||
focuson = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.addontab) {
|
||||
focuson = feed.children("li:visible:first");
|
||||
var option = focuson;
|
||||
addItem(option.text(), option.attr("rel"), 0, 0, 1);
|
||||
complete.hide();
|
||||
event.preventDefault();
|
||||
focuson = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.keyCode == 40) {
|
||||
removeFeedEvent();
|
||||
if (focuson == null || focuson.length == 0) {
|
||||
focuson = feed.children("li:visible:first");
|
||||
feed.get(0).scrollTop = 0;
|
||||
}
|
||||
else{
|
||||
focuson.removeClass("auto-focus");
|
||||
focuson = focuson.nextAll("li:visible:first");
|
||||
var prev = parseInt(focuson.prevAll("li:visible").length, 10);
|
||||
var next = parseInt(focuson.nextAll("li:visible").length, 10);
|
||||
if ((prev > Math.round(options.height / 2) || next <= Math.round(options.height / 2)) && typeof(focuson.get(0)) != "undefined") {
|
||||
feed.get(0).scrollTop = parseInt(focuson.get(0).scrollHeight, 10) * (prev - Math.round(options.height / 2));
|
||||
}
|
||||
}
|
||||
feed.children("li").removeClass("auto-focus");
|
||||
focuson.addClass("auto-focus");
|
||||
}
|
||||
if (event.keyCode == 38) {
|
||||
removeFeedEvent();
|
||||
if (focuson == null || focuson.length == 0) {
|
||||
focuson = feed.children("li:visible:last");
|
||||
feed.get(0).scrollTop = parseInt(focuson.get(0).scrollHeight, 10) * (parseInt(feed.children("li:visible").length, 10) - Math.round(options.height / 2));
|
||||
}
|
||||
else{
|
||||
focuson.removeClass("auto-focus");
|
||||
focuson = focuson.prevAll("li:visible:first");
|
||||
var prev = parseInt(focuson.prevAll("li:visible").length, 10);
|
||||
var next = parseInt(focuson.nextAll("li:visible").length, 10);
|
||||
if ((next > Math.round(options.height / 2) || prev <= Math.round(options.height / 2)) && typeof(focuson.get(0)) != "undefined") {
|
||||
feed.get(0).scrollTop = parseInt(focuson.get(0).scrollHeight, 10) * (prev - Math.round(options.height / 2));
|
||||
}
|
||||
}
|
||||
feed.children("li").removeClass("auto-focus");
|
||||
focuson.addClass("auto-focus");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function maxItems() {
|
||||
if (options.maxitems != 0) {
|
||||
if (holder.children("li.bit-box").length < options.maxitems) {
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addTextItem(value) {
|
||||
if (options.newel && maxItems()) {
|
||||
feed.children("li[fckb=1]").remove();
|
||||
if (value.length == 0) {
|
||||
return;
|
||||
}
|
||||
var li = $(document.createElement("li"));
|
||||
li.attr({
|
||||
"rel": value,
|
||||
"fckb": "1"
|
||||
}).html(value);
|
||||
feed.prepend(li);
|
||||
counter++;
|
||||
}
|
||||
else{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function funCall(func, item) {
|
||||
var _object = "";
|
||||
for (i = 0; i < item.get(0).attributes.length; i++) {
|
||||
if (item.get(0).attributes[i].nodeValue != null) {
|
||||
_object += "\"_" + item.get(0).attributes[i].nodeName + "\": \"" + item.get(0).attributes[i].nodeValue + "\",";
|
||||
}
|
||||
}
|
||||
_object = "{" + _object + " notinuse: 0}";
|
||||
func.call(func, _object);
|
||||
}
|
||||
|
||||
function checkFocusOn() {
|
||||
if (focuson == null) {
|
||||
return false;
|
||||
}
|
||||
if (focuson.length == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function xssPrevent(string) {
|
||||
string = string.replace(/[\"\'][\s]*javascript:(.*)[\"\']/g, "\"\"");
|
||||
string = string.replace(/script(.*)/g, "");
|
||||
string = string.replace(/eval\((.*)\)/g, "");
|
||||
string = string.replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '');
|
||||
return string;
|
||||
}
|
||||
|
||||
var options = $.extend({
|
||||
json_url: null,
|
||||
cache: false,
|
||||
height: "10",
|
||||
newel: false,
|
||||
addontab: false,
|
||||
firstselected: false,
|
||||
filter_case: false,
|
||||
filter_selected: false,
|
||||
complete_text: "Start to type...",
|
||||
maxshownitems: 30,
|
||||
maxitems: 10,
|
||||
onselect: null,
|
||||
onremove: null,
|
||||
attachto: null,
|
||||
delay: 350
|
||||
},
|
||||
opt);
|
||||
|
||||
//system variables
|
||||
var holder = null;
|
||||
var feed = null;
|
||||
var complete = null;
|
||||
var counter = 0;
|
||||
var cache = new Array();
|
||||
var json_cache = false;
|
||||
var search_string = "";
|
||||
var focuson = null;
|
||||
var deleting = 0;
|
||||
var complete_hover = 1;
|
||||
|
||||
var element = $(this);
|
||||
var elemid = element.attr("id");
|
||||
init();
|
||||
|
||||
return this;
|
||||
});
|
||||
};
|
||||
});
|
||||
776
themes/default/js/plugins/jquery.tokeninput.js
Normal file
776
themes/default/js/plugins/jquery.tokeninput.js
Normal file
@@ -0,0 +1,776 @@
|
||||
/**
|
||||
DON'T MAKE AUTOMATIC UPGRADE
|
||||
This is a merged version of :
|
||||
+ https://github.com/gr2m/jquery-tokeninput/
|
||||
+ https://github.com/mistic100/jquery-tokeninput/
|
||||
*/
|
||||
|
||||
/*
|
||||
* jQuery Plugin: Tokenizing Autocomplete Text Entry
|
||||
* Version 1.4.2
|
||||
*
|
||||
* Copyright (c) 2009 James Smith (http://loopj.com)
|
||||
* Licensed jointly under the GPL and MIT licenses,
|
||||
* choose which one suits your project best!
|
||||
*
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
// Default settings
|
||||
var DEFAULT_SETTINGS = {
|
||||
hintText: "Type in a search term",
|
||||
noResultsText: "No results",
|
||||
searchingText: "Searching...",
|
||||
deleteText: "×",
|
||||
searchDelay: 300,
|
||||
minChars: 1,
|
||||
tokenLimit: null,
|
||||
jsonContainer: null,
|
||||
method: "GET",
|
||||
contentType: "json",
|
||||
queryParam: "q",
|
||||
tokenDelimiter: ",",
|
||||
preventDuplicates: false,
|
||||
prePopulate: null,
|
||||
processPrePopulate: false,
|
||||
animateDropdown: true,
|
||||
onResult: null,
|
||||
onAdd: null,
|
||||
onDelete: null,
|
||||
allowCreation: false
|
||||
};
|
||||
|
||||
// Default classes to use when theming
|
||||
var DEFAULT_CLASSES = {
|
||||
tokenList: "token-input-list",
|
||||
token: "token-input-token",
|
||||
tokenDelete: "token-input-delete-token",
|
||||
selectedToken: "token-input-selected-token",
|
||||
highlightedToken: "token-input-highlighted-token",
|
||||
dropdown: "token-input-dropdown",
|
||||
dropdownItem: "token-input-dropdown-item",
|
||||
dropdownItem2: "token-input-dropdown-item2",
|
||||
selectedDropdownItem: "token-input-selected-dropdown-item",
|
||||
inputToken: "token-input-input-token"
|
||||
};
|
||||
|
||||
// Input box position "enum"
|
||||
var POSITION = {
|
||||
BEFORE: 0,
|
||||
AFTER: 1,
|
||||
END: 2
|
||||
};
|
||||
|
||||
// Keys "enum"
|
||||
var KEY = {
|
||||
BACKSPACE: 8,
|
||||
TAB: 9,
|
||||
ENTER: 13,
|
||||
ESCAPE: 27,
|
||||
SPACE: 32,
|
||||
PAGE_UP: 33,
|
||||
PAGE_DOWN: 34,
|
||||
END: 35,
|
||||
HOME: 36,
|
||||
LEFT: 37,
|
||||
UP: 38,
|
||||
RIGHT: 39,
|
||||
DOWN: 40,
|
||||
NUMPAD_ENTER: 108,
|
||||
COMMA: 188
|
||||
};
|
||||
|
||||
|
||||
// Expose the .tokenInput function to jQuery as a plugin
|
||||
$.fn.tokenInput = function (url_or_data, options) {
|
||||
var settings = $.extend({}, DEFAULT_SETTINGS, options || {});
|
||||
|
||||
return this.each(function () {
|
||||
new $.TokenList(this, url_or_data, settings);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// TokenList class for each input
|
||||
$.TokenList = function (input, url_or_data, settings) {
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
|
||||
// Configure the data source
|
||||
if(typeof(url_or_data) === "string") {
|
||||
// Set the url to query against
|
||||
settings.url = url_or_data;
|
||||
|
||||
// Make a smart guess about cross-domain if it wasn't explicitly specified
|
||||
if(settings.crossDomain === undefined) {
|
||||
if(settings.url.indexOf("://") === -1) {
|
||||
settings.crossDomain = false;
|
||||
} else {
|
||||
settings.crossDomain = (location.href.split(/\/+/g)[1] !== settings.url.split(/\/+/g)[1]);
|
||||
}
|
||||
}
|
||||
} else if(typeof(url_or_data) === "object") {
|
||||
// Set the local data to search through
|
||||
settings.local_data = url_or_data;
|
||||
}
|
||||
|
||||
// Build class names
|
||||
if(settings.classes) {
|
||||
// Use custom class names
|
||||
settings.classes = $.extend({}, DEFAULT_CLASSES, settings.classes);
|
||||
} else if(settings.theme) {
|
||||
// Use theme-suffixed default class names
|
||||
settings.classes = {};
|
||||
$.each(DEFAULT_CLASSES, function(key, value) {
|
||||
settings.classes[key] = value + "-" + settings.theme;
|
||||
});
|
||||
} else {
|
||||
settings.classes = DEFAULT_CLASSES;
|
||||
}
|
||||
|
||||
|
||||
// Save the tokens
|
||||
var saved_tokens = [];
|
||||
|
||||
// Keep track of the number of tokens in the list
|
||||
var token_count = 0;
|
||||
|
||||
// Basic cache to save on db hits
|
||||
var cache = new $.TokenList.Cache();
|
||||
|
||||
// Keep track of the timeout, old vals
|
||||
var timeout;
|
||||
var input_val;
|
||||
|
||||
// Create a new text input an attach keyup events
|
||||
var input_box = $("<input type=\"text\" autocomplete=\"off\">")
|
||||
.css({
|
||||
outline: "none"
|
||||
})
|
||||
.focus(function () {
|
||||
if (settings.tokenLimit === null || settings.tokenLimit !== token_count) {
|
||||
show_dropdown_hint();
|
||||
}
|
||||
})
|
||||
.blur(function () {
|
||||
hide_dropdown();
|
||||
})
|
||||
.bind("keyup keydown blur update", resize_input)
|
||||
.keydown(function (event) {
|
||||
var previous_token;
|
||||
var next_token;
|
||||
|
||||
switch(event.keyCode) {
|
||||
case KEY.LEFT:
|
||||
case KEY.RIGHT:
|
||||
case KEY.UP:
|
||||
case KEY.DOWN:
|
||||
if(!$(this).val()) {
|
||||
previous_token = input_token.prev();
|
||||
next_token = input_token.next();
|
||||
|
||||
if((previous_token.length && previous_token.get(0) === selected_token) || (next_token.length && next_token.get(0) === selected_token)) {
|
||||
// Check if there is a previous/next token and it is selected
|
||||
if(event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) {
|
||||
deselect_token($(selected_token), POSITION.BEFORE);
|
||||
} else {
|
||||
deselect_token($(selected_token), POSITION.AFTER);
|
||||
}
|
||||
} else if((event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) && previous_token.length) {
|
||||
// We are moving left, select the previous token if it exists
|
||||
select_token($(previous_token.get(0)));
|
||||
} else if((event.keyCode === KEY.RIGHT || event.keyCode === KEY.DOWN) && next_token.length) {
|
||||
// We are moving right, select the next token if it exists
|
||||
select_token($(next_token.get(0)));
|
||||
}
|
||||
} else {
|
||||
var dropdown_item = null;
|
||||
|
||||
if(event.keyCode === KEY.DOWN || event.keyCode === KEY.RIGHT) {
|
||||
dropdown_item = $(selected_dropdown_item).next();
|
||||
} else {
|
||||
dropdown_item = $(selected_dropdown_item).prev();
|
||||
}
|
||||
|
||||
if(dropdown_item.length) {
|
||||
select_dropdown_item(dropdown_item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY.BACKSPACE:
|
||||
previous_token = input_token.prev();
|
||||
|
||||
if(!$(this).val().length) {
|
||||
if(selected_token) {
|
||||
delete_token($(selected_token));
|
||||
} else if(previous_token.length) {
|
||||
select_token($(previous_token.get(0)));
|
||||
}
|
||||
|
||||
return false;
|
||||
} else if($(this).val().length === 1) {
|
||||
hide_dropdown();
|
||||
} else {
|
||||
// set a timeout just long enough to let this function finish.
|
||||
setTimeout(function(){do_search();}, 5);
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY.TAB:
|
||||
case KEY.ENTER:
|
||||
case KEY.NUMPAD_ENTER:
|
||||
case KEY.COMMA:
|
||||
if(selected_dropdown_item) {
|
||||
add_token($(selected_dropdown_item));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY.ESCAPE:
|
||||
hide_dropdown();
|
||||
return true;
|
||||
|
||||
default:
|
||||
if(String.fromCharCode(event.which)) {
|
||||
// set a timeout just long enough to let this function finish.
|
||||
setTimeout(function(){do_search();}, 5);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if ($(input).get(0).tagName == 'SELECT') {
|
||||
// Create a new input to store selected tokens, original will be delete later
|
||||
var hidden_input = $("<input type=\"text\" name=\"" + $(input).attr('name') + "\" autocomplete=\"off\">")
|
||||
.hide()
|
||||
.val("")
|
||||
.focus(function () {
|
||||
input_box.focus();
|
||||
})
|
||||
.blur(function () {
|
||||
input_box.blur();
|
||||
})
|
||||
.insertBefore(input);
|
||||
} else {
|
||||
// Keep a reference to the original input box
|
||||
var hidden_input = $(input)
|
||||
.hide()
|
||||
.val("")
|
||||
.focus(function () {
|
||||
input_box.focus();
|
||||
})
|
||||
.blur(function () {
|
||||
input_box.blur();
|
||||
});
|
||||
}
|
||||
|
||||
// Keep a reference to the selected token and dropdown item
|
||||
var selected_token = null;
|
||||
var selected_token_index = 0;
|
||||
var selected_dropdown_item = null;
|
||||
|
||||
// The list to store the token items in
|
||||
var token_list = $("<ul />")
|
||||
.addClass(settings.classes.tokenList)
|
||||
.click(function (event) {
|
||||
var li = $(event.target).closest("li");
|
||||
if(li && li.get(0) && $.data(li.get(0), "tokeninput")) {
|
||||
toggle_select_token(li);
|
||||
} else {
|
||||
// Deselect selected token
|
||||
if(selected_token) {
|
||||
deselect_token($(selected_token), POSITION.END);
|
||||
}
|
||||
|
||||
// Focus input box
|
||||
input_box.focus();
|
||||
}
|
||||
})
|
||||
.mouseover(function (event) {
|
||||
var li = $(event.target).closest("li");
|
||||
if(li && selected_token !== this) {
|
||||
li.addClass(settings.classes.highlightedToken);
|
||||
}
|
||||
})
|
||||
.mouseout(function (event) {
|
||||
var li = $(event.target).closest("li");
|
||||
if(li && selected_token !== this) {
|
||||
li.removeClass(settings.classes.highlightedToken);
|
||||
}
|
||||
})
|
||||
.insertBefore(hidden_input);
|
||||
|
||||
// The token holding the input box
|
||||
var input_token = $("<li />")
|
||||
.addClass(settings.classes.inputToken)
|
||||
.appendTo(token_list)
|
||||
.append(input_box);
|
||||
|
||||
// The list to store the dropdown items in
|
||||
var dropdown = $("<div>")
|
||||
.addClass(settings.classes.dropdown)
|
||||
.appendTo("body")
|
||||
.hide();
|
||||
|
||||
// Magic element to help us resize the text input
|
||||
var input_resizer = $("<tester/>")
|
||||
.insertAfter(input_box)
|
||||
.css({
|
||||
position: "absolute",
|
||||
top: -9999,
|
||||
left: -9999,
|
||||
width: "auto",
|
||||
fontSize: input_box.css("fontSize"),
|
||||
fontFamily: input_box.css("fontFamily"),
|
||||
fontWeight: input_box.css("fontWeight"),
|
||||
letterSpacing: input_box.css("letterSpacing"),
|
||||
whiteSpace: "nowrap"
|
||||
});
|
||||
|
||||
// Pre-populate list if items exist
|
||||
hidden_input.val("");
|
||||
var li_data = settings.prePopulate || hidden_input.data("pre");
|
||||
if(settings.processPrePopulate && $.isFunction(settings.onResult)) {
|
||||
li_data = settings.onResult.call(hidden_input, li_data);
|
||||
}
|
||||
if(li_data && li_data.length) {
|
||||
$.each(li_data, function (index, value) {
|
||||
insert_token(value.id, value.name);
|
||||
});
|
||||
}
|
||||
|
||||
// Pre-populate from SELECT options
|
||||
if ($(input).get(0).tagName == 'SELECT') {
|
||||
$(input).children('option').each(function () {
|
||||
insert_token($(this).attr('value'), $(this).text());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Private functions
|
||||
//
|
||||
|
||||
function resize_input() {
|
||||
if(input_val === (input_val = input_box.val())) {return;}
|
||||
|
||||
// Enter new content into resizer and resize input accordingly
|
||||
var escaped = input_val.replace(/&/g, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>');
|
||||
input_resizer.html(escaped);
|
||||
input_box.width(input_resizer.width() + 30);
|
||||
}
|
||||
|
||||
function is_printable_character(keycode) {
|
||||
return ((keycode >= 48 && keycode <= 90) || // 0-1a-z
|
||||
(keycode >= 96 && keycode <= 111) || // numpad 0-9 + - / * .
|
||||
(keycode >= 186 && keycode <= 192) || // ; = , - . / ^
|
||||
(keycode >= 219 && keycode <= 222)); // ( \ ) '
|
||||
}
|
||||
|
||||
// Inner function to a token to the list
|
||||
function insert_token(id, value) {
|
||||
var this_token = $("<li><p>"+ value +"</p></li>")
|
||||
.addClass(settings.classes.token)
|
||||
.insertBefore(input_token);
|
||||
|
||||
// The 'delete token' button
|
||||
$("<span>" + settings.deleteText + "</span>")
|
||||
.addClass(settings.classes.tokenDelete)
|
||||
.appendTo(this_token)
|
||||
.click(function () {
|
||||
delete_token($(this).parent());
|
||||
return false;
|
||||
});
|
||||
|
||||
// Store data on the token
|
||||
var token_data = {"id": id, "name": value};
|
||||
$.data(this_token.get(0), "tokeninput", token_data);
|
||||
|
||||
// Save this token for duplicate checking
|
||||
saved_tokens = saved_tokens.slice(0,selected_token_index).concat([token_data]).concat(saved_tokens.slice(selected_token_index));
|
||||
selected_token_index++;
|
||||
|
||||
// Update the hidden input
|
||||
var token_ids = $.map(saved_tokens, function (el) {
|
||||
return el.id;
|
||||
});
|
||||
hidden_input.val(token_ids.join(settings.tokenDelimiter));
|
||||
|
||||
token_count += 1;
|
||||
|
||||
return this_token;
|
||||
}
|
||||
|
||||
// Add a token to the token list based on user input
|
||||
function add_token (item) {
|
||||
var li_data = $.data(item.get(0), "tokeninput");
|
||||
var callback = settings.onAdd;
|
||||
|
||||
// See if the token already exists and select it if we don't want duplicates
|
||||
if(token_count > 0 && settings.preventDuplicates) {
|
||||
var found_existing_token = null;
|
||||
token_list.children().each(function () {
|
||||
var existing_token = $(this);
|
||||
var existing_data = $.data(existing_token.get(0), "tokeninput");
|
||||
if(existing_data && existing_data.id === li_data.id) {
|
||||
found_existing_token = existing_token;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if(found_existing_token) {
|
||||
select_token(found_existing_token);
|
||||
input_token.insertAfter(found_existing_token);
|
||||
input_box.focus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert the new tokens
|
||||
insert_token(li_data.id, li_data.name);
|
||||
|
||||
// Check the token limit
|
||||
if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
|
||||
input_box.hide();
|
||||
hide_dropdown();
|
||||
return;
|
||||
} else {
|
||||
input_box.focus();
|
||||
}
|
||||
|
||||
// Clear input box
|
||||
input_box.val("");
|
||||
|
||||
// Don't show the help dropdown, they've got the idea
|
||||
hide_dropdown();
|
||||
|
||||
// Execute the onAdd callback if defined
|
||||
if($.isFunction(callback)) {
|
||||
callback.call(hidden_input,li_data);
|
||||
}
|
||||
}
|
||||
|
||||
// Select a token in the token list
|
||||
function select_token (token) {
|
||||
token.addClass(settings.classes.selectedToken);
|
||||
selected_token = token.get(0);
|
||||
|
||||
// Hide input box
|
||||
input_box.val("");
|
||||
|
||||
// Hide dropdown if it is visible (eg if we clicked to select token)
|
||||
hide_dropdown();
|
||||
}
|
||||
|
||||
// Deselect a token in the token list
|
||||
function deselect_token (token, position) {
|
||||
token.removeClass(settings.classes.selectedToken);
|
||||
selected_token = null;
|
||||
|
||||
if(position === POSITION.BEFORE) {
|
||||
input_token.insertBefore(token);
|
||||
selected_token_index--;
|
||||
} else if(position === POSITION.AFTER) {
|
||||
input_token.insertAfter(token);
|
||||
selected_token_index++;
|
||||
} else {
|
||||
input_token.appendTo(token_list);
|
||||
selected_token_index = token_count;
|
||||
}
|
||||
|
||||
// Show the input box and give it focus again
|
||||
input_box.focus();
|
||||
}
|
||||
|
||||
// Toggle selection of a token in the token list
|
||||
function toggle_select_token(token) {
|
||||
var previous_selected_token = selected_token;
|
||||
|
||||
if(selected_token) {
|
||||
deselect_token($(selected_token), POSITION.END);
|
||||
}
|
||||
|
||||
if(previous_selected_token === token.get(0)) {
|
||||
deselect_token(token, POSITION.END);
|
||||
} else {
|
||||
select_token(token);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete a token from the token list
|
||||
function delete_token (token) {
|
||||
// Remove the id from the saved list
|
||||
var token_data = $.data(token.get(0), "tokeninput");
|
||||
var callback = settings.onDelete;
|
||||
|
||||
var index = token.prevAll().length;
|
||||
if(index > selected_token_index) index--;
|
||||
|
||||
// Delete the token
|
||||
token.remove();
|
||||
selected_token = null;
|
||||
|
||||
// Show the input box and give it focus again
|
||||
input_box.focus();
|
||||
|
||||
// Remove this token from the saved list
|
||||
saved_tokens = saved_tokens.slice(0,index).concat(saved_tokens.slice(index+1));
|
||||
if(index < selected_token_index) selected_token_index--;
|
||||
|
||||
// Update the hidden input
|
||||
var token_ids = $.map(saved_tokens, function (el) {
|
||||
return el.id;
|
||||
});
|
||||
hidden_input.val(token_ids.join(settings.tokenDelimiter));
|
||||
|
||||
token_count -= 1;
|
||||
|
||||
if(settings.tokenLimit !== null) {
|
||||
input_box
|
||||
.show()
|
||||
.val("")
|
||||
.focus();
|
||||
}
|
||||
|
||||
// Execute the onDelete callback if defined
|
||||
if($.isFunction(callback)) {
|
||||
callback.call(hidden_input,token_data);
|
||||
}
|
||||
}
|
||||
|
||||
// Hide and clear the results dropdown
|
||||
function hide_dropdown () {
|
||||
dropdown.hide().empty();
|
||||
selected_dropdown_item = null;
|
||||
}
|
||||
|
||||
function show_dropdown() {
|
||||
dropdown
|
||||
.css({
|
||||
position: "absolute",
|
||||
top: $(token_list).offset().top + $(token_list).outerHeight(),
|
||||
left: $(token_list).offset().left,
|
||||
zindex: 999
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
function show_dropdown_searching () {
|
||||
if(settings.searchingText) {
|
||||
dropdown.html("<p>"+settings.searchingText+"</p>");
|
||||
show_dropdown();
|
||||
}
|
||||
}
|
||||
|
||||
function show_dropdown_hint () {
|
||||
if(settings.hintText) {
|
||||
dropdown.html("<p>"+settings.hintText+"</p>");
|
||||
show_dropdown();
|
||||
}
|
||||
}
|
||||
|
||||
// Highlight the query part of the search term
|
||||
function highlight_term(value, term) {
|
||||
return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<b>$1</b>");
|
||||
}
|
||||
|
||||
// Populate the results dropdown with some results
|
||||
function populate_dropdown (query, results) {
|
||||
if(results && results.length) {
|
||||
dropdown.empty();
|
||||
var dropdown_ul = $("<ul>")
|
||||
.appendTo(dropdown)
|
||||
.mouseover(function (event) {
|
||||
select_dropdown_item($(event.target).closest("li"));
|
||||
})
|
||||
.mousedown(function (event) {
|
||||
add_token($(event.target).closest("li"));
|
||||
return false;
|
||||
})
|
||||
.hide();
|
||||
|
||||
$.each(results, function(index, value) {
|
||||
var this_li = $("<li>" + highlight_term(value.name, query) + "</li>")
|
||||
.appendTo(dropdown_ul);
|
||||
|
||||
if(index % 2) {
|
||||
this_li.addClass(settings.classes.dropdownItem);
|
||||
} else {
|
||||
this_li.addClass(settings.classes.dropdownItem2);
|
||||
}
|
||||
|
||||
if(index === 0) {
|
||||
select_dropdown_item(this_li);
|
||||
}
|
||||
|
||||
$.data(this_li.get(0), "tokeninput", {"id": value.id, "name": value.name});
|
||||
});
|
||||
|
||||
show_dropdown();
|
||||
|
||||
if(settings.animateDropdown) {
|
||||
dropdown_ul.slideDown("fast");
|
||||
} else {
|
||||
dropdown_ul.show();
|
||||
}
|
||||
} else {
|
||||
if(settings.noResultsText) {
|
||||
dropdown.html("<p>"+settings.noResultsText+"</p>");
|
||||
show_dropdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Highlight an item in the results dropdown
|
||||
function select_dropdown_item (item) {
|
||||
if(item) {
|
||||
if(selected_dropdown_item) {
|
||||
deselect_dropdown_item($(selected_dropdown_item));
|
||||
}
|
||||
|
||||
item.addClass(settings.classes.selectedDropdownItem);
|
||||
selected_dropdown_item = item.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove highlighting from an item in the results dropdown
|
||||
function deselect_dropdown_item (item) {
|
||||
item.removeClass(settings.classes.selectedDropdownItem);
|
||||
selected_dropdown_item = null;
|
||||
}
|
||||
|
||||
// Do a search and show the "searching" dropdown if the input is longer
|
||||
// than settings.minChars
|
||||
function do_search() {
|
||||
var query = input_box.val().toLowerCase();
|
||||
|
||||
if(query && query.length) {
|
||||
if(selected_token) {
|
||||
deselect_token($(selected_token), POSITION.AFTER);
|
||||
}
|
||||
|
||||
if(query.length >= settings.minChars) {
|
||||
show_dropdown_searching();
|
||||
clearTimeout(timeout);
|
||||
|
||||
timeout = setTimeout(function(){
|
||||
run_search(query);
|
||||
}, settings.searchDelay);
|
||||
} else {
|
||||
hide_dropdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do the actual search
|
||||
function run_search(query) {
|
||||
var cached_results = cache.get(query);
|
||||
if(cached_results) {
|
||||
populate_dropdown(query, cached_results);
|
||||
} else {
|
||||
// Are we doing an ajax search or local data search?
|
||||
if(settings.url) {
|
||||
// Extract exisiting get params
|
||||
var ajax_params = {};
|
||||
ajax_params.data = {};
|
||||
if(settings.url.indexOf("?") > -1) {
|
||||
var parts = settings.url.split("?");
|
||||
ajax_params.url = parts[0];
|
||||
|
||||
var param_array = parts[1].split("&");
|
||||
$.each(param_array, function (index, value) {
|
||||
var kv = value.split("=");
|
||||
ajax_params.data[kv[0]] = kv[1];
|
||||
});
|
||||
} else {
|
||||
ajax_params.url = settings.url;
|
||||
}
|
||||
|
||||
// Prepare the request
|
||||
ajax_params.data[settings.queryParam] = query;
|
||||
ajax_params.type = settings.method;
|
||||
ajax_params.dataType = settings.contentType;
|
||||
if(settings.crossDomain) {
|
||||
ajax_params.dataType = "jsonp";
|
||||
}
|
||||
|
||||
// Attach the success callback
|
||||
ajax_params.success = function(results) {
|
||||
if($.isFunction(settings.onResult)) {
|
||||
results = settings.onResult.call(hidden_input, results);
|
||||
}
|
||||
|
||||
if(settings.allowCreation) {
|
||||
results.push({name: input_box.val() + ' (new)', id: input_box.val()});
|
||||
}
|
||||
cache.add(query, settings.jsonContainer ? results[settings.jsonContainer] : results);
|
||||
|
||||
// only populate the dropdown if the results are associated with the active search query
|
||||
if(input_box.val().toLowerCase() === query) {
|
||||
populate_dropdown(query, settings.jsonContainer ? results[settings.jsonContainer] : results);
|
||||
}
|
||||
};
|
||||
|
||||
// Make the request
|
||||
$.ajax(ajax_params);
|
||||
} else if(settings.local_data) {
|
||||
// Do the search through local data
|
||||
var results = $.grep(settings.local_data, function (row) {
|
||||
return row.name.toLowerCase().indexOf(query.toLowerCase()) > -1;
|
||||
});
|
||||
|
||||
if($.isFunction(settings.onResult)) {
|
||||
results = settings.onResult.call(hidden_input, results);
|
||||
}
|
||||
|
||||
if(settings.allowCreation) {
|
||||
results.push({name: input_box.val() + ' (new)', id: input_box.val()});
|
||||
}
|
||||
|
||||
cache.add(query, results);
|
||||
|
||||
populate_dropdown(query, results);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($(input).get(0).tagName == 'SELECT') {
|
||||
$(input).remove();
|
||||
}
|
||||
};
|
||||
|
||||
// Really basic cache for the results
|
||||
$.TokenList.Cache = function (options) {
|
||||
var settings = $.extend({
|
||||
max_size: 500
|
||||
}, options);
|
||||
|
||||
var data = {};
|
||||
var size = 0;
|
||||
|
||||
var flush = function () {
|
||||
data = {};
|
||||
size = 0;
|
||||
};
|
||||
|
||||
this.add = function (query, results) {
|
||||
if(size > settings.max_size) {
|
||||
flush();
|
||||
}
|
||||
|
||||
if(!data[query]) {
|
||||
size += 1;
|
||||
}
|
||||
|
||||
data[query] = results;
|
||||
};
|
||||
|
||||
this.get = function (query) {
|
||||
return data[query];
|
||||
};
|
||||
};
|
||||
}(jQuery));
|
||||
Reference in New Issue
Block a user