diff --git a/main/admin/user_fields.php b/main/admin/user_fields.php index a4bb9b7656..377390c32a 100644 --- a/main/admin/user_fields.php +++ b/main/admin/user_fields.php @@ -1,23 +1,5 @@ addElement('select','fieldtype',get_lang('FieldType'),$types,array('onchange'=>'change_image_user_field(this.value)')); $form->addRule('fieldtype', get_lang('ThisFieldIsRequired'), 'required'); // Field display name @@ -172,7 +157,7 @@ $form->setDefaults($defaults); if(isset($_GET['field_id']) && !empty($_GET['field_id'])) { $class="save"; $text=get_lang('buttonEditUserField'); - } else { + } else { $class="add"; $text=get_lang('buttonAddUserField'); } diff --git a/main/auth/profile.php b/main/auth/profile.php index f609f69ee3..e462778e3e 100644 --- a/main/auth/profile.php +++ b/main/auth/profile.php @@ -39,6 +39,11 @@ if (!(isset($_user['user_id']) && $_user['user_id']) || api_is_anonymous($_user[ } $htmlHeadXtra[] = ''; //jQuery + +$htmlHeadXtra[] = ''; //jQuery +$htmlHeadXtra[] = ''; + + $htmlHeadXtra[] = ''; - -if (api_get_setting('allow_message_tool') == 'true') { - $htmlHeadXtra[] =''; -} -$htmlHeadXtra[] =''; $interbreadcrumb[] = array('url' => '../auth/profile.php', 'name' => get_lang('ModifyProfile')); @@ -94,6 +73,16 @@ if (!empty($_GET['fe'])) { $_GET['fe'] = null; } +$jquery_ready_content = ''; +if (api_get_setting('allow_message_tool') == 'true') { + $jquery_ready_content = << $field_details) { case USER_FIELD_TYPE_DIVIDER: $form->addElement('static', $field_details[1], '
'.$field_details[3].''); break; + case USER_FIELD_TYPE_TAG: + //the magic should be here + $user_tags = UserManager::get_user_tags(api_get_user_id(),$field_details[0]); + + $pre_html = '
+
'.$field_details[3].'
+
'; + $post = '
'; + + $tag_list = ''; + if (is_array($user_tags) && count($user_tags)> 0) { + foreach ($user_tags as $tag) { + $tag_list .= ''; + } + } + $multi_select = ''; + $form->addElement('html',$pre_html.$multi_select.$post ); + $url = api_get_path(WEB_CODE_PATH).'user'; + //if cache is set to true the jquery will be called 1 time + $jquery_ready_content.= <<'; + + if (api_get_setting('profile', 'apikeys') == 'true') { $form->addElement('html', '
'); $form->addElement('text', 'api_key_generate', get_lang('MyApiKey'), array('size' => 40, 'id' => 'id_api_key_generate')); @@ -548,8 +581,8 @@ if (!empty($_SESSION['production_uploaded'])) { } elseif ($form->validate()) { $wrong_current_password = false; - $user_data = $form->exportValues(); - +// $user_data = $form->exportValues(); + $user_data = $form->getSubmitValues(); // set password if a new one was provided if (!empty($user_data['password0'])) { if (check_user_password($user_data['password0'])) { @@ -635,8 +668,19 @@ if (!empty($_SESSION['production_uploaded'])) { $sql .= " WHERE user_id = '".$_user['user_id']."'"; //var_dump($sql); exit(); Database::query($sql, __FILE__, __LINE__); - //update the extra fields - foreach ($extras as $key => $value) { + + // User tag process + //1. Deleting all user tags + $list_extra_field_type_tag = UserManager::get_all_extra_field_by_type(USER_FIELD_TYPE_TAG); + if (is_array($list_extra_field_type_tag) && count($list_extra_field_type_tag)>0) { + foreach ($list_extra_field_type_tag as $id) { + UserManager::delete_user_tags(api_get_user_id(), $id); + } + } + + //2. Update the extra fields and user tags if available + foreach ($extras as $key => $value) { + //3. Tags are process in the UserManager::update_extra_field_value by the UserManager::process_tags function $myres = UserManager::update_extra_field_value($_user['user_id'], $key, $value); } @@ -738,7 +782,7 @@ $big_image_width = $big_image_size[0]; $big_image_height = $big_image_size[1]; $url_big_image = $big_image.'?rnd='.time(); -// Style position:absolute has been removed for Opera-compatibility. +// Style position:absolute has been removed for Opera-compatibility. //echo '
'; echo '
'; diff --git a/main/inc/lib/database.lib.php b/main/inc/lib/database.lib.php index b539948f78..74bb975732 100644 --- a/main/inc/lib/database.lib.php +++ b/main/inc/lib/database.lib.php @@ -62,6 +62,14 @@ define('TABLE_MAIN_USER_FIELD', 'user_field'); define('TABLE_MAIN_USER_FIELD_OPTIONS', 'user_field_options'); define('TABLE_MAIN_USER_FIELD_VALUES', 'user_field_values'); +//User tags +define('TABLE_MAIN_USER_TAG', 'user_tag'); +define('TABLE_MAIN_USER_REL_TAG', 'user_rel_tag'); + +//User group +define('TABLE_MAIN_USER_GROUP', 'user_group'); +define('TABLE_MAIN_USER_GROUP_VALUES', 'user_group_values'); + // Search engine define('TABLE_MAIN_SPECIFIC_FIELD', 'specific_field'); define('TABLE_MAIN_SPECIFIC_FIELD_VALUES', 'specific_field_values'); diff --git a/main/inc/lib/javascript/tag/close.gif b/main/inc/lib/javascript/tag/close.gif new file mode 100644 index 0000000000..cc2199248c Binary files /dev/null and b/main/inc/lib/javascript/tag/close.gif differ diff --git a/main/inc/lib/javascript/tag/jquery.fcbkcomplete.js b/main/inc/lib/javascript/tag/jquery.fcbkcomplete.js new file mode 100644 index 0000000000..946b955c5f --- /dev/null +++ b/main/inc/lib/javascript/tag/jquery.fcbkcomplete.js @@ -0,0 +1,662 @@ +/* + FCBKcomplete 2.6 + - Jquery version required: 1.2.x, 1.3.x + + 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 + + */ + +/* Coded by: emposha */ +/* Copyright: 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 + */ + +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"); + element.after(holder); + + complete = $(document.createElement("div")); + complete.addClass("facebook-auto"); + complete.append('
'+ options.complete_text +"
"); + + if (browser_msie) + { + complete.append(''); + browser_msie_frame = complete.children('.ie6fix'); + //$("input:checkbox").parent().css("z-index","-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.attr("selected","selected"); + } + else + { + option.removeAttr("selected"); + } + + cache.push({ + caption: option.text(), + value: option.val() + }); + search_string += "" + (cache.length - 1) + ":" + option.text() + ";"; + } + ); + } + + //public method to add new item + this.addItem = function(title, value) + { + addItem(title, value); + } + + function addItem (title, value, preadded) + { + var li = document.createElement("li"); + var txt = document.createTextNode(title); + var aclose = document.createElement("a"); + + $(li).attr({"class": "bit-box","rel": value}); + $(li).prepend(txt); + $(aclose).attr({"class": "closebutton","href": "#"}); + + li.appendChild(aclose); + holder.append(li); + + $(aclose).click( + function(){ + $(this).parent("li").fadeOut("fast", + function(){ + removeItem($(this)); + } + ); + return false; + } + ); + + if (!preadded) + { + $("#"+elemid + "_annoninput").remove(); + var _item; + addInput(1); + if (element.children("option[value=" + value + "]").length) + { + _item = element.children("option[value=" + value + "]"); + _item.get(0).setAttribute("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).addClass("selected"); + _item.text(title); + element.append(_item); + } + if (options.onselect.length) + { + funCall(options.onselect,_item) + } + } + holder.children("li.bit-box.deleted").removeClass("deleted"); + feed.hide(); + browser_msie?browser_msie_frame.hide():''; + } + + function removeItem(item) + { + if (options.onremove.length) + { + var _item = element.children("option[value=" + item.attr("rel") + "]"); + funCall(options.onremove,_item) + } + element.children("option[value=" + item.attr("rel") + "]").removeAttr("selected"); + element.children("option[value=" + item.attr("rel") + "]").removeClass("selected"); + item.remove(); + deleting = 0; + } + + function addInput(focusme) + { + var li = $(document.createElement("li")); + var input = $(document.createElement("input")); + + 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() + { + complete.fadeOut("fast"); + } + ); + + holder.click( + function() + { + input.focus(); + if (feed.length && input.val().length) + { + feed.show(); + } + else + { + feed.hide(); + browser_msie?browser_msie_frame.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(); + browser_msie?browser_msie_frame.hide():''; + 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 && etext.length != 0) + { + counter = 0; + + if (options.json_url) + { + if (options.cache && json_cache) + { + addMembers(etext); + bindEvents(); + } + else + { + //search texts > 1 fix by >J.montoya + if (etext.length > 0) { + $.getJSON(options.json_url + "&tag=" + etext, null, function(data){ + addMembers(etext, data); + json_cache = true; + bindEvents(); + }); + } + } + } + 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) + { + cache = new Array(); + search_string = ""; + } + + addTextItem(etext); + + if (data != null && data.length) + { + $.each(data, + function(i, val) + { + cache.push ( + { + caption: val.caption, + value: val.value + } + ); + search_string += "" + (cache.length - 1) + ":" + val.caption + ";"; + } + ); + } + + var maximum = options.maxshownitems 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 += '
  • ' + itemIllumination(object.caption, etext) + '
  • '; + 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"}); + if (browser_msie) + { + browser_msie_frame.css({"height": (options.height * 24) + "px", "width": feed.width() + "px"}).show(); + } + } + else + { + feed.css("height", "auto"); + if (browser_msie) + { + browser_msie_frame.css({"height": feed.height() + "px", "width": feed.width() + "px"}).show(); + } + } + } + + function itemIllumination(text, etext) + { + if (options.filter_case) + { + try { + eval("var text = text.replace(/(.*)(" + etext + ")(.*)/gi,'$1$2$3');"); + } catch(ex){}; + } + else + { + try { + eval("var text = text.replace(/(.*)(" + etext.toLowerCase() + ")(.*)/gi,'$1$2$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() + { + //click in the list + var option = $(this); + addItem(option.text(),option.attr("rel")); + feed.hide(); + browser_msie?browser_msie_frame.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 && checkFocusOn()) + { + var option = focuson; + addItem(option.text(), option.attr("rel")); + complete.hide(); + event.preventDefault(); + focuson = null; + return false; + } + + if (event.keyCode == 13 && !checkFocusOn()) + { + if (options.newel) + { + var value = xssPrevent($(this).val()); + addItem(value, value); + 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 addTextItem(value) + { + if (options.newel) + { + 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}"; + try { + eval(func + "(" + _object + ")"); + }catch(ex){}; + } + + 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, + firstselected: false, + filter_case: false, + filter_hide: false, + complete_text: "Start to type...", + maxshownitems: 30, + onselect: "", + onremove: "" + }, 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 browser_msie = "\v"=="v"; + var browser_msie_frame; + + var element = $(this); + var elemid = element.attr("id"); + init(); + + return this; + }); + }; + } +); diff --git a/main/inc/lib/javascript/tag/jquery.fcbkcomplete.min.js b/main/inc/lib/javascript/tag/jquery.fcbkcomplete.min.js new file mode 100644 index 0000000000..2cc12e1fba --- /dev/null +++ b/main/inc/lib/javascript/tag/jquery.fcbkcomplete.min.js @@ -0,0 +1,52 @@ +/* + FCBKcomplete 2.6 + - Jquery version required: 1.2.x, 1.3.x + + 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 + + */ + +/* Coded by: emposha */ +/* Copyright: 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 + */ + + 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");element.after(holder);complete=$(document.createElement("div"));complete.addClass("facebook-auto");complete.append('
    '+options.complete_text+"
    ");if(browser_msie){complete.append('');browser_msie_frame=complete.children('.ie6fix');}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.attr("selected","selected");}else{option.removeAttr("selected");}cache.push({caption:option.text(),value:option.val()});search_string+=""+(cache.length-1)+":"+option.text()+";";});}this.addItem=function(title,value){addItem(title,value);};function addItem(title,value,preadded){var li=document.createElement("li");var txt=document.createTextNode(title);var aclose=document.createElement("a");$(li).attr({"class":"bit-box","rel":value});$(li).prepend(txt);$(aclose).attr({"class":"closebutton","href":"#"});li.appendChild(aclose);holder.append(li);$(aclose).click(function(){$(this).parent("li").fadeOut("fast",function(){removeItem($(this));});return false;});if(!preadded){$("#"+elemid+"_annoninput").remove();var _item;addInput(1);if(element.children("option[value="+value+"]").length){_item=element.children("option[value="+value+"]");_item.get(0).setAttribute("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).addClass("selected");_item.text(title);element.append(_item);}if(options.onselect.length){funCall(options.onselect,_item);}}holder.children("li.bit-box.deleted").removeClass("deleted");feed.hide();browser_msie?browser_msie_frame.hide():'';}function removeItem(item){if(options.onremove.length){var _item=element.children("option[value="+item.attr("rel")+"]");funCall(options.onremove,_item);}element.children("option[value="+item.attr("rel")+"]").removeAttr("selected");element.children("option[value="+item.attr("rel")+"]").removeClass("selected");item.remove();deleting=0;}function addInput(focusme){var li=$(document.createElement("li"));var input=$(document.createElement("input"));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(){complete.fadeOut("fast");});holder.click(function(){input.focus();if(feed.length&&input.val().length){feed.show();}else{feed.hide();browser_msie?browser_msie_frame.hide():'';complete.children(".default").show();}});input.keypress(function(event){if(event.keyCode==13){return false;}input.attr("size",input.val().length+1);});input.keydown(function(event){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();browser_msie?browser_msie_frame.hide():'';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&&etext.length!=0){counter=0;if(options.json_url){if(options.cache&&json_cache){addMembers(etext);bindEvents();}else{$.getJSON(options.json_url+"?tag="+etext,null,function(data){addMembers(etext,data);json_cache=true;bindEvents();});}}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){cache=new Array();search_string="";}addTextItem(etext);if(data!=null&&data.length){$.each(data,function(i,val){cache.push({caption:val.caption,value:val.value});search_string+=""+(cache.length-1)+":"+val.caption+";";});}var maximum=options.maxshownitems0){var id=match[1];var object=cache[id];if(options.filter_selected&&element.children("option[value="+object.value+"]").hasClass("selected")){}else{content+='
  • '+itemIllumination(object.caption,etext)+'
  • ';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"});if(browser_msie){browser_msie_frame.css({"height":(options.height*24)+"px","width":feed.width()+"px"}).show();}}else{feed.css("height","auto");if(browser_msie){browser_msie_frame.css({"height":feed.height()+"px","width":feed.width()+"px"}).show();}}}function itemIllumination(text,etext){if(options.filter_case){try{eval("var text = text.replace(/(.*)("+etext+")(.*)/gi,'$1$2$3');");}catch(ex){}}else{try{eval("var text = text.replace(/(.*)("+etext.toLowerCase()+")(.*)/gi,'$1$2$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"));feed.hide();browser_msie?browser_msie_frame.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&&checkFocusOn()){var option=focuson;addItem(option.text(),option.attr("rel"));complete.hide();event.preventDefault();focuson=null;return false;}if(event.keyCode==13&&!checkFocusOn()){if(options.newel){var value=xssPrevent($(this).val());addItem(value,value);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 addTextItem(value){if(options.newel){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'; print_r($fvalue); if (is_array($fvalue)) { foreach($fvalue as $val) { $fvalues .= Database::escape_string($val).';'; @@ -910,6 +912,11 @@ class UserManager // Check if enumerated field, if the option is available $rowuf = Database::fetch_array($resuf); switch ($rowuf['field_type']) { + case 10 : + //Tags are process here + UserManager::process_tags(explode(';', $fvalues), $user_id, $rowuf['id']); + return true; + break; case 3: case 4: case 5: @@ -932,7 +939,7 @@ class UserManager } break; case 1: - case 2: + case 2: default: break; } @@ -1433,6 +1440,19 @@ class UserManager } return $return; } + + public static function get_all_extra_field_by_type($field_type) { + // database table definition + $table_field = Database::get_main_table(TABLE_MAIN_USER_FIELD); + + // all the information of the field + $sql = "SELECT * FROM $table_field WHERE field_type='".Database::escape_string($field_type)."'"; + $result = Database::query($sql, __FILE__, __LINE__); + while ($row = Database::fetch_array($result)) { + $return[] = $row['id']; + } + return $return; + } /** * Get all the extra field information of a certain field (also the options) @@ -1460,7 +1480,7 @@ class UserManager } return $return; } - + /** Get extra user data by value * @param string the internal variable name of the field * @param string the internal value of the field @@ -2223,4 +2243,274 @@ class UserManager $rs = Database::query($sql_insert_outbox, __FILE__, __LINE__); } } + + /* + * + * USER TAGS + * + * Intructions to create a new user tag + * + * 1. Create a new extra field in main/admin/user_fields.php with the "TAG" field type make it available and visible. Called it "books" for example. + * 2. Go to profile main/auth/profile.php There you will see a special input (facebook style) that will show suggestions of tags. + * 3. Step 2 will not work since this special input needs a file called "main/user/books.php" In this case. In order to have this file copy and paste from this file main/user/tag.php + * 4. All the tags are registered in the user_tag table and the relationship between user and tags is in the user_rel_tag table + * 5. Test and enjoy. + * + */ + + /** + * Gets the tags of a specific field_id + * + * @param int field_id + * @param string how we are going to result value in array or in a string (json) + * @return mixed + */ + public static function get_tags($tag, $field_id, $return_format='json',$limit=10) { + // database table definition + $table_user_tag = Database::get_main_table(TABLE_MAIN_USER_TAG); + $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG); + $field_id = intval($field_id); //like '%$tag%' + $limit = intval($limit); + $tag = Database::escape_string($tag); + // all the information of the field + $sql = "SELECT id, tag from $table_user_tag + WHERE field_id = $field_id AND tag LIKE '$tag%' ORDER BY tag LIMIT $limit"; + $result = Database::query($sql, __FILE__, __LINE__); + $return = array(); + if (Database::num_rows($result)>0) { + while ($row = Database::fetch_array($result,'ASSOC')) { + $return[] = array('caption'=>$row['tag'], 'value'=>$row['tag']); + } + } + if ($return_format=='json') { + $return = json_encode($return); + } + return $return; + } + + public static function get_top_tags($field_id, $limit=100) { + // database table definition + $table_user_tag = Database::get_main_table(TABLE_MAIN_USER_TAG); + $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG); + $field_id = intval($field_id); + $limit = intval($limit); + // all the information of the field + $sql = "SELECT count(*) count, tag FROM $table_user_tag_values uv INNER JOIN $table_user_tag ut ON(ut.id = uv.tag_id) + WHERE field_id = $field_id GROUP BY tag_id ORDER BY count DESC LIMIT $limit"; + $result = Database::query($sql, __FILE__, __LINE__); + $return = array(); + if (Database::num_rows($result)>0) { + while ($row = Database::fetch_array($result,'ASSOC')) { + $return[] = $row; + } + } + return $return; + } + + /** + * Get user's tags + * @param int field_id + * @param int user_id + * @return array + */ + public static function get_user_tags($user_id,$field_id) { + // database table definition + $table_user_tag = Database::get_main_table(TABLE_MAIN_USER_TAG); + $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG); + $field_id = intval($field_id); + $user_id = intval($user_id); + + // all the information of the field + $sql = "SELECT ut.id, tag,count FROM $table_user_tag ut INNER JOIN $table_user_tag_values uv ON (uv.tag_id=ut.ID) + WHERE field_id = $field_id AND user_id = $user_id ORDER BY tag"; + $result = Database::query($sql, __FILE__, __LINE__); + $return = array(); + if (Database::num_rows($result)> 0) { + while ($row = Database::fetch_array($result,'ASSOC')) { + $return[$row['id']] = array($row['tag'],$row['count']); + } + } + return $return; + } + + /** + * Searchs user with a specific tag + * @param string the tag + * @param int field id of the tag + * @return array + */ + public static function get_all_user_tags($tag, $field_id, $from, $number_of_items) { + // database table definition + $table_user_tag = Database::get_main_table(TABLE_MAIN_USER_TAG); + $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG); + $field_id = intval($field_id); + $tag = Database::escape_string($tag); + $from = intval($from); + $number_of_items = intval($number_of_items); + + // all the information of the field + $sql = "SELECT u.user_id,u.username,firstname, lastname, tag FROM $table_user_tag ut INNER JOIN $table_user_tag_values uv ON (uv.tag_id=ut.ID) + INNER JOIN user u ON(uv.user_id =u.user_id) + WHERE field_id = $field_id AND tag LIKE '$tag%' ORDER BY tag"; + + $sql .= " LIMIT $from,$number_of_items"; + $result = Database::query($sql, __FILE__, __LINE__); + $return = array(); + if (Database::num_rows($result)> 0) { + while ($row = Database::fetch_array($result,'ASSOC')) { + $return[$row['user_id']] = $row; + } + } + return $return; + } + + + /** + * Get the tag id + * @param int $tag + * @param int $field_id + * @return int 0 if fails otherwise the tag id + */ + public function get_tag_id($tag, $field_id) { + $table_user_tag = Database::get_main_table(TABLE_MAIN_USER_TAG); + $tag = Database::escape_string($tag); + $field_id = intval($field_id); + //with COLLATE latin1_bin to select query in a case sensitive mode + $sql = "SELECT id FROM $table_user_tag WHERE tag COLLATE latin1_bin LIKE '$tag' AND field_id = $field_id"; + $result = Database::query($sql, __FILE__, __LINE__); + if (Database::num_rows($result)>0) { + $row = Database::fetch_array($result,'ASSOC'); + return $row['id']; + } else { + return 0; + } + } + + /** + * Get the tag id + * @param int $tag + * @param int $field_id + * @return int 0 if fails otherwise the tag id + */ + public function get_tag_id_from_id($tag_id, $field_id) { + $table_user_tag = Database::get_main_table(TABLE_MAIN_USER_TAG); + $tag_id = intval($tag_id); + $field_id = intval($field_id); + $sql = "SELECT id FROM $table_user_tag WHERE id = '$tag_id' AND field_id = $field_id"; + $result = Database::query($sql, __FILE__, __LINE__); + if (Database::num_rows($result)>0) { + $row = Database::fetch_array($result,'ASSOC'); + return $row['id']; + } else { + return false; + } + } + + + /** + * Adds a user-tag value + * @param mixed $tag + * @param int $user_id + * @param int $field_id + * @return bool + */ + public function add_tag($tag, $user_id, $field_id) { + // database table definition + $table_user_tag = Database::get_main_table(TABLE_MAIN_USER_TAG); + $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG); + $tag = Database::escape_string($tag); + $user_id = intval($user_id); + $field_id = intval($field_id); + + //&& (substr($tag,strlen($tag)-1) == '@') + /*$sent_by_user = false; + if ( substr($tag,0,1) == '@') { + //is a value sent by the list + $sent_by_user = true; + $tag = substr($tag,1,strlen($tag)-2); + } + */ + $tag_id = UserManager::get_tag_id($tag,$field_id); + //@todo we don't create tags with numbers + if (is_numeric($tag)) { + //the form is sending an id this means that the user select it from the list so it MUST exists + /*$new_tag_id = UserManager::get_tag_id_from_id($tag,$field_id); + if ($new_tag_id !== false) { + $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id = $new_tag_id"; + $result = Database::query($sql, __FILE__, __LINE__); + $last_insert_id = $new_tag_id; + } else { + $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)"; + $result = Database::query($sql, __FILE__, __LINE__); + $last_insert_id = Database::get_last_insert_id(); + }*/ + } else { + //this is a new tag + if ($tag_id == 0) { + //the tag doesn't exist + $sql = "INSERT INTO $table_user_tag (tag, field_id,count) VALUES ('$tag','$field_id', count + 1)"; + $result = Database::query($sql, __FILE__, __LINE__); + $last_insert_id = Database::get_last_insert_id(); + } else { + //the tag exists we update it + $sql = "UPDATE $table_user_tag SET count = count + 1 WHERE id = $tag_id"; + $result = Database::query($sql, __FILE__, __LINE__); + $last_insert_id = $tag_id; + } + } + + if (!empty($last_insert_id) && ($last_insert_id!=0)) { + //we insert the relationship user-tag + $sql_select ="SELECT tag_id FROM $table_user_tag_values WHERE user_id = $user_id AND tag_id = $last_insert_id "; + $result = Database::query($sql_select, __FILE__, __LINE__); + //if the relationship does not exist we create it + if (Database::num_rows($result)==0) { + $sql = "INSERT INTO $table_user_tag_values SET user_id = $user_id, tag_id = $last_insert_id"; + $result = Database::query($sql, __FILE__, __LINE__); + } + } + } + /** + * Deletes an user tag + * @param int user id + * @param int field id + * + */ + public function delete_user_tags($user_id, $field_id) { + // database table definition + $table_user_tag = Database::get_main_table(TABLE_MAIN_USER_TAG); + $table_user_tag_values = Database::get_main_table(TABLE_MAIN_USER_REL_TAG); + $tags = UserManager::get_user_tags($user_id, $field_id); + //echo '
    ';var_dump($tags);
    +		if(is_array($tags) && count($tags)>0) {
    +			foreach ($tags as $key=>$tag) {
    +				if ($tag[1]>'0') {				
    +					$sql = "UPDATE $table_user_tag SET count = count - 1  WHERE id = $key ";
    +					$result = Database::query($sql, __FILE__, __LINE__);
    +				}
    +				$sql = "DELETE FROM $table_user_tag_values WHERE user_id = $user_id AND tag_id = $key";
    +				$result = Database::query($sql, __FILE__, __LINE__);
    +			}	
    +			
    +		}		
    +	}
    +	
    +	/**
    +	 * Process the tag list comes from the UserManager::update_extra_field_value() function
    +	 * @param array the tag list that will be added 
    +	 * @param int user id
    +	 * @param int field id
    +	 * @return bool
    +	 */
    +	public function process_tags($tags, $user_id, $field_id) {
    +		//We loop the tags and add it to the DB
    +		if (is_array($tags)) {
    +			foreach($tags as $tag) {
    +				UserManager::add_tag($tag, $user_id, $field_id);
    +			}			
    +		} else {
    +			UserManager::add_tag($tags,$user_id, $field_id);
    +		}
    +		return true;
    +	}	
     }
    diff --git a/main/install/dokeos_main.sql b/main/install/dokeos_main.sql
    index 2b58a7e80a..b447737d62 100644
    --- a/main/install/dokeos_main.sql
    +++ b/main/install/dokeos_main.sql
    @@ -2259,3 +2259,26 @@ CREATE TABLE session_category (
       date_end date default NULL,
       PRIMARY KEY  (id)
     );
    +
    +
    +--
    +-- Table structure for table user tag
    +--
    +
    +
    +CREATE TABLE  user_tag (
    +	id int NOT NULL auto_increment,
    +	tag varchar(255) NOT NULL,
    +	field_id int NOT NULL,
    +	count int NOT NULL,
    +	PRIMARY KEY  (id)
    +);
    +
    +
    +CREATE TABLE user_rel_tag (
    +	id int NOT NULL auto_increment,
    +	user_id int NOT NULL,
    +	tag_id int NOT NULL,  
    +	PRIMARY KEY  (id)
    +);
    +
    diff --git a/main/install/migrate-db-1.8.6.1-1.8.6.2-pre.sql b/main/install/migrate-db-1.8.6.1-1.8.6.2-pre.sql
    index 2c9e94d9c3..4ed485912f 100755
    --- a/main/install/migrate-db-1.8.6.1-1.8.6.2-pre.sql
    +++ b/main/install/migrate-db-1.8.6.1-1.8.6.2-pre.sql
    @@ -20,7 +20,6 @@ ALTER TABLE session_rel_course_rel_user ADD COLUMN visibility int NOT NULL defau
     ALTER TABLE session_rel_course_rel_user ADD COLUMN status int NOT NULL default 0;
     CREATE TABLE session_category (id int(11) NOT NULL auto_increment, name varchar(100) default NULL, date_start date default NULL, date_end date default NULL, PRIMARY KEY  (id));
     
    -
     INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url_changeable) VALUES ('allow_coach_to_edit_course_session', NULL, 'radio', 'Course', 'false', 'AllowCoachsToEditInsideTrainingSessions', 'AllowCoachsToEditInsideTrainingSessionsComment', NULL, NULL, 0);
     INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url, access_url_changeable) VALUES ('show_courses_descriptions_in_catalog', NULL, 'radio', 'Course', 'true', 'ShowCoursesDescriptionsInCatalogTitle', 'ShowCoursesDescriptionsInCatalogComment', NULL, NULL, 1, 1);
     
    @@ -30,6 +29,11 @@ INSERT INTO settings_options (variable, value, display_text) VALUES ('show_cours
     INSERT INTO settings_options (variable, value, display_text) VALUES ('allow_coach_to_edit_course_session', 'true', 'Yes');
     INSERT INTO settings_options (variable, value, display_text) VALUES ('allow_coach_to_edit_course_session', 'false', 'No');
     
    +CREATE TABLE user_tag (id int NOT NULL auto_increment, tag varchar(255) NOT NULL, field_id int NOT NULL, count int NOT NULL, PRIMARY KEY  (id));
    +CREATE TABLE user_rel_tag (id int NOT NULL auto_increment,user_id int NOT NULL,tag_id int NOT NULL, PRIMARY KEY  (id));
    +
    +
    +
     -- xxSTATSxx
     
     -- xxUSERxx
    diff --git a/main/social/profile.php b/main/social/profile.php
    index 6aba32d0ff..2d74d10101 100644
    --- a/main/social/profile.php
    +++ b/main/social/profile.php
    @@ -731,38 +731,46 @@ echo '
    '; $extra_information .= get_lang('ExtraInformation'); $extra_information .= '

    '; $extra_information .='