From c44a94e8f59d879b5e829f990e4d2818f34ccbd3 Mon Sep 17 00:00:00 2001 From: Shashi Gowda Date: Fri, 8 Apr 2011 13:55:01 +0530 Subject: [PATCH] Port autocomplete from tagInput to jQuery UI, send Last-Modified header and look for it in JS. --- actions/peopletagautocomplete.php | 61 +++-- js/jquery.tagInput.js | 381 ------------------------------ js/jquery.timers.js | 138 ----------- js/util.js | 101 ++++++-- js/util.min.js | 2 +- lib/action.php | 4 +- theme/base/css/display.css | 24 +- theme/rebase/css/display.css | 34 +-- 8 files changed, 142 insertions(+), 603 deletions(-) delete mode 100644 js/jquery.tagInput.js delete mode 100644 js/jquery.timers.js diff --git a/actions/peopletagautocomplete.php b/actions/peopletagautocomplete.php index db11a24667..04b9baefbe 100644 --- a/actions/peopletagautocomplete.php +++ b/actions/peopletagautocomplete.php @@ -34,6 +34,8 @@ if (!defined('STATUSNET')) { class PeopletagautocompleteAction extends Action { var $user; + var $tags; + var $last_mod; /** * Check pre-requisites and instantiate attributes @@ -66,13 +68,47 @@ class PeopletagautocompleteAction extends Action return false; } + $profile = $this->user->getProfile(); + $tags = $profile->getOwnedTags(common_current_user()); + + $this->tags = array(); + while ($tags->fetch()) { + + if (empty($this->last_mod)) { + $this->last_mod = $tags->modified; + } + + $arr = array(); + $arr['tag'] = $tags->tag; + $arr['mode'] = $tags->private ? 'private' : 'public'; + // $arr['url'] = $tags->homeUrl(); + $arr['freq'] = $tags->taggedCount(); + + $this->tags[] = $arr; + } + + $tags->free(); + return true; } + /** + * Last modified time + * + * Helps in browser-caching + * + * @return String time + */ + + function lastModified() + { + return strtotime($this->last_mod); + } + /** * Handle request * - * Does the subscription and returns results. + * Print the JSON autocomplete data * * @param Array $args unused. * @@ -81,24 +117,11 @@ class PeopletagautocompleteAction extends Action function handle($args) { - $profile = $this->user->getProfile(); - $tags = $profile->getOwnedTags(common_current_user()); - - $tags_array = array(); - while ($tags->fetch()) { - $arr = array(); - $arr['tag'] = $tags->tag; - $arr['mode'] = $tags->private ? 'private' : 'public'; - // $arr['url'] = $tags->homeUrl(); - $arr['freq'] = $tags->taggedCount(); - - $tags_array[] = $arr; + //common_log(LOG_DEBUG, 'Autocomplete data: ' . json_encode($this->tags)); + if ($this->tags) { + print(json_encode($this->tags)); + exit(0); } - - $tags->free(); - - //common_log(LOG_DEBUG, 'Autocomplete data: ' . json_encode($tags_array)); - print(json_encode($tags_array)); - exit(0); + return false; } } diff --git a/js/jquery.tagInput.js b/js/jquery.tagInput.js deleted file mode 100644 index 8ed4058fb2..0000000000 --- a/js/jquery.tagInput.js +++ /dev/null @@ -1,381 +0,0 @@ -/* - Copyright (c) 2009 Open Lab, http://www.open-lab.com/ - Written by Roberto Bicchierai http://roberto.open-lab.com. - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -/** - * options.tags an object array [{tag:"tag1",freq:1},{tag:"tag2",freq:2}, {tag:"tag3",freq:3},{tag:"tag4",freq:4} ]. - * options.jsonUrl an url returning a json object array in the same format of options.tag. The url will be called with - * "search" parameter to be used server side to filter results - * option.autoFilter true/false default=true when active show only matching tags, "false" should be used for server-side filtering - * option.autoStart true/false default=false when active dropdown will appear entering field, otherwise when typing - * options.sortBy "frequency"|"tag"|"none" default="tag" - * options.tagSeparator default="," any separator char as space, comma, semicolumn - * options.boldify true/false default trrue boldify the matching part of tag in dropdown - * - * options.suggestedTags callback an object array like ["sugtag1","sugtag2","sugtag3"] - * options.suggestedTagsPlaceHolder jquery proxy for suggested tag placeholder. When placeholder is supplied (hence unique), tagField should be applied on a single input - * (something like $("#myTagFiled").tagField(...) will works fine: $(":text").tagField(...) probably not!) - */ - -if (typeof(String.prototype.trim) == "undefined"){ - String.prototype.trim = function () { - return this.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"); - }; -} - - - -jQuery.fn.tagInput = function(options) { - // -------------------------- start default option values -------------------------- - if (!options.tags && !options.jsonUrl) { - options.tags = [ { tag:"tag1", freq:1 }, { tag:"tag2", freq:2 }, { tag:"tag3", freq:3 }, { tag:"tag4", freq:4 } ]; - } - - if (typeof(options.tagSeparator) == "undefined") - options.tagSeparator = ","; - - if (typeof(options.autoFilter) == "undefined") - options.autoFilter = true; - - if (typeof(options.autoStart) == "undefined") - options.autoStart = false; - - if (typeof(options.boldify) == "undefined") - options.boldify = true; - - if (typeof(options.animate) == "undefined") - options.animate = true; - - if (typeof(options.animate) != "function") { - options._animate = options.animate; - options.animate = function(show, el, cb) { - var func = (options._animate) ? (show ? 'fadeIn' : 'fadeOut') : (show ? 'show' : 'hide'); - el[func](cb); - } - } - - if (typeof(options.sortBy) == "undefined") - options.sortBy = "tag"; - - if (typeof(options.sortBy) == "string") { - options._sortBy = options.sortBy; - options.sortBy = function(obj) { return obj[options._sortBy]; } - } - - if (typeof(options.formatLine) == "undefined") - options.formatLine = function (i, obj, search, matches) { - var tag = obj.tag; - if (options.boldify && matches) { - tag = "" + tag.substring(0, search.length) + "" + tag.substring(search.length); - } - - var line = $("
"); - line.append("
" + tag + "
"); - if (obj.freq) - line.append("
" + obj.freq + "
"); - return line; - } - - if (typeof(options.formatValue == "undefined")) - options.formatValue = function (obj, i) { - return obj.tag; - } - // -------------------------- end default option values -------------------------- - - - this.each(function() { - - var theInput = $(this); - var theDiv; - - theInput.addClass("tagInput"); - theInput.tagOptions=options; - theInput.attr('autocomplete', 'off'); - - var suggestedTagsPlaceHolder=options.suggestedTagsPlaceHolder; - //create suggested tags place if the case - if (options.suggestedTags){ - if (!suggestedTagsPlaceHolder){ - //create a placeholder - var stl=$("
suggested tags:
"); - suggestedTagsPlaceHolder=stl.find(".tagInputSuggestedTagList"); - theInput.after(stl); - } - - //fill with suggestions - for (var tag in options.suggestedTags) { - suggestedTagsPlaceHolder.append($("" + options.suggestedTags[tag] + "")); - } - - // bind click on suggestion tags - suggestedTagsPlaceHolder.find(".tag").click(function() { - var element = $(this); - var val = theInput.val(); - var tag = element.text(); - - //check if already present - var re = new RegExp(tag + "\\b","g"); - if (containsTag(val, tag)) { - val = val.replace(re, ""); //remove all the tag - element.removeClass("tagUsed"); - } else { - val = val + options.tagSeparator + tag; - element.addClass("tagUsed"); - } - theInput.val(refurbishTags(val)); -// selectSuggTagFromInput(); - - }); - - } - - - // -------------------------- INPUT FOCUS -------------------------- - var tagInputFocus = function () { - theDiv = $("#__tagInputDiv"); - // check if the result box exists - if (theDiv.size() <= 0) { - //create the div - theDiv = $(""); - theInput.after(theDiv); - theDiv.css({left:theInput.position().left}); - } - if (options.autoStart) - tagInputRefreshDiv(theInput, theDiv); - }; - - - // -------------------------- INPUT BLUR -------------------------- - var tagInputBlur = function () { - // reformat string - theDiv = $("#__tagInputDiv"); - theInput.val(refurbishTags(theInput.val())); - - options.animate(0, theDiv, function() { - theDiv.remove(); - }); - }; - - - // -------------------------- INPUT KEYBOARD -------------------------- - var tagInputKey = function (e) { - var rows = theDiv.find("div.tagInputLine"); - var rowNum = rows.index(theDiv.find("div.tagInputSel")); - - var ret = true; - switch (e.which) { - case 38: //up arrow - rowNum = (rowNum < 1 ? 0 : rowNum - 1 ); - tagInputHLSCR(rows.eq(rowNum), true); - break; - - case 40: //down arrow - rowNum = (rowNum < rows.size() - 1 ? rowNum + 1 : rows.size() - 1 ); - tagInputHLSCR(rows.eq(rowNum), false); - break; - - case 9: //tab - case 13: //enter - if (theDiv.is(":visible")){ - var theRow = rows.eq(rowNum); - tagInputClickRow(theRow); - ret = false; - } - break; - - case 27: //esc - options.animate(0, theDiv); - break; - - default: - $(document).stopTime("tagInputRefresh"); - $(document).oneTime(400, "tagInputRefresh", function() { - tagInputRefreshDiv(); - }); - break; - } - return ret; - }; - - - // -------------------------- TAG DIV HIGHLIGHT AND SCROLL -------------------------- - var tagInputHLSCR = function(theRowJQ, isUp) { - if (theRowJQ.size() > 0) { - var div = theDiv.get(0); - var theRow = theRowJQ.get(0); - if (isUp) { - if (theDiv.scrollTop() > theRow.offsetTop) { - theDiv.scrollTop(theRow.offsetTop); - } - } else { - if ((theRow.offsetTop + theRow.offsetHeight) > (div.scrollTop + div.offsetHeight)) { - div.scrollTop = theRow.offsetTop + theRow.offsetHeight - div.offsetHeight; - } - } - theDiv.find("div.tagInputSel").removeClass("tagInputSel"); - theRowJQ.addClass("tagInputSel"); - } - }; - - - // -------------------------- TAG LINE CLICK -------------------------- - var tagInputClickRow = function(theRow) { - - var lastComma = theInput.val().lastIndexOf(options.tagSeparator); - var sep= lastComma<=0? (""):(options.tagSeparator+ (options.tagSeparator==" "?"":" ")); - var newVal = (theInput.val().substr(0, lastComma) + sep + theRow.attr('id').replace('val-','')).trim(); - theInput.val(newVal); - theDiv.hide(); - $().oneTime(200, function() { - theInput.focus(); - }); - }; - - - // -------------------------- REFILL TAG BOX -------------------------- - var tagInputRefreshDiv = function () { - - var lastComma = theInput.val().lastIndexOf(options.tagSeparator); - var search = theInput.val().substr(lastComma + 1).trim(); - - - // -------------------------- FILLING THE DIV -------------------------- - var fillingCallbak = function(tags) { - tags = tags.sort(function (a, b) { - if (options.sortBy(a) < options.sortBy(b)) - return 1; - if (options.sortBy(a) > options.sortBy(b)) - return -1; - return 0; - }); - - for (var i in tags) { - tags[i]._val = options.formatValue(tags[i], i); - var el = tags[i]; - var matches = el._val.toLocaleLowerCase().indexOf(search.toLocaleLowerCase()) == 0; - if (!options.autoFilter || matches) { - var line = $(options.formatLine(i, el, search, matches)); - if (!line.is('.tagInputLine')) - line = $("
").append(line); - line.attr('id', 'val-' + el._val); - theDiv.append(line); - } - } - if (theDiv.html()!=""){ - options.animate(true, theDiv); - } - - theDiv.find("div:first").addClass("tagInputSel"); - theDiv.find("div.tagInputLine").bind("click", function() { - tagInputClickRow($(this)); - }); - }; - - - if (search != "" || options.autoStart) { - theDiv.html(""); - - if (options.tags) - fillingCallbak(options.tags); - else{ - var data = {search:search}; - $.getJSON(options.jsonUrl, data, fillingCallbak ); - } - } else { - options.animate(false, theDiv); - } - }; - - // -------------------------- CLEAN THE TAG LIST FROM EXTRA SPACES, DOUBLE COMMAS ETC. -------------------------- - var refurbishTags = function (tagString) { - var splitted = tagString.split(options.tagSeparator); - var res = ""; - var first = true; - for (var i = 0; i < splitted.length; i++) { - if (splitted[i].trim() != "") { - if (first) { - first = false; - res = res + splitted[i].trim(); - } else { - res = res + options.tagSeparator+ (options.tagSeparator==" "?"":" ") + splitted[i].trim(); - } - } - } - return( res); - }; - - // -------------------------- TEST IF TAG IS PRESENT -------------------------- - var containsTag=function (tagString,tag){ - var splitted = tagString.split(options.tagSeparator); - var res=""; - var found=false; - tag=tag.trim(); - for(i = 0; i < splitted.length; i++){ - var testTag=splitted[i].trim(); - if (testTag==tag){ - found=true; - break; - } - } - return found; - }; - - - // -------------------------- SELECT TAGS BASING ON USER INPUT -------------------------- - var delayedSelectTagFromInput= function(){ - var element = $(this); - $().stopTime("suggTagRefresh"); - $().oneTime(200, "suggTagRefresh", function() { - selectSuggTagFromInput(); - }); - - }; - - var selectSuggTagFromInput = function () { - var val = theInput.val(); - suggestedTagsPlaceHolder.find(".tag").each(function(){ - var el = $(this); - var tag=el.text(); - - //check if already present - if (containsTag(val,tag)) { - el.addClass("tagUsed"); - } else { - el.removeClass("tagUsed"); - } - }); - - }; - - - - - // -------------------------- INPUT BINDINGS -------------------------- - $(this).bind("focus", tagInputFocus).bind("blur", tagInputBlur).bind("keydown", tagInputKey); - if (options.suggestedTags) - $(this).bind("keyup",delayedSelectTagFromInput) ; - - - }); - return this; -}; - - diff --git a/js/jquery.timers.js b/js/jquery.timers.js deleted file mode 100644 index bb51157d40..0000000000 --- a/js/jquery.timers.js +++ /dev/null @@ -1,138 +0,0 @@ -/** - * jQuery.timers - Timer abstractions for jQuery - * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com) - * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/). - * Date: 2009/10/16 - * - * @author Blair Mitchelmore - * @version 1.2 - * - **/ - -jQuery.fn.extend({ - everyTime: function(interval, label, fn, times) { - return this.each(function() { - jQuery.timer.add(this, interval, label, fn, times); - }); - }, - oneTime: function(interval, label, fn) { - return this.each(function() { - jQuery.timer.add(this, interval, label, fn, 1); - }); - }, - stopTime: function(label, fn) { - return this.each(function() { - jQuery.timer.remove(this, label, fn); - }); - } -}); - -jQuery.extend({ - timer: { - global: [], - guid: 1, - dataKey: "jQuery.timer", - regex: /^([0-9]+(?:\.[0-9]*)?)\s*(.*s)?$/, - powers: { - // Yeah this is major overkill... - 'ms': 1, - 'cs': 10, - 'ds': 100, - 's': 1000, - 'das': 10000, - 'hs': 100000, - 'ks': 1000000 - }, - timeParse: function(value) { - if (value == undefined || value == null) - return null; - var result = this.regex.exec(jQuery.trim(value.toString())); - if (result[2]) { - var num = parseFloat(result[1]); - var mult = this.powers[result[2]] || 1; - return num * mult; - } else { - return value; - } - }, - add: function(element, interval, label, fn, times) { - var counter = 0; - - if (jQuery.isFunction(label)) { - if (!times) - times = fn; - fn = label; - label = interval; - } - - interval = jQuery.timer.timeParse(interval); - - if (typeof interval != 'number' || isNaN(interval) || interval < 0) - return; - - if (typeof times != 'number' || isNaN(times) || times < 0) - times = 0; - - times = times || 0; - - var timers = jQuery.data(element, this.dataKey) || jQuery.data(element, this.dataKey, {}); - - if (!timers[label]) - timers[label] = {}; - - fn.timerID = fn.timerID || this.guid++; - - var handler = function() { - if ((++counter > times && times !== 0) || fn.call(element, counter) === false) - jQuery.timer.remove(element, label, fn); - }; - - handler.timerID = fn.timerID; - - if (!timers[label][fn.timerID]) - timers[label][fn.timerID] = window.setInterval(handler,interval); - - this.global.push( element ); - - }, - remove: function(element, label, fn) { - var timers = jQuery.data(element, this.dataKey), ret; - - if ( timers ) { - - if (!label) { - for ( label in timers ) - this.remove(element, label, fn); - } else if ( timers[label] ) { - if ( fn ) { - if ( fn.timerID ) { - window.clearInterval(timers[label][fn.timerID]); - delete timers[label][fn.timerID]; - } - } else { - for ( var fn in timers[label] ) { - window.clearInterval(timers[label][fn]); - delete timers[label][fn]; - } - } - - for ( ret in timers[label] ) break; - if ( !ret ) { - ret = null; - delete timers[label]; - } - } - - for ( ret in timers ) break; - if ( !ret ) - jQuery.removeData(element, this.dataKey); - } - } - } -}); - -jQuery(window).bind("unload", function() { - jQuery.each(jQuery.timer.global, function(index, item) { - jQuery.timer.remove(item); - }); -}); diff --git a/js/util.js b/js/util.js index 9d8e139088..844a5adb8d 100644 --- a/js/util.js +++ b/js/util.js @@ -518,8 +518,8 @@ var SN = { // StatusNet url: form.attr('action'), data: form.serialize() + '&ajax=1', beforeSend: function(xhr) { - form.addClass(SN.C.S.Processing) - .find('.submit') + form.find('.submit') + .addClass(SN.C.S.Processing) .addClass(SN.C.S.Disabled) .attr(SN.C.S.Disabled, SN.C.S.Disabled); }, @@ -1543,39 +1543,94 @@ var SN = { // StatusNet }); }, - PeopletagAutocomplete: function() { - $('.form_tag_user #tags').tagInput({ - tags: SN.C.PtagACData, - tagSeparator: " ", - animate: false, - formatLine: function (i, e, search, matches) { - var tag = "" + e.tag.substring(0, search.length) + "" + e.tag.substring(search.length); - - var line = $("
").addClass('mode-' + e.mode); - line.append($("
" + tag - + " " + e.mode + "
")); - if (e.freq) - line.append("
" + e.freq + "
"); - return line; + /** + * Called when a people tag edit box is shown in the interface + * + * - loads the jQuery UI autocomplete plugin + * - sets event handlers for tag completion + * + */ + PeopletagAutocomplete: function(txtBox) { + var split = function(val) { + return val.split( /\s+/ ); + } + var extractLast = function(term) { + return split(term).pop(); + } + + // don't navigate away from the field on tab when selecting an item + txtBox.live( "keydown", function( event ) { + if ( event.keyCode === $.ui.keyCode.TAB && + $(this).data( "autocomplete" ).menu.active ) { + event.preventDefault(); } - }); + }).autocomplete({ + minLength: 0, + source: function(request, response) { + // delegate back to autocomplete, but extract the last term + response($.ui.autocomplete.filter( + SN.C.PtagACData, extractLast(request.term))); + }, + focus: function() { + return false; + }, + select: function(event, ui) { + var terms = split(this.value); + terms.pop(); + terms.push(ui.item.value); + terms.push(""); + this.value = terms.join(" "); + return false; + } + }).data('autocomplete')._renderItem = function(ul, item) { + // FIXME: with jQuery UI you cannot have it highlight the match + var _l = '' + item.tag + + ' ' + item.mode + '' + + '' + item.freq + '' + + return $("
  • ") + .addClass('mode-' + item.mode) + .addClass('ptag-ac-line') + .data("item.autocomplete", item) + .append(_l) + .appendTo(ul); + } }, + /** + * Run setup for the ajax people tags editor + * + * - show edit button + * - set event handle for click on edit button + * - loads people tag autocompletion data if not already present + * or if it is stale. + * + */ PeopleTags: function() { $('.user_profile_tags .editable').append($('').closest(".notice-options").addClass("opaque");a.find("button.close").click(function(){$(this).remove();a.removeClass("dialogbox").closest(".notice-options").removeClass("opaque");a.find(".submit_dialogbox").remove();a.find(".submit").show();return false})},NoticeAttachments:function(){$(".notice a.attachment").each(function(){SN.U.NoticeWithAttachment($(this).closest(".notice"))})},NoticeWithAttachment:function(b){if(b.find(".attachment").length===0){return}var a=b.find(".attachment.more");if(a.length>0){$(a[0]).click(function(){var c=$(this);c.addClass(SN.C.S.Processing);$.get(c.attr("href")+"/ajax",null,function(d){c.parent(".entry-content").html($(d).find("#attachment_view .entry-content").html())});return false}).attr("title",SN.msg("showmore_tooltip"))}},NoticeDataAttach:function(b){var a=b.find("input[type=file]");a.change(function(f){b.find(".attach-status").remove();var d=$(this).val();if(!d){return false}var c=$('
    ');c.find("code").text(d);c.find("button").click(function(){c.remove();a.val("");return false});b.append(c);if(typeof this.files=="object"){for(var e=0;eg){f=false}if(f){h(c,function(j){var i=$("").attr("title",e).attr("alt",e).attr("src",j).attr("style","height: 120px");d.find(".attach-status").append(i)})}else{var b=$("
    ").text(e);d.find(".attach-status").append(b)}},NoticeLocationAttach:function(a){var e=a.find("[name=lat]");var k=a.find("[name=lon]");var g=a.find("[name=location_ns]").val();var l=a.find("[name=location_id]").val();var b="";var d=a.find("[name=notice_data-geo]");var c=a.find("[name=notice_data-geo]");var j=a.find("label.notice_data-geo");function f(n){j.attr("title",jQuery.trim(j.text())).removeClass("checked");a.find("[name=lat]").val("");a.find("[name=lon]").val("");a.find("[name=location_ns]").val("");a.find("[name=location_id]").val("");a.find("[name=notice_data-geo]").attr("checked",false);$.cookie(SN.C.S.NoticeDataGeoCookie,"disabled",{path:"/"});if(n){a.find(".geo_status_wrapper").removeClass("success").addClass("error");a.find(".geo_status_wrapper .geo_status").text(n)}else{a.find(".geo_status_wrapper").remove()}}function m(n,o){SN.U.NoticeGeoStatus(a,"Looking up place name...");$.getJSON(n,o,function(p){var q,r;if(typeof(p.location_ns)!="undefined"){a.find("[name=location_ns]").val(p.location_ns);q=p.location_ns}if(typeof(p.location_id)!="undefined"){a.find("[name=location_id]").val(p.location_id);r=p.location_id}if(typeof(p.name)=="undefined"){NLN_text=o.lat+";"+o.lon}else{NLN_text=p.name}SN.U.NoticeGeoStatus(a,NLN_text,o.lat,o.lon,p.url);j.attr("title",NoticeDataGeo_text.ShareDisable+" ("+NLN_text+")");a.find("[name=lat]").val(o.lat);a.find("[name=lon]").val(o.lon);a.find("[name=location_ns]").val(q);a.find("[name=location_id]").val(r);a.find("[name=notice_data-geo]").attr("checked",true);var s={NLat:o.lat,NLon:o.lon,NLNS:q,NLID:r,NLN:NLN_text,NLNU:p.url,NDG:true};$.cookie(SN.C.S.NoticeDataGeoCookie,JSON.stringify(s),{path:"/"})})}if(c.length>0){if($.cookie(SN.C.S.NoticeDataGeoCookie)=="disabled"){c.attr("checked",false)}else{c.attr("checked",true)}var h=a.find(".notice_data-geo_wrap");var i=h.attr("data-api");j.attr("title",j.text());c.change(function(){if(c.attr("checked")===true||$.cookie(SN.C.S.NoticeDataGeoCookie)===null){j.attr("title",NoticeDataGeo_text.ShareDisable).addClass("checked");if($.cookie(SN.C.S.NoticeDataGeoCookie)===null||$.cookie(SN.C.S.NoticeDataGeoCookie)=="disabled"){if(navigator.geolocation){SN.U.NoticeGeoStatus(a,"Requesting location from browser...");navigator.geolocation.getCurrentPosition(function(p){a.find("[name=lat]").val(p.coords.latitude);a.find("[name=lon]").val(p.coords.longitude);var q={lat:p.coords.latitude,lon:p.coords.longitude,token:$("#token").val()};m(i,q)},function(p){switch(p.code){case p.PERMISSION_DENIED:f("Location permission denied.");break;case p.TIMEOUT:f("Location lookup timeout.");break}},{timeout:10000})}else{if(e.length>0&&k.length>0){var n={lat:e,lon:k,token:$("#token").val()};m(i,n)}else{f();c.remove();j.remove()}}}else{var o=JSON.parse($.cookie(SN.C.S.NoticeDataGeoCookie));a.find("[name=lat]").val(o.NLat);a.find("[name=lon]").val(o.NLon);a.find("[name=location_ns]").val(o.NLNS);a.find("[name=location_id]").val(o.NLID);a.find("[name=notice_data-geo]").attr("checked",o.NDG);SN.U.NoticeGeoStatus(a,o.NLN,o.NLat,o.NLon,o.NLNU);j.attr("title",NoticeDataGeo_text.ShareDisable+" ("+o.NLN+")").addClass("checked")}}else{f()}}).change()}},NoticeGeoStatus:function(e,a,f,g,c){var h=e.find(".geo_status_wrapper");if(h.length==0){h=$('
    ');h.find("button.close").click(function(){e.find("[name=notice_data-geo]").removeAttr("checked").change();return false});e.append(h)}var b;if(c){b=$("").attr("href",c)}else{b=$("")}b.text(a);if(f||g){var d=f+";"+g;b.attr("title",d);if(!a){b.text(d)}}h.find(".geo_status").empty().append(b)},NewDirectMessage:function(){NDM=$(".entity_send-a-message a");NDM.attr({href:NDM.attr("href")+"&ajax=1"});NDM.bind("click",function(){var a=$(".entity_send-a-message form");if(a.length===0){$(this).addClass(SN.C.S.Processing);$.get(NDM.attr("href"),null,function(b){$(".entity_send-a-message").append(document._importNode($("form",b)[0],true));a=$(".entity_send-a-message .form_notice");SN.U.FormNoticeXHR(a);SN.U.FormNoticeEnhancements(a);a.append('');$(".entity_send-a-message button").click(function(){a.hide();return false});NDM.removeClass(SN.C.S.Processing)})}else{a.show();$(".entity_send-a-message textarea").focus()}return false})},GetFullYear:function(c,d,a){var b=new Date();b.setFullYear(c,d,a);return b},StatusNetInstance:{Set:function(b){var a=SN.U.StatusNetInstance.Get();if(a!==null){b=$.extend(a,b)}$.cookie(SN.C.S.StatusNetInstance,JSON.stringify(b),{path:"/",expires:SN.U.GetFullYear(2029,0,1)})},Get:function(){var a=$.cookie(SN.C.S.StatusNetInstance);if(a!==null){return JSON.parse(a)}return null},Delete:function(){$.cookie(SN.C.S.StatusNetInstance,null)}},belongsOnTimeline:function(b){var a=$("body").attr("id");if(a=="public"){return true}var c=$("#nav_profile a").attr("href");if(c){var d=$(b).find(".vcard.author a.url").attr("href");if(d==c){if(a=="all"||a=="showstream"){return true}}}return false},switchInputFormTab:function(a){$(".input_form_nav_tab.current").removeClass("current");if(a=="placeholder"){$("#input_form_nav_status").addClass("current")}else{$("#input_form_nav_"+a).addClass("current")}$(".input_form.current").removeClass("current");$("#input_form_"+a).addClass("current").find(".ajax-notice").each(function(){var b=$(this);SN.Init.NoticeFormSetup(b)}).find("textarea:first").focus()}},Init:{NoticeForm:function(){if($("body.user_in").length>0){$("#input_form_placeholder input.placeholder").focus(function(){SN.U.switchInputFormTab("status")});$("body").bind("click",function(g){var d=$("#content .input_forms div.current");if(d.length>0){if($("#content .input_forms").has(g.target).length==0){var a=d.find('textarea, input[type=text], input[type=""]');var c=false;a.each(function(){c=c||$(this).val()});if(!c){SN.U.switchInputFormTab("placeholder")}}}var b=$("li.notice-reply");if(b.length>0){var f=$(g.target);b.each(function(){var j=$(this);if(j.has(g.target).length==0){var h=j.find(".notice_data-text:first");var i=$.trim(h.val());if(i==""||i==h.data("initialText")){var e=j.closest("li.notice");j.remove();e.find("li.notice-reply-placeholder").show()}}})}})}},NoticeFormSetup:function(a){if(!a.data("NoticeFormSetup")){SN.U.NoticeLocationAttach(a);SN.U.FormNoticeXHR(a);SN.U.FormNoticeEnhancements(a);SN.U.NoticeDataAttach(a);a.data("NoticeFormSetup",true)}},Notices:function(){if($("body.user_in").length>0){var a=$(".form_notice:first");if(a.length>0){SN.C.I.NoticeFormMaster=document._importNode(a[0],true)}SN.U.NoticeRepeat();SN.U.NoticeReply();SN.U.NoticeInlineReplySetup()}SN.U.NoticeAttachments()},EntityActions:function(){if($("body.user_in").length>0){$(".form_user_subscribe").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_user_unsubscribe").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_group_join").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_group_leave").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_user_nudge").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_peopletag_subscribe").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_peopletag_unsubscribe").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_user_add_peopletag").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_user_remove_peopletag").live("click",function(){SN.U.FormXHR($(this));return false});SN.U.NewDirectMessage()}},ProfileSearch:function(){if($("body.user_in").length>0){$(".form_peopletag_edit_user_search input.submit").live("click",function(){SN.U.FormProfileSearchXHR($(this).parents("form"));return false})}},Login:function(){if(SN.U.StatusNetInstance.Get()!==null){var a=SN.U.StatusNetInstance.Get().Nickname;if(a!==null){$("#form_login #nickname").val(a)}}$("#form_login").bind("submit",function(){SN.U.StatusNetInstance.Set({Nickname:$("#form_login #nickname").val()});return true})},PeopletagAutocomplete:function(){$(".form_tag_user #tags").tagInput({tags:SN.C.PtagACData,tagSeparator:" ",animate:false,formatLine:function(d,g,c,f){var a=""+g.tag.substring(0,c.length)+""+g.tag.substring(c.length);var b=$("
    ").addClass("mode-"+g.mode);b.append($("
    "+a+" "+g.mode+"
    "));if(g.freq){b.append("
    "+g.freq+"
    ")}return b}})},PeopleTags:function(){$(".user_profile_tags .editable").append($('').closest(".notice-options").addClass("opaque");a.find("button.close").click(function(){$(this).remove();a.removeClass("dialogbox").closest(".notice-options").removeClass("opaque");a.find(".submit_dialogbox").remove();a.find(".submit").show();return false})},NoticeAttachments:function(){$(".notice a.attachment").each(function(){SN.U.NoticeWithAttachment($(this).closest(".notice"))})},NoticeWithAttachment:function(b){if(b.find(".attachment").length===0){return}var a=b.find(".attachment.more");if(a.length>0){$(a[0]).click(function(){var c=$(this);c.addClass(SN.C.S.Processing);$.get(c.attr("href")+"/ajax",null,function(d){c.parent(".entry-content").html($(d).find("#attachment_view .entry-content").html())});return false}).attr("title",SN.msg("showmore_tooltip"))}},NoticeDataAttach:function(b){var a=b.find("input[type=file]");a.change(function(f){b.find(".attach-status").remove();var d=$(this).val();if(!d){return false}var c=$('
    ');c.find("code").text(d);c.find("button").click(function(){c.remove();a.val("");return false});b.append(c);if(typeof this.files=="object"){for(var e=0;eg){f=false}if(f){h(c,function(k){var j=$("").attr("title",e).attr("alt",e).attr("src",k).attr("style","height: 120px");d.find(".attach-status").append(j)})}else{var b=$("
    ").text(e);d.find(".attach-status").append(b)}},NoticeLocationAttach:function(a){var e=a.find("[name=lat]");var l=a.find("[name=lon]");var g=a.find("[name=location_ns]").val();var m=a.find("[name=location_id]").val();var b="";var d=a.find("[name=notice_data-geo]");var c=a.find("[name=notice_data-geo]");var k=a.find("label.notice_data-geo");function f(o){k.attr("title",jQuery.trim(k.text())).removeClass("checked");a.find("[name=lat]").val("");a.find("[name=lon]").val("");a.find("[name=location_ns]").val("");a.find("[name=location_id]").val("");a.find("[name=notice_data-geo]").attr("checked",false);$.cookie(SN.C.S.NoticeDataGeoCookie,"disabled",{path:"/"});if(o){a.find(".geo_status_wrapper").removeClass("success").addClass("error");a.find(".geo_status_wrapper .geo_status").text(o)}else{a.find(".geo_status_wrapper").remove()}}function n(o,p){SN.U.NoticeGeoStatus(a,"Looking up place name...");$.getJSON(o,p,function(q){var r,s;if(typeof(q.location_ns)!="undefined"){a.find("[name=location_ns]").val(q.location_ns);r=q.location_ns}if(typeof(q.location_id)!="undefined"){a.find("[name=location_id]").val(q.location_id);s=q.location_id}if(typeof(q.name)=="undefined"){NLN_text=p.lat+";"+p.lon}else{NLN_text=q.name}SN.U.NoticeGeoStatus(a,NLN_text,p.lat,p.lon,q.url);k.attr("title",NoticeDataGeo_text.ShareDisable+" ("+NLN_text+")");a.find("[name=lat]").val(p.lat);a.find("[name=lon]").val(p.lon);a.find("[name=location_ns]").val(r);a.find("[name=location_id]").val(s);a.find("[name=notice_data-geo]").attr("checked",true);var t={NLat:p.lat,NLon:p.lon,NLNS:r,NLID:s,NLN:NLN_text,NLNU:q.url,NDG:true};$.cookie(SN.C.S.NoticeDataGeoCookie,JSON.stringify(t),{path:"/"})})}if(c.length>0){if($.cookie(SN.C.S.NoticeDataGeoCookie)=="disabled"){c.attr("checked",false)}else{c.attr("checked",true)}var h=a.find(".notice_data-geo_wrap");var j=h.attr("data-api");k.attr("title",k.text());c.change(function(){if(c.attr("checked")===true||$.cookie(SN.C.S.NoticeDataGeoCookie)===null){k.attr("title",NoticeDataGeo_text.ShareDisable).addClass("checked");if($.cookie(SN.C.S.NoticeDataGeoCookie)===null||$.cookie(SN.C.S.NoticeDataGeoCookie)=="disabled"){if(navigator.geolocation){SN.U.NoticeGeoStatus(a,"Requesting location from browser...");navigator.geolocation.getCurrentPosition(function(q){a.find("[name=lat]").val(q.coords.latitude);a.find("[name=lon]").val(q.coords.longitude);var r={lat:q.coords.latitude,lon:q.coords.longitude,token:$("#token").val()};n(j,r)},function(q){switch(q.code){case q.PERMISSION_DENIED:f("Location permission denied.");break;case q.TIMEOUT:f("Location lookup timeout.");break}},{timeout:10000})}else{if(e.length>0&&l.length>0){var o={lat:e,lon:l,token:$("#token").val()};n(j,o)}else{f();c.remove();k.remove()}}}else{var p=JSON.parse($.cookie(SN.C.S.NoticeDataGeoCookie));a.find("[name=lat]").val(p.NLat);a.find("[name=lon]").val(p.NLon);a.find("[name=location_ns]").val(p.NLNS);a.find("[name=location_id]").val(p.NLID);a.find("[name=notice_data-geo]").attr("checked",p.NDG);SN.U.NoticeGeoStatus(a,p.NLN,p.NLat,p.NLon,p.NLNU);k.attr("title",NoticeDataGeo_text.ShareDisable+" ("+p.NLN+")").addClass("checked")}}else{f()}}).change()}},NoticeGeoStatus:function(e,a,f,g,c){var h=e.find(".geo_status_wrapper");if(h.length==0){h=$('
    ');h.find("button.close").click(function(){e.find("[name=notice_data-geo]").removeAttr("checked").change();return false});e.append(h)}var b;if(c){b=$("").attr("href",c)}else{b=$("")}b.text(a);if(f||g){var d=f+";"+g;b.attr("title",d);if(!a){b.text(d)}}h.find(".geo_status").empty().append(b)},NewDirectMessage:function(){NDM=$(".entity_send-a-message a");NDM.attr({href:NDM.attr("href")+"&ajax=1"});NDM.bind("click",function(){var a=$(".entity_send-a-message form");if(a.length===0){$(this).addClass(SN.C.S.Processing);$.get(NDM.attr("href"),null,function(b){$(".entity_send-a-message").append(document._importNode($("form",b)[0],true));a=$(".entity_send-a-message .form_notice");SN.U.FormNoticeXHR(a);SN.U.FormNoticeEnhancements(a);a.append('');$(".entity_send-a-message button").click(function(){a.hide();return false});NDM.removeClass(SN.C.S.Processing)})}else{a.show();$(".entity_send-a-message textarea").focus()}return false})},GetFullYear:function(c,d,a){var b=new Date();b.setFullYear(c,d,a);return b},StatusNetInstance:{Set:function(b){var a=SN.U.StatusNetInstance.Get();if(a!==null){b=$.extend(a,b)}$.cookie(SN.C.S.StatusNetInstance,JSON.stringify(b),{path:"/",expires:SN.U.GetFullYear(2029,0,1)})},Get:function(){var a=$.cookie(SN.C.S.StatusNetInstance);if(a!==null){return JSON.parse(a)}return null},Delete:function(){$.cookie(SN.C.S.StatusNetInstance,null)}},belongsOnTimeline:function(b){var a=$("body").attr("id");if(a=="public"){return true}var c=$("#nav_profile a").attr("href");if(c){var d=$(b).find(".vcard.author a.url").attr("href");if(d==c){if(a=="all"||a=="showstream"){return true}}}return false},switchInputFormTab:function(a){$(".input_form_nav_tab.current").removeClass("current");if(a=="placeholder"){$("#input_form_nav_status").addClass("current")}else{$("#input_form_nav_"+a).addClass("current")}$(".input_form.current").removeClass("current");$("#input_form_"+a).addClass("current").find(".ajax-notice").each(function(){var b=$(this);SN.Init.NoticeFormSetup(b)}).find("textarea:first").focus()}},Init:{NoticeForm:function(){if($("body.user_in").length>0){$("#input_form_placeholder input.placeholder").focus(function(){SN.U.switchInputFormTab("status")});$("body").bind("click",function(g){var d=$("#content .input_forms div.current");if(d.length>0){if($("#content .input_forms").has(g.target).length==0){var a=d.find('textarea, input[type=text], input[type=""]');var c=false;a.each(function(){c=c||$(this).val()});if(!c){SN.U.switchInputFormTab("placeholder")}}}var b=$("li.notice-reply");if(b.length>0){var f=$(g.target);b.each(function(){var k=$(this);if(k.has(g.target).length==0){var h=k.find(".notice_data-text:first");var j=$.trim(h.val());if(j==""||j==h.data("initialText")){var e=k.closest("li.notice");k.remove();e.find("li.notice-reply-placeholder").show()}}})}})}},NoticeFormSetup:function(a){if(!a.data("NoticeFormSetup")){SN.U.NoticeLocationAttach(a);SN.U.FormNoticeXHR(a);SN.U.FormNoticeEnhancements(a);SN.U.NoticeDataAttach(a);a.data("NoticeFormSetup",true)}},Notices:function(){if($("body.user_in").length>0){var a=$(".form_notice:first");if(a.length>0){SN.C.I.NoticeFormMaster=document._importNode(a[0],true)}SN.U.NoticeRepeat();SN.U.NoticeReply();SN.U.NoticeInlineReplySetup()}SN.U.NoticeAttachments()},EntityActions:function(){if($("body.user_in").length>0){$(".form_user_subscribe").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_user_unsubscribe").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_group_join").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_group_leave").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_user_nudge").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_peopletag_subscribe").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_peopletag_unsubscribe").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_user_add_peopletag").live("click",function(){SN.U.FormXHR($(this));return false});$(".form_user_remove_peopletag").live("click",function(){SN.U.FormXHR($(this));return false});SN.U.NewDirectMessage()}},ProfileSearch:function(){if($("body.user_in").length>0){$(".form_peopletag_edit_user_search input.submit").live("click",function(){SN.U.FormProfileSearchXHR($(this).parents("form"));return false})}},Login:function(){if(SN.U.StatusNetInstance.Get()!==null){var a=SN.U.StatusNetInstance.Get().Nickname;if(a!==null){$("#form_login #nickname").val(a)}}$("#form_login").bind("submit",function(){SN.U.StatusNetInstance.Set({Nickname:$("#form_login #nickname").val()});return true})},PeopletagAutocomplete:function(b){var a=function(d){return d.split(/\s+/)};var c=function(d){return a(d).pop()};b.live("keydown",function(d){if(d.keyCode===$.ui.keyCode.TAB&&$(this).data("autocomplete").menu.active){d.preventDefault()}}).autocomplete({minLength:0,source:function(e,d){d($.ui.autocomplete.filter(SN.C.PtagACData,c(e.term)))},focus:function(){return false},select:function(e,f){var d=a(this.value);d.pop();d.push(f.item.value);d.push("");this.value=d.join(" ");return false}}).data("autocomplete")._renderItem=function(e,f){var d=''+f.tag+' '+f.mode+''+f.freq+"";return $("
  • ").addClass("mode-"+f.mode).addClass("ptag-ac-line").data("item.autocomplete",f).append(d).appendTo(e)}},PeopleTags:function(){$(".user_profile_tags .editable").append($('