SOCMED/asset/js/jquery.fcbkcomplete.js
2020-01-02 21:48:25 +07:00

620 lines
21 KiB
JavaScript

/**
FCBKcomplete v2.8.9.3 is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
- Jquery version required: 1.6.x
*/
/* Based on TextboxList by Guillermo Rauch http://devthought.com/ */
/**
* width - element width (by default 512px)
* 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
* filter_begin - filter only from begin
* complete_text - text for complete page
* maxshownitems - maximum numbers that will be shown at dropdown list (less better performance)
* oncreate - fire event on item create
* 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
* addoncomma - add first visible element when pressing the comma key
* attachto - after this element fcbkcomplete insert own elements
* bricket - use square bricket with select (needed for asp or php) enabled by default
* input_tabindex - the tabindex of the input element
* input_min_size - minimum size of the input element (default: 1)
* input_name - value of the input element's 'name'-attribute (no 'name'-attribute set if empty)
* select_all_text - text for select all link
*/
(function( $, undefined ) {
$.fn.fcbkcomplete = function(opt) {
return this.queue( function() {
function init() {
createFCBK();
addInput(0);
}
function createFCBK() {
holder = $('<ul class="holder"></ul>').width(options.width);
if (options.attachto) {
if (typeof(options.attachto) == "object") {
options.attachto.append(holder);
} else {
$(options.attachto).append(holder);
}
} else {
element.after(holder);
}
complete = $('<div class="facebook-auto">').width(options.width);
if (options.complete_text != "") {
var completeText = options.complete_text;
complete.append('<div class="default">' + completeText + '</div>');
if (options.select_all_text) {
complete.children('.default').append($('<a href="" class="select_all_items">' + options.select_all_text + '</a>').click(function(){$(element).trigger('selectAll'); return false;}));
}
}
complete.hover(function() {complete_hover = 0;}, function() {complete_hover = 1;});
feed = $('<ul id="'+elemid+'_feed"></ul>').width(options.width);
holder.after(complete.prepend(feed));
elPrepare();
}
function elPrepare() {
name = element.attr("name");
if (options.bricket) {
if (typeof(name) != 'undefined' && name.indexOf("[]") == -1) {
name = name + "[]";
}
}
var temp_elem = $('<'+element.get(0).tagName+' name="'+name+'" id="'+elemid+'" multiple="multiple" class="' + element.get(0).className + ' hidden">').data('cache', {});
$.each(element.children('option'), function(i, option) {
option = $(option);
temp_elem.data('cache')[option.val()] = option.text();
if (option.hasClass("selected")) {
var id = addItem(option.text(), option.val(), true, option.hasClass("locked"));
temp_elem.append('<option value="'+option.val()+'" selected="selected" id="opt_'+id+'"class="selected">'+option.text()+'</option>');
}
});
element.after(temp_elem);
element.remove();
element = temp_elem;
//public method to add new item
$(element).bind("addItem", function(event, data) {
addItem(data.title, data.value, 0, 0, 0);
});
//public method to remove item
$(element).bind("removeItem", function(event, data) {
var item = holder.children('li[rel=' + data.value + ']');
if (item.length) {
removeItem(item);
}
});
//public method to remove item
$(element).bind("destroy", function(event, data) {
holder.remove();
complete.remove();
element.show();
});
//public method to select all items
$(element).bind("selectAll", function(event, data) {
var currVals = $(element).val() || [];
$.each($(element).data('cache'), function(key, value){
if($.inArray(key, currVals) === -1){
addItem(value, key, 0, 0, 0);
}
});
feed.parent().hide()
});
}
function addItem(title, value, preadded, locked, focusme) {
if (!maxItems()) {
return false;
}
var liclass = "bit-box" + (locked ? " locked": "");
var id = randomId();
var txt = document.createTextNode(xssDisplay(title));
var aclose = $('<a class="closebutton" href="#"></a>');
var li = $('<li class="'+liclass+'" rel="'+value+'" id="pt_'+id+'"></li>').prepend(txt).append(aclose);
holder.append(li);
aclose.click( function() {
removeItem($(this).parent("li"));
return false;
});
if (!preadded) {
$("#" + elemid + "_annoninput").remove();
addInput(focusme);
var _item = $('<option value="'+xssDisplay(value, 1)+'" id="opt_'+id+'" class="selected" selected="selected">'+xssDisplay(title)+'</option>');
element.append(_item);
if (options.onselect) {
funCall(options.onselect, _item);
}
element.change();
}
holder.children("li.bit-box.deleted").removeClass("deleted");
clear_feed(1);
return id;
}
function removeItem(item) {
if (!item.hasClass('locked')) {
item.fadeOut("fast");
var id = item.attr('id');
if (options.onremove) {
var _item = id ? $("#o" + id + "") : element.children("option[value=" + item.attr("rel") + "]");
funCall(options.onremove, _item);
}
if (id) {
$("#o" + id + "").remove();
} else {
element.children('option[value="' + item.attr("rel") + '"]').remove();
}
item.remove();
element.change();
deleting = 0;
}
}
function addInput(focusme) {
var li = $('<li class="bit-input" id="'+elemid + '_annoninput">');
var input = $('<input type="text" class="maininput" size="' + options.input_min_size + '" autocomplete="off">');
if (options.input_tabindex > 0) input.attr("tabindex", options.input_tabindex);
if (options.input_name != "") input.attr("name", options.input_name);
holder.append(li.append(input));
input.focus( function() {
isactive = true;
if (maxItems()) {
complete.fadeIn("fast");
}
});
input.blur( function() {
isactive = false;
if (complete_hover) {
complete.fadeOut("fast");
} else {
input.focus();
}
});
holder.click( function() {
if (options.input_min_size < 0 && feed.length) {
load_feed(xssPrevent(input.val(), 1));
}
input.focus();
if (feed.length && input.val().length > options.input_min_size) {
feed.show();
} else {
clear_feed(1);
complete.children(".default").show();
}
});
input.keypress( function(event) {
if (event.keyCode == _key.enter) {
return false;
}
//auto expand input
var newsize = (options.input_min_size > input.val().length) ? options.input_min_size : (input.val().length + 1);
input.attr("size", newsize).width(parseInt(input.css('font-size')) * newsize);
});
input.keyup( function(event) {
var etext = xssPrevent(input.val(), 1);
if (event.keyCode == _key.backspace && etext.length == 0) {
clear_feed(1);
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 != _key.downarrow && event.keyCode != _key.uparrow && event.keyCode!= _key.leftarrow && event.keyCode!= _key.rightarrow && etext.length > options.input_min_size) {
load_feed(etext);
complete.children(".default").hide();
feed.show();
}
});
if (options.oncreate) {
funCall(options.oncreate, input);
}
if (focusme) {
setTimeout( function() {
input.focus();
complete.children(".default").show();
}, 1);
}
}
function addMembers(etext, data) {
feed.html('');
if (!options.cache && data != null) {
cache.clear();
}
addTextItem(etext);
if (data != null && data.length) {
$.each(data, function(i, val) {
cache.set(xssPrevent(val.key), xssPrevent(val.value));
});
}
var maximum = options.maxshownitems < cache.length() ? options.maxshownitems: cache.length();
var content = '';
$.each(cache.search(etext), function (i, object) {
if (options.filter_selected && element.children('option[value="' + object.key + '"]').hasClass("selected")) {
//nothing here...
} else {
content += '<li rel="' + object.key + '">' + xssDisplay(itemIllumination(object.value, etext)) + '</li>';
counter++;
maximum--;
}
});
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");
}
if (maxItems() && complete.is(':hidden')) {
complete.show();
}
}
function itemIllumination(text, etext) {
var string_regex_adder = options.filter_begin ? '': '(.*)';
var regex_result = options.filter_begin ? '<em>$1</em>$2' : '$1<em>$2</em>$3';
var string_regex = string_regex_adder + (options.filter_case ? "(" + etext + ")(.*)" : "(" + etext.toLowerCase() + ")(.*)");
try {
var regex = new RegExp(string_regex, ((options.filter_case) ? "g":"gi"));
var text = text.replace(regex, regex_result);
} catch(ex) {};
return text;
}
function bindFeedEvent() {
feed.children("li").mouseover( function() {
feed.children("li").removeClass("auto-focus");
focuson = $(this);
focuson.addClass("auto-focus");
});
feed.children("li").mouseout( function() {
$(this).removeClass("auto-focus");
focuson = null;
});
}
function removeFeedEvent() {
feed.unbind("mouseover").unbind("mouseout").mousemove( function() {
bindFeedEvent();
feed.unbind("mousemove");
});
}
function bindEvents() {
var maininput = $("#" + elemid + "_annoninput").children(".maininput");
bindFeedEvent();
feed.children("li").unbind("mousedown").mousedown( function() {
var option = $(this);
addItem(option.text(), option.attr("rel"), 0, 0, 1);
clear_feed(1);
complete.hide();
});
maininput.unbind("keydown");
maininput.keydown( function(event) {
if (event.keyCode != _key.backspace) {
holder.children("li.bit-box.deleted").removeClass("deleted");
}
if ((event.keyCode == _key.enter || event.keyCode == _key.tab || event.keyCode == _key.comma) && checkFocusOn()) {
var option = focuson;
addItem(option.text(), option.attr("rel"), 0, 0, 1);
return _preventDefault(event);
}
if ((event.keyCode == _key.enter || event.keyCode == _key.tab || event.keyCode == _key.comma) && !checkFocusOn()) {
if (options.newel) {
var value = xssPrevent($(this).val());
addItem(value, value, 0, 0, 1);
return _preventDefault(event);
}
if ((options.addontab || options.addoncomma) && options.newel) {
focuson = feed.children("li:visible:first");
var option = focuson;
addItem(option.text(), option.attr("rel"), 0, 0, 1);
return _preventDefault(event);
}
}
if (event.keyCode == _key.downarrow) {
nextItem('first');
}
if (event.keyCode == _key.uparrow) {
nextItem('last');
}
});
}
function nextItem(position) {
removeFeedEvent();
if (focuson == null || focuson.length == 0) {
focuson = feed.children("li:visible:" + position);
feed.get(0).scrollTop = position == 'first' ? 0 : parseInt(focuson.get(0).scrollHeight, 10) * (parseInt(feed.children("li:visible").length, 10) - Math.round(options.height / 2));
} else {
focuson.removeClass("auto-focus");
focuson = position == 'first' ? focuson.nextAll("li:visible:first") : focuson.prevAll("li:visible:first");
var prev = parseInt(focuson.prevAll("li:visible").length, 10);
var next = parseInt(focuson.nextAll("li:visible").length, 10);
if (((position == 'first' ? prev : next) > Math.round(options.height / 2) || (position == 'first' ? prev : 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");
}
function _preventDefault(event) {
complete.hide();
event.preventDefault();
focuson = null;
return false;
}
function maxItems() {
return options.maxitems != 0 && (holder.children("li.bit-box").length < options.maxitems);
}
function addTextItem(value) {
if (options.newel && maxItems()) {
feed.children("li[fckb=1]").remove();
if (value.length == 0) {
return;
}
var li = $('<li rel="'+value+'" fckb="1">').html(xssDisplay(value));
feed.prepend(li);
counter++;
}
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;
}
}
return func.call(func, _object);
}
function checkFocusOn() {
if (focuson == null || focuson.length == 0) {
return false;
}
return true;
}
function xssPrevent(string, flag) {
if (typeof flag != "undefined") {
for(i = 0; i < string.length; i++) {
var charcode = string.charCodeAt(i);
if ((_key.exclamation <= charcode && charcode <= _key.slash) ||
(_key.colon <= charcode && charcode <= _key.at) ||
(_key.squarebricket_left <= charcode && charcode <= _key.apostrof)) {
string = string.replace(string[i], escape(string[i]));
}
}
string = string.replace(/(\{|\}|\*)/i, "\\$1");
}
return string.replace(/script(.*)/g, "");
}
function xssDisplay(string, flag) {
string = string.toString();
string = string.replace('\\', "");
if (typeof flag != "undefined") {
return string;
}
return unescape(string);
}
function clear_feed(flag) {
feed.children().remove();
if (flag) {
feed.hide();
}
}
function load_feed(etext){
counter = 0;
if (options.json_url && maxItems()) {
if (options.cache && json_cache_object.get(etext)) {
addMembers(etext);
bindEvents();
} else {
getBoxTimeout++;
var getBoxTimeoutValue = getBoxTimeout;
setTimeout( function() {
if (getBoxTimeoutValue != getBoxTimeout) return;
$.getJSON(options.json_url, {"tag": xssDisplay(etext)}, function(data) {
if (!isactive) return; // prevents opening the selection again after the focus is already off
addMembers(etext, data);
json_cache_object.set(etext, 1);
bindEvents();
});
}, options.delay);
}
} else {
addMembers(etext);
bindEvents();
}
}
var options = $.extend({
json_url: null,
width: 512,
cache: false,
height: "10",
newel: false,
addontab: false,
addoncomma: false,
firstselected: false,
filter_case: false,
filter_selected: false,
filter_begin: false,
complete_text: "Start to type...",
select_all_text: null,
maxshownitems: 30,
maxitems: 10,
oncreate: null,
onselect: null,
onremove: null,
attachto: null,
delay: 350,
input_tabindex: 0,
input_min_size: 1,
input_name: "",
bricket: true
},
opt);
//system variables
var holder = null;
var feed = null;
var complete = null;
var counter = 0;
var isactive = false;
var focuson = null;
var deleting = 0;
var complete_hover = 1;
var element = $(this);
var elemid = element.attr("id");
var getBoxTimeout = 0;
var json_cache_object = {
'set': function (id, val) {
var data = element.data("jsoncache");
data[id] = val;
element.data("jsoncache", data);
},
'get': function(id) {
return element.data("jsoncache")[id] != 'undefined' ? element.data("jsoncache")[id] : null;
},
'init' : function () {
element.data("jsoncache", {});
}
};
var _key = { 'enter': 13,
'tab': 9,
'comma': 188,
'backspace': 8,
'leftarrow': 37,
'uparrow': 38,
'rightarrow': 39,
'downarrow': 40,
'exclamation': 33,
'slash': 47,
'colon': 58,
'at': 64,
'squarebricket_left': 91,
'apostrof': 96
};
var randomId = function() {
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
var randomstring = '';
for (var i = 0; i < 32; i++) {
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return randomstring;
};
var cache = {
'search': function (text, callback) {
var temp = new Array();
var regex = new RegExp((options.filter_begin ? '^' : '') + text, (options.filter_case ? "g": "gi"));
$.each(element.data("cache"), function (i, _elem) {
if (typeof _elem.search === 'function') {
if (_elem.search(regex) != -1) {
temp.push({'key': i, 'value': _elem});
}
}
});
return temp;
},
'set': function (id, val) {
var data = element.data("cache");
data[id] = val;
element.data("cache", data);
},
'get': function(id) {
return element.data("cache")[id] != 'undefined' ? element.data("cache")[id] : null;
},
'clear': function() {
element.data("cache", {});
},
'length': function() {
return element.data("cache").length;
},
'init': function () {
if (element.data("cache") == 'undefined') {
element.data("cache", {});
}
}
};
//initialization
init();
//cache initialization
json_cache_object.init();
cache.init();
return this;
});
};
})(jQuery);