remplace FCBKcomplete by TokenInput

git-svn-id: http://piwigo.org/svn/trunk@10970 68402e56-0260-453c-a942-63ccdbb3a9ee
This commit is contained in:
mistic100
2011-05-21 00:25:26 +00:00
parent 5a1c5acb0e
commit daa0bdd09e
10 changed files with 857 additions and 729 deletions

View File

@@ -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)
{

View File

@@ -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}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;}

View File

@@ -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";

View File

@@ -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...";
?>

View File

@@ -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
}

View File

@@ -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;
});
};
});

View 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: "&times;",
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, '&amp;').replace(/\s/g,' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
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));