My things - thinkery.me

var scrollIntoView = function(el) {
    if (!el || !el.length) return;
    var h = window.innerHeight - $("section#things").position().top,
      eh = el.height();
    var p = el.position().top,
      b = $(window).scrollTop();
    if (p + eh > b + h || p < b) {
      $("html,body").stop().animate({
        scrollTop: Math.floor(p + eh - h / 2) + "px"
      }, 400);
    }
  };

var implodeTextList = function(list) {
    var startTag = "<b>",
      endTag = "</b>";
    if (typeof list[0] != "string") return list;
    if (list.length == 1) return startTag + list[0] + endTag;
    var tempList = list.slice();
    var last = startTag + tempList.pop() + endTag;
    return startTag + tempList.join(endTag + ", " + startTag) + endTag + " and " + last;
  };

var isTouchDevice = (function() {
  var android = navigator.userAgent.indexOf('Android') != -1;
  return android || !! ('createTouch' in document);
  //return typeof Touch == "object";
})();
var isIPad = navigator.userAgent.match(/iPad/i) != null;

var Thinkery = (function() {
  var username, tag, data, originalData, singlePage, currentQuery = false;
  if (typeof jQuery.prompt != 'undefined') jQuery.prompt.setDefaults({
    persistent: false,
    opacity: 0.7,
    show: "fadeIn",
    overlayspeed: "fast",
    promptspeed: "fast",
    top: "25%"
  });

  // impromptu for mobile devices
  if (typeof jQuery.prompt != 'undefined' && isTouchDevice) jQuery.prompt.setDefaults({
    persistent: false,
    opacity: 0.7,
    show: "show",
    overlayspeed: "fast",
    promptspeed: "fast",
    top: "5%"
  });

  var updateTimeLeft = function(timeLeft) {
      var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

      function timeLeft(secs, shortDate) {
        if (typeof shortDate == "undefined") shortDate = true;

        var ago = false;
        if (secs < 0) {
          secs = -secs;
          ago = true;
        }

        var x, s, t = [];

        if (secs >= 3456000) { // 40 days
          s = new Date(new Date() - secs * 1000);
          return months[s.getMonth()] + " " + s.getDate() + ", " + s.getFullYear();
        }
        if (secs >= 86400) {
          s = Math.floor(secs / 86400);
          x = s + " d" + (shortDate ? "" : "ay");
          if (!shortDate && s > 1) x += "s";
          t.push(x);
          secs -= s * 86400;
        }

        if (secs >= 3600) {
          s = Math.floor(secs / 3600);
          x = s + " h" + (shortDate ? "r" : "our");
          if (s > 1) x += "s";
          t.push(x);
          secs -= s * 3600;
        }

        if (secs >= 60) {
          s = Math.floor(secs / 60);
          x = s + " min" + (shortDate ? "" : "ute");
          if (s > 1) x += "s";
          t.push(x);
          secs -= s * 60;
        }

        if (t.length == 0) {
          if (!secs) {
            t.push("just before");
            ago = false;
          } else t.push(parseInt(secs, 10) + "s");
        }

        var ret = "";
        s = "";
        for (var i = Math.min(1, t.length - 1); i >= 0; i--) {
          ret = t[i] + s + ret;
          s = (shortDate || s) ? ", " : " and ";
        }

        return ret + (ago ? " ago" : "");
      }
      $("span.dateTime").each(function() {
        var $this = $(this);
        var t = $this.attr("data-t").split(",");
        var time = new Date;
        time.setUTCHours(parseInt(t[3], 10));
        time.setUTCMinutes(parseInt(t[4], 10));
        time.setUTCSeconds(parseInt(t[5], 10));
        time.setUTCMonth(0);
        time.setUTCFullYear(t[0]);
        time.setUTCDate(parseInt(t[2], 10));
        time.setUTCMonth(parseInt(t[1], 10) - 1);

        var diff = (time.getTime() - new Date) / 1000;
        $this.text(timeLeft(diff, !$this.hasClass("long")));
      });
    };

  setInterval(updateTimeLeft, 30000);

  var lastTag = false;
  var loadTag = function(_tag, initialLoad, nonEmpty) {
      if (typeof initialLoad == "undefined") initialLoad = false;
      if (!Thinkery.mainListUrl) return false;
      if (_tag == lastTag) return false;
      lastTag = _tag;

      var tagUrlPart = _tag ? "tag=" + encodeURIComponent(_tag) : "";
      $.getJSON(Thinkery.mainListUrl + tagUrlPart, function(r) {

        if (initialLoad && data.length == 0) {
          location.href = "/" + username;
          return;
        }
        var tags = $("nav#menu ul li").removeClass("active");
        if (typeof _tag == "undefined" || !_tag) {
          if (typeof history.pushState == "function") history.pushState({
            tag: ""
          }, username, "/" + username);
          tags.filter("li:contains(All)").addClass("active");
          tag = false;
        } else {
          _tag = String(_tag);
          if (typeof history.pushState == "function") history.pushState({
            tag: _tag
          }, username + " - " + _tag, "/" + username + "/" + _tag);
          tags.filter("li[data-tag='" + _tag.replace("'", "\\'") + "']").addClass("active");
          tag = _tag;
        }

        _gaq.push(['_trackPageview', '/' + username + "/" + tag]);

        originalData = data = r;
        $("section#things ul").show(function() {
          var searchAdd = $("#searchadd");
          if (nonEmpty == true) {

          } else if (searchAdd.val() != "") {
            searchAdd.val("").keyup();
          }
          $("button.ir").addClass("search").removeClass("add");
          $("sub.results, sub.hint").addClass("hidden");
          updateList();
          $("section#things ul li:first").addClass("active");
          $("section#things ul").fadeIn();
          if ($("#bulkControls").is(":visible")) showBulk();
        });
        retrieveThings();
        registerLazyLoad();
        updateFlyout(0, false, true);
      });
      return false;
    };

  var retrieveQueue = 0,
    retrieveTimeout = false;
  // update items that have not been retrieved
  var retrieveThings = function() {
      if (retrieveTimeout) {
        clearTimeout(retrieveTimeout);
        if (retrieveQueue > 3) {
          retrieveTimeout = setTimeout(retrieveThings, 3000);
          return;
        }
      }
      var l = data.length;
      for (var i = 0; i < l; i++) {
        if (data[i].retrieved) continue;
        if (retrieveQueue > 3) {
          retrieveTimeout = setTimeout(retrieveThings, 3000);
          break;
        }
        retrieveQueue += 1;
        data[i].thinking = true;
        updateList(i);
        $.ajax({
          url: "/retrieve.php",
          type: "post",
          data: {
            id: data[i]._id
          },
          success: function(r) {
            retrieveQueue -= 1;
            if (typeof r._id == "undefined") return false;
            for (var i = 0, l = data.length; i < l; i++) {
              if (data[i]._id != r._id) continue;
              data[i] = r;
              if ($("section#things li.active").index() == i) updateFlyout(i);
              updateList(i);
              break;
            }
          },
          error: function() {
            retrieveQueue -= 1;
          }
        });
      }
    };

  /* Check if more things can be loaded */
  var checkMore = function() {
      var l = $('section#things li:not(.no-thing)').length;
      var s = $('#searchadd');
      var num = parseInt($('#menu li.active .num').text(), 10);
      if (isNaN(num)) num = 0;

      if (!l || l >= num || (s.length !== 0 && s.val() !== '')) {
        $('.loadmore').addClass('inactive').find('a').text('');
        return false;
      }

      $('.loadmore').removeClass('inactive').find('a').text('Show more ↓');
      return true;
    };

  /* init Lazy Loading */
  var registerLazyLoad = function(initLoad) {
      if (typeof initLoad == 'undefined') initLoad = false;

      //page init
      $('section#things').data('page', 0);
      checkMore();

      $(window).unbind('scroll').bind('scroll', function() {
        if ($(window).scrollTop() != $(document).height() - $(window).height()) return;

        setTimeout(function() {
          if ($(window).scrollTop() != $(document).height() - $(window).height()) return;
          loadThings(initLoad);
        }, 300);
      });

      $('.loadmore a').unbind('click').live('click', function(e) {
        e.preventDefault();
        loadThings(initLoad);
      });
    };

  /* load more things */
  var loadThings = function(noargs) {
      if (!checkMore()) return;

      //show loader, increment page count
      $('section#things, .loadmore').addClass('loading');
      $('section#things').data('page', parseInt($('section#things').data('page'), 10) + 1);

      if (typeof noargs !== 'undefined' && noargs) {
        var _data = {
          'page': 0
        };
      } else {
        var tag = $('#menu ul li.active').attr('data-tag');
        var page = $('section#things').data('page');

        var _data = {
          'page': page
        };
        if (typeof tag !== 'undefined' && tag !== '') {
          $.extend(_data, {
            'tag': encodeURIComponent(tag)
          });
        }
        if (document.URL.split("?")[1] == 'archived') {
          $.extend(_data, {
            'archived': true
          });
        }
        if ($('#search h4 a').text() !== "") {
          $.extend(_data, {
            'username': $('#search h4 a').text()
          });
        }
      }
      var url, _type = "get";
      if (currentQuery) {
        url = '/search.php';
        _type = "post";
      } else if (typeof Thinkery.mainListUrl == "undefined") {
        url = '/mainlist.php';
      } else {
        url = Thinkery.mainListUrl;
      }

      $.ajax({
        url: url,
        dataType: 'json',
        data: _data,
        type: _type,
        success: function(r) {
          if (r == '') {
            $('.loadmore').addClass('inactive').find('a').text('');
          } else {
            updateData(r);
            retrieveThings();
          }
          $('section#things, .loadmore').removeClass('loading');
        }
      });
    };

  var reloadSidebar = function(full) {
      if (typeof full == "undefined") full = false;
      var sidebarUrl = "/sidebar.php?username=" + encodeURIComponent(username);
      if (tag) sidebarUrl += "&tag=" + encodeURIComponent(tag);
      if (location.search == "?archived") sidebarUrl += "&archived";
      if (full) sidebarUrl += "&full";
      var favorites = $("#edittags").hasClass("active");

      $("nav#menu").load(sidebarUrl + " nav#menu>*", function() {
        if ($("#bulkControls").is(":visible")) {
          $('#toggleBulk').addClass("active");
        }
        if (favorites) {
          $("#edittags").click();
        }
        $(window).trigger('reloadSidebar');
      });


    };

  var updateData = function(d) {
      if (!d) {
        $('.loadmore').addClass('inactive').find('a').text('');
        return;
      }
      for (i = 0, l = d.length; i < l; i++) {
        data.push(d[i]);
      }
      originalData = data;
      updateList();
    };

  var getPrivacyIcon = function(tmp) {
      return '<span class="icn grey ' + getPrivacyClass(tmp) + ' tip ' + (tmp.canEdit ? 'canEdit' : '') + ' title="' + getPrivacyTitle(tmp) + '"></span>';
    };

  var getPrivacyTitle = function(tmp, html) {
      if (typeof html == "undefined") html = false;
      var privacyTitle = "Private: only you can see it";
      if (!tmp["private"]) {
        privacyTitle = "Public: everybody can see it";
        if (tmp.shared) {
          privacyTitle += '; also shared between ' + implodeTextList(tmp.shared);
        }
      } else if (tmp.shared) {
        privacyTitle = 'Shared between ' + implodeTextList(tmp.shared);
      }
      if (!html) privacyTitle = privacyTitle.replace(/</g, "&lt;").replace(/>/g, "&gt;");
      return privacyTitle;
    };

  var getPrivacyIconText = function(tmp) {
      var friends = tmp.shared ? tmp.shared.length - 1 : 0;
      var privacyIconText = "Private";
      if (!tmp["private"]) {
        privacyIconText = "Public" + (friends > 0 ? " + " + friends + ' Friend' + (friends == 1 ? "" : "s") : "");
      } else if (tmp.shared) {
        privacyIconText = friends + ' Friend' + (friends == 1 ? "" : "s");
      }
      return privacyIconText;
    };

  var getPrivacyClass = function(tmp) {
      var privacyClass = "private";
      if (!tmp["private"]) {
        privacyClass = "public";
      } else if (tmp.shared) {
        privacyClass = "shared";
      }
      return privacyClass;
    };

  var updateList = function(i) {
      bulkedit = $("#bulkControls").is(":visible");
      var listItem;

      if (typeof i != "undefined") {
        var tmp = data[i];
        listItem = $("section#things li").eq(i);
        if (tmp.archived) {
          listItem.addClass("archived");
        } else {
          listItem.removeClass("archived");
        }
        var allClasses = listItem[0].className.split(" ");
        for (var o = 0, l = allClasses.length; o < l; o++) {
          if (allClasses[o].substr(0, 6) == "thing-") listItem.removeClass(allClasses[o]);
        }
        for (var o = 0, l = tmp.classNames.length; o < l; o++) {
          listItem.addClass(tmp.classNames[o]);
        }
        $("article", listItem).html(tmp.htmlTitle + ((typeof tmp.thinking != "undefined" && tmp.thinking) ? '<img src="/img/loading.gif" class="loader" /> <span class="smaller grey">thinking...</span>' : "")).highlight(currentQuery);
        $("span.tags", listItem).html(tmp.tags);
        var p = $("span.public, span.private, span.shared", listItem);

        var privacyClass = getPrivacyClass(tmp);
        p.removeClass("private public shared").addClass(privacyClass).attr("title", getPrivacyTitle(tmp, true)).tipTip();
        if (privacyClass == "private") $("div.privacy", listItem).hide();
        else $("div.privacy", listItem).show();

        var bulk = $("input.bulk", listItem);
        bulk.attr("checked", typeof tmp.checked != "undefined" && tmp.checked);
        if (tmp.canEdit && bulkedit) {
          bulk.show();
        } else {
          bulk.hide();
        }
        return;
      }
      var actions, active;

      if (typeof i == "undefined" && $('section#things li.active').length != 0) {
        active = $("section#things li.active").index();
      }

      if (data.length == 0) {
        $("section#things ul").text("").append($("ul#noThingTemplate li").clone());
        return;
      }

      var list = $("section#things ul"),
        html = "",
        oldFirstId = $("section#flyout input.id").val(),
        firstId = false,
        tmp, l;
      for (j = 0, l = data.length; j < l; j++) {
        tmp = data[j];
        listItem = "<li class=\"thing-list-item";
        if (tmp.archived) listItem += ' archived';
        if (tmp.classNames) listItem += ' ' + tmp.classNames.join(" ");
        if (tmp.todoStatus) listItem += ' checked';
        listItem += '">';
        if (tmp.canEdit) listItem += '<span class="drag"></span>';
        var privacyIcon = getPrivacyIcon(tmp);
        listItem += '<div class="privacy"' + ((!tmp.shared || !tmp.shared.length) && tmp["private"] ? ' style="display: none"' : '') + '>' + privacyIcon + "</div>";
        listItem += '<input type="checkbox" name="bulk[]" value="' + tmp._id + '" class="bulk" ' + (typeof tmp.checked != "undefined" && tmp.checked ? ' checked="checked"' : '') + ' />';
        listItem += '<input type="checkbox" class="todo" ' + (typeof tmp.todoStatus != "undefined" && tmp.todoStatus ? ' checked="checked"' : '') + ' />';
        listItem += '<article>' + tmp.htmlTitle + ((typeof tmp.thinking != "undefined" && tmp.thinking) ? '<img src="/img/loading.gif" class="loader" /> <span class="smaller grey">thinking...</span>' : "") + "</article>";
        actions = "";
        actions += privacyIcon;
        if (tmp.canEdit) {
          actions += "<a href=\"\" class=\"icn edit tip\" title=\"Edit\">&nbsp;</a>" + "<a href=\"\" class=\"icn archive tip\" title=\"" + (tmp.archived ? "Unarchive" : "Move to archive") + "\">&nbsp;</a>" + "<a href=\"\" class=\"icn delete tip\" title=\"Delete\">&nbsp;</a>";
        }
        listItem += "<sub class=\"meta\">" + "<span class=\"tags\">" + tmp.tags + "</span> <span data-t=\"" + tmp.date + "\" class=\"info grey dateTime\">just before</span>" + "<span class=\"actions\">" + actions + "</span>" + "</sub>";
        listItem += "</li>";

        html += listItem;
      }
      list.html(html);

      //check if element and/or edit-mode is active
      if (typeof i == 'undefined') i = active;
      if (typeof i != "undefined") {
        if ($('section#flyout .content.edit').is(":hidden")) {
          updateFlyout(i);
        }
        $('section#things li').eq(i).addClass('active');
      }

      $("section#things li article").highlight(currentQuery);
      $("section#things li span.tags").highlight(currentQuery);

      checkMore();
      if (typeof data[0] == "undefined") {
        $("section#flyout .content").hide();

      }
/*else if (oldFirstId) {
			updateFlyout(0, false, false);
		}*/

      updateTimeLeft();
      $(window).trigger('things-list-updated', data);
    };

  var updatePublicPrivate = function(i) {
      var content = $("section#flyout div.content.display");
      var active = $("section#things li").eq(i).hasClass("active");
      var a = $("nav#sharing ul.dropdown>li>a>span"),
        pp = $("span.publicprivate", content),
        permalink = $("a.permalink", content);
      var tmp = data[i];
      if (active) {
        if (tmp.canEdit) $("nav#sharing").show();
        else $("nav#sharing").hide();
        $("nav#sharing ul ul a").removeClass("active");
      }
      var friends = tmp.shared ? tmp.shared.length - 1 : 0;

      var text = getPrivacyIconText(tmp);
      var privacyClass = getPrivacyClass(tmp);
      pp.text(text).removeClass("private public shared").addClass(privacyClass).attr("title", getPrivacyTitle(tmp, true)).tipTip();
      permalink.attr("title", privacyClass == "private" ? "Private Permalink" : "Public Permalink: use this URL to share it with shared").tipTip();
      if (active) {
        a.text(text).removeClass("private public shared").addClass(privacyClass);
        $("nav#sharing ul ul a." + privacyClass).addClass("active");
      }
    };

  var updateFlyout = function(i, showEdit, fade) {
      if (typeof showEdit == "undefined") showEdit = false;
      if (typeof data[i] == "undefined") return false;
      if (typeof fade == "undefined") fade = true;
      var tmp = data[i];

      $("section#things li").eq(i).addClass("active").siblings().removeClass("active");
      var content = $("section#flyout div.content.display");
      var edit = $("section#flyout div.content.edit");
      var show = showEdit ? edit : content;
      var showIt = function() {
          if (tmp.url) {
            $("h1.linked a", content).html(tmp.htmlTitle).attr("href", tmp.url).highlight(currentQuery);
            $("h1.linked", content).show();
            $("h1.unlinked", content).hide();
          } else {
            $("h1.unlinked", content).html(tmp.htmlTitle).show().highlight(currentQuery);
            $("h1.linked", content).hide();
          }
          $("div.embed", content).html(tmp.html).highlight(currentQuery);
          $("span.tags", content).html(tmp.tags).highlight(currentQuery);
          $("span.dateTime", show).attr("data-t", tmp.date);
          if (tmp.htmlNote && $.trim(String(tmp.htmlNote).replace("<br>", "")).length) {
            $("details", content).html(tmp.htmlNote).show().highlight(currentQuery);
            $("a.icn.edit.note", content).hide();
          } else {
            $("details", content).hide();
            $("a.icn.edit.note", content).show();
          }
          $("a.icn.archive", content).text(tmp.archived ? "Unarchive" : "Archive").attr("title", tmp.archived ? "Unarchive" : "Move to archive");
          $("a.permalink", content).attr("href", tmp.permalink);
          if (tmp.canEdit) $("nav.actions").show();
          else $("nav.actions").hide();
          updatePublicPrivate(i);

          $("input.title", edit).val(tmp.title);
          $("input.url", edit).val(tmp.url ? tmp.url : "");
          $("input.tags", edit).val(tmp.textTags);
          $("input.id", edit).val(tmp._id);
          $("textarea.note", edit).val(tmp.note ? tmp.note : "");
          $("select[name=private]", edit).eq(0).attr("selectedIndex", tmp["private"] ? 0 : 1);

          updateTimeLeft();
          var afterShow = function() {
              if (showEdit) {
                var editor = $("textarea.note", edit).cleditor({
                  width: "99%",
                  height: "12%",
                  controls: "bold italic underline strikethrough | bullets numbering | link unlink | style highlight | undo redo | source",
                  styles: [
                    ["Paragraph", "<p>"],
                    ["Header 1", "<h1>"],
                    ["Header 2", "<h2>"],
                    ["Header 3", "<h3>"],
                    ["Header 4", "<h4>"],
                    ["Header 5", "<h5>"],
                    ["Header 6", "<h6>"]
                  ]
                })[0].updateFrame().focus();
                var resizeEditor = function() {
                    var d = $("div.cleditorMain");
                    var p = d.offset();
                    d.height(Math.max(200, $(window).height() - p.top - 135));
                    editor.refresh();
                  };

                resizeEditor();
                if ($(window).scrollTop() == $(document).height() - $(window).height()) {
                  $(window).scrollTop($(window).scrollTop() - 50);
                }
                //$('#flyout .content.edit').scrollTop(0);
                $(window).unbind("resize").resize(resizeEditor);
                $("input.title", edit).focus();
              }
            };
          if (fade) {
            show.fadeIn(20, afterShow);
          } else {
            show.show();
            afterShow();
          }
        };
      if (fade) {
        $(content).add(edit).filter(":visible").fadeOut(10, showIt);
      } else {
        $(content).add(edit).filter(":visible").hide();
        showIt();
      }
    };

  var showBulk = function() {
      var bulkControls = $("#bulkControls").show();

      var c = 0;
      var unarchive = bulkControls.find("button[name=unarchive]"),
        archive = bulkControls.find("button[name=archive]"),
        publ = bulkControls.find("button[name=public]"),
        priv = bulkControls.find("button[name=private]");

      if ($("section#things li.archived").length) { // has things that are archived
        unarchive.parent().show(); // so offer the unarchive button
        c++;
      } else {
        unarchive.parent().hide();
      }

      if ($("section#things li:not(.archived)").length) { // has things that are not archived
        archive.parent().show(); // so offer the archive button
        c++;
      } else {
        archive.parent().hide();
      }

      if ($("section#things li span.private").length) { // has things that are private
        publ.parent().show(); // so offer the public button
        c++;
      } else {
        publ.parent().hide();
      }

      if ($("section#things li span.public").length) { // has things that are public
        priv.parent().show(); // so offer the private button
        c++;
      } else {
        priv.parent().hide();
      }

      if (c > 3) {
        publ.text("public");
        priv.text("private");
      } else {
        publ.text("make public");
        priv.text("make private");
      }

      if (c > 2) {
        $("#closeBulk").text("[x]");
      } else {
        $("#closeBulk").text("[x] close");
      }
      $("section#things li").addClass("bulkedit");
      $("#toggleAllChecked").attr("checked", false);
      $('#toggleBulk').addClass("active");
    };

  var hideBulk = function() {
      $("#bulkControls").hide();
      $("section#things li").removeClass("bulkedit");
      $('#toggleBulk').removeClass("active");
    };

  var tags = {};

  return {
    registerLazyLoad: registerLazyLoad,
    loadTag: loadTag,
    loadThings: loadThings,
    updateList: updateList,
    reloadSidebar: reloadSidebar,
    findThingById: function(_id) {
      for (var i = 0, l = data.length; i < l; i++) {
        if (data[i]._id == _id) return data[i];
      }
      return false;
    },
    saveThing: function(thing, cb, err) {
      $.post("/save.php", thing, function(r) {
        if (!r || !r._id) {
          if (err) err();
          return;
        }
        for (var i = 0, l = data.length; i < l; i++) {
          if (data[i]._id != r._id) continue;
          data[i] = r;
          updateFlyout(i);
          updatePublicPrivate(i);
          updateList(i);
        }
        if (cb) cb();
      });
    },
    load: function(_username, _data, _singlePage, _tags) {
      for (var k in _tags) {
        _tags[k]['q'] = k.toLowerCase();
        tags[k] = _tags[k];
      }
      Thinkery.tags = tags;

      username = _username;
      originalData = data = _data;
      singlePage = typeof _singlePage == "boolean" ? _singlePage : false;
      $('#main').attr('username', username);

      retrieveThings();

      $("nav#menu ul li a").live("click", function(e) {
        if (!Thinkery.mainListUrl) return true;
        var li = $(e.target).closest("li");
        if (li.closest("nav#filter").length) return true;

        var _tag = li.data("tag");

        if (!li.data("all") && (typeof _tag == "undefined" || !_tag)) {
          if (!tag) return true;
          location.href = "/" + username + "/" + tag + (e.target.search == "?archived" ? "?archived" : "");
          return false;
        }

        if (li.hasClass("smart")) _tag = "smart:" + _tag;

        loadTag(_tag);
        return false;
      });

      $("nav#menu ul li span.settings, nav#menu #addsmartfolder").live("click", function(e) {
        $.prompt($("#smartfolderTemplate").html(), {
          buttons: {
            "Save": true,
            "Cancel": false
          },
          classes: 'share',
          loaded: function(v) {
            var buttons = $("button", "#jqi table");

            function firstRemoveButton() {
              var rows = $("tr", "#jqi table");
              var firstRemove = rows.find("button.remove");
              if (rows.length == 1) firstRemove.attr("disabled", true);
              else firstRemove.attr("disabled", false);
            }
            firstRemoveButton();

            buttons.live("click", function(r) {
              var button = $(r.target);
              if (button.hasClass("add")) {
                $("#jqi table").append($("#smartfolderTemplate tr").clone());
              } else if (button.hasClass("remove")) {
                button.closest("tr").remove();
              }
              firstRemoveButton();
            });
          }
        });
        return false;
      });

      $("a[data-tag]").live("click", function(e) {
        if (!Thinkery.mainListUrl) return true;
        var _tag = $(e.target).data("tag");
        if (typeof _tag == "undefined" || !_tag) return true;
        loadTag(_tag);
        return false;
      });

      $('nav#menu .moretags a').live("click", function(e) {
        var $this = $(this);
        var expanded = !$this.hasClass('expanded');
        var p = $this.parent();
        var loaded = p.hasClass('loaded');

        if (expanded) {
          $this.html("Fewer tags &uarr;");
          this.className = "expanded";

          if (!loaded) {
            $this.html("<img src='/img/loading.gif' />");
            reloadSidebar(true);
          } else {
            $("ul#nonFavoriteTags li").show();
          }
        } else {
          $this.html("All tags &darr;");
          this.className = "collapsed";
          $("ul#nonFavoriteTags li:gt(9)").hide();
        }

        $('nav#menu').css("position", expanded ? "absolute" : "fixed");
        return false;
      });

      $("section#things li").live("click", function(e) {
        if (e.shiftKey) {
          var i = $("section#things li.active").index();
          var j = $(this).index();
          if (j < i) {
            var k = j;
            j = i;
            i = k;
          }
          var bulks = $("section#things li input.bulk");
          if ($("#bulkControls").is(":hidden")) bulks.attr("checked", false);
          for (; i <= j; i++) {
            data[i].checked = true;
            bulks.eq(i).attr("checked", true);
          }
          showBulk();
          return false;
        }
        updateFlyout($(this).index());
      });

      $("section#things li input.todo").live("click", function(e) {
        var li = $(this).closest("li");
        var i = li.index();
        data[i].todoStatus = this.checked;
        if (this.checked) li.addClass("checked");
        else li.removeClass("checked");
        $.post("/save.php", {
          id: data[i]._id,
          "todo": this.checked ? "checked" : "not-checked"
        });
      });

      $("section#things li input.bulk").live("click", function(e) {
        data[$(this).closest("li").index()].checked = this.checked;
      });

      if (isTouchDevice) {
        var touchStartThing = false,
          touchStartTag = false,
          touchMoves = 0;
        $("section#things li").live("touchstart", function(e) {
          touchStartThing = $(this).index();
          touchMoves = 3;
        });
        $("section#things li").live("touchmove", function(e) {
          if (--touchMoves > 0) return;
          touchStartThing = false;
        });
        $("section#things li").live("touchend", function(e) {
          if (touchStartThing === false) return;
          if (isIPad) {
            updateFlyout($(this).index());
          } else {
            location.href = data[$(this).index()].permalink;
          }
        });
        $("a[data-tag]").live("touchstart touchmove", function(e) {
          touchStartThing = false;
        });
        $("a[data-tag]").live("touchend", function(e) {
          e.preventDefault();
          if (!Thinkery.mainListUrl) return true;
          touchStartThing = false;
          var _tag = $(e.target).data("tag");
          if (typeof _tag == "undefined" || !_tag) return true;
          loadTag(_tag);
          return false;
        });
      }

      $("section#things li a.edit").live("click", function(e) {
        e.preventDefault();
        updateFlyout($(this).closest("li").index(), /* edit */ true);
        return false;
      });

      $('section#flyout .content .icn.edit').live("click", function(e) {
        e.preventDefault();
        $("section#things li.active a.edit").click();
        return false;
      });

      $('section#flyout .content.edit nav.actions button.cancel').live("click", function() {
        if (isTouchDevice) return location.reload();
        $('section#flyout .content.display').show();
        $('section#flyout .content.edit').hide();
        $('section#flyout').css("position", "fixed");
        return false;
      });

      var updatePrivacy = function(r) {
          for (var i = 0, l = data.length; i < l; i++) {
            if (data[i]._id != r._id) continue;
            data[i] = r;
            updateFlyout(i);
            updateList(i);
            updatePublicPrivate(i);
            break;
          }
        };

      $('section#flyout .meta .publicprivate, section#things li span.private, section#things li span.public, section#things li span.shared').live('click', function(e) {
        var i = $(this).closest("section#flyout").length ? $("section#things li.active").index() : $(this).closest("li").index();
        if (!data[i].canEdit) return false;
        var newPrivate = !data[i]["private"];
        var id = data[i]._id;
        $("#tiptip_holder").hide();
        $.post("/save.php", {
          id: id,
          "private": newPrivate ? "private" : "public"
        }, updatePrivacy);
      });

      $('nav#sharing li').live('click', function(e) {
        var $this = $(this);
        if ($this.hasClass("dir")) return false;

        var i = $("section#things li.active").index();
        if (!data[i].canEdit) return false;

        var newPrivate = true;
        var id = data[i]._id;
        switch ($this.text()) {

        case "Public":
          newPrivate = false;
        case "Private":
          $.post("/save.php", {
            id: id,
            "private": newPrivate ? "private" : "public"
          }, updatePrivacy);
          break;

        case "Friends":
          $.prompt($('#shareTagPopup').html(), {
            buttons: {},
            classes: 'share',
            loaded: function(v) {
              var buttons = $("button", "#jqi");
              $("input[name=users]:visible").focus().keyup(function(e) {
                if (e.altKey || e.metaKey || e.ctrlKey) return true;
                var keyCode = (e == null) ? event.keyCode : e.which;
                switch (keyCode) {
                case 13:
                  // buttons.eq(0).click();
                  return false;
                }
              });
              buttons.eq(0).click(function() {
                var users = $("input[name=users]:visible").val();
                $.post("/share.php", {
                  id: id,
                  users: users,
                  allowChange: $("input[name=allowChange]:visible").is(":checked")
                }, function(v) {
                  $.prompt.close();
                  if (typeof v.thing != "undefined") {
                    data[i] = v.thing;
                    updateFlyout(i);
                    updateList(i);
                    updatePublicPrivate(i);
                  }
                  $.prompt("Now these users can view this item: " + v.users.join(", "));
                });
                return false;
              });
              buttons.eq(1).click(function() {
                $.prompt.close();
                return false;
              });
            }
          });
          break;

        }
        return false;
      });

      $('section#flyout .content.edit nav.actions button.save').live("click", function() {
        var edit = $("section#flyout .content.edit");
        var title = edit.find("input.title").val();
        if ($.trim(title).length == 0) {
          $.prompt("The title can't be empty.");
          return false;
        }
        var id = edit.find("input.id").val();
        var tags = $.trim(edit.find("input.tags").val());

        $.post("/save.php", {
          id: id,
          title: title,
          tags: tags,
          url: edit.find("input.url").val(),
          note: edit.find("textarea.note").val(),
          "private": edit.find("select[name=private]").val()
        }, function(r) {
          if (isTouchDevice) return location.reload();

          for (var i = 0, l = data.length; i < l; i++) {
            if (data[i]._id != id) continue;
            data[i] = r;
            updateFlyout(i);
            updateList(i);
            reloadSidebar();

            break;
          }
        });
        $('section#flyout').css("position", "fixed");

        return false;
      });

      $("section#flyout a.delete, section#things li a.delete, section#flyout a.archive, section#things li a.archive").live("click", function() {
        var question, buttons, del = $(this).hasClass("delete");
        var i = $(this).closest("section#flyout").length ? $("section#things li.active").index() : $(this).closest("li").index();
        if (del) {
          question = "<h1 class='border'>Delete</h1>Really delete <i>" + data[i].title + "</i>?";
          buttons = {
            "Yes, delete it": true,
            "Cancel": false
          };
        } else {
          if (data[i].archived) {
            question = "<h1 class='border'>Unarchive</h1>Really unarchive <i>" + data[i].title + "</i>?";
            buttons = {
              "Yes, unarchive it": true,
              "Cancel": false
            };
          } else {
            question = "<h1 class='border'>Archive</h1>Really archive <i>" + data[i].title + "</i>?";
            buttons = {
              "Yes, archive it": true,
              "Cancel": false
            };
          }
        }
        $.prompt(question, {
          buttons: buttons,
          classes: del ? "delete" : "archive",
          callback: function(buttonClicked) {
            if (!buttonClicked || typeof data[i] == "undefined") return false;
            $.post(del ? "/delete.php" : (data[i].archived ? "/archive.php?unarchive" : "/archive.php"), {
              id: data[i]._id
            }, function(r) {
              if (singlePage) {
                if (del) { // item doesn't exist anymore, go to all things
                  location.href = "/" + username;
                  return;
                }
                data[i].archived = !data[i].archived;
              } else {
                if (!del && data[i].archived) {
                  data[i].archived = false;
                } else {
                  data.splice(i, 1);
                }
              }

              reloadSidebar();
              updateList();
              if ($("section#things li").length == 0) {
                $("section#things ul").append("<li>No Things found.</li>");
                $("section#flyout div.content.display").css("visibility", "hidden");
              } else {
                var el = $("section#things li").eq(i).click();
                scrollIntoView(el);
              }
            });
          }
        });
        return false;
      });

      var lastQuery, lastAjax, lastTimeout = null,
        beforeQuery = null,
        tmpQuery, ajaxQueryOld, ajaxQueryCurrent;
      var autocompleteDiv = $('#tag-autocomplete');
      var slStart = null;
      var searchAdd = $('#searchadd').bind('focus focusin mouseenter', function() {
        return true;
        if (check_tag_autocomplete()) {
          // beforeQuery = null;
          searchAdd.keyup();
        }
      });
      var searchField = $('#search').bind('mouseleave click', function(e) {
        return true;
        autocompleteDiv.empty().hide();
      });
      var searchInput = $('#search-input');
      var btns = {
        bir: $("button.ir"),
        hint: $("sub.hint"),
        results: $("sub.results")
      };

      function tag_autocomplete_render(tagName) {
        $("<li>" + tagName + " <span class=\"grey flr\">" + tags[tagName].count + "</span></li>").attr('data-tag', tagName).appendTo(autocompleteDiv).click(function() {
          searchAdd.trigger('tag-autocomplete', tagName);
        });
      }

      function check_tag_autocomplete() {
        slStart = searchAdd.get(0).selectionStart || slStart;
        var sval = searchAdd.val();
        if (sval[sval.length - 1] == " ") return false;
        if (!slStart) {
          var tmp = $.trim(sval).split(" ");

        } else {
          var tmp = $.trim(sval);

          tmp = tmp.substr(0, slStart + 1);

          if (tmp[tmp.length - 1] == " ") return false;
          tmp = tmp.split(" ");
          tmp.reverse();
          for (var i = 0, l = tmp.length; i < l; i++) {
            if (tmp[i][0] == "#") {
              return tmp[i];
            } else {
              return false;
            }
          }
          tmp.reverse();
        }

        tmp.reverse();
        for (var i = 0, l = tmp.length; i < l; i++) {
          if (tmp[i][0] == "#") {
            return tmp[i];
          }
        }

        return false;
      }

      searchAdd.bind('tag-autocomplete', function(evt, tagName) {
        if (!tagName || typeof tagName == "undefined") return;
        // var d = check_tag_autocomplete();

        var tmp = $.trim(searchAdd.val()).split(" ");
        tmp.reverse();
        for (var i = 0, l = tmp.length; i < l; i++) {
          if (tmp[i][0] == "#") {
            tmp[i] = '#' + tagName + " ";
            break;
          }
        }
        tmp.reverse();
        searchAdd.val(tmp.join(" ")).data('tag.added', true);
        autocompleteDiv.empty().hide();
        beforeQuery = null;

        searchAdd.focus().keyup();

        btns.bir.addClass("searchadd").removeClass("add");
        btns.hint.addClass("hidden");
        btns.results.removeClass("hidden");

      }).bind('stop', function() {
        if (lastAjax) lastAjax.abort();
        clearTimeout(lastTimeout);
        searchField.removeClass('searching');
      }).keyup(function() {

        lastQuery = this.value;

        if ($.trim(this.value) == "") {
          searchAdd.trigger('stop');
          btns.bir.addClass("search").removeClass("add").removeClass("searchadd");
          btns.hint.addClass("hidden");
          btns.results.addClass("hidden");
          data = originalData;
          currentQuery = false;
          updateList();
          autocompleteDiv.hide();
          return true;
        }

        if (beforeQuery == lastQuery) return;
        tmpQuery = beforeQuery;
        beforeQuery = lastQuery;

        // vorherigen ajax request abbrechen wenn neue suche angefangen wird
        searchAdd.trigger('stop');

        lastTimeout = setTimeout(function() {
          searchAdd.focus();
          var d = check_tag_autocomplete();

          if (d && d[0] == "#" && searchAdd.data('tag.added') !== true) {
            // tags autocomplete
            if (!autocompleteDiv.size()) {
              autocompleteDiv = $('<ul id="tag-autocomplete" class="tag-autocomplete search">').appendTo("#container");
            }
            autocompleteDiv.empty().hide();
            d = d.toLowerCase();
            var k, q = d.substr(1),
              ql = q.length,
              qk;
            for (k in tags) {
              qk = tags[k].q;
              if (qk.substr(0, ql) == q && k != q) {
                tag_autocomplete_render(k);
              }
            }
            if (autocompleteDiv.find('li:first').addClass('active').size()) {
              autocompleteDiv.show();
              // beforeQuery = null;
              return;
            } else {
              autocompleteDiv.hide();
            }
          } else {
            autocompleteDiv.hide();
          }

          searchAdd.data('tag.added', false);
          //if( $trim(tmpQuery) == $.trim(beforeQuery) ) {

          //}
          ajaxQueryCurrent = $.trim(lastQuery);
          if (ajaxQueryOld == ajaxQueryCurrent) return;


          searchAdd.trigger('stop');
          searchField.addClass('searching');
          lastAjax = $.post("/search.php", {
            q: lastQuery
          }, function(r) {

            ajaxQueryOld = ajaxQueryCurrent;

            // if (lastQuery != r.q) return;
            data = r.result;
            currentQuery = r.q;
            if (data.length == 0) {
              btns.bir.addClass("add").removeClass("search").removeClass("searchadd");
              btns.hint.removeClass("hidden");
              btns.results.addClass("hidden");
            } else {
              btns.bir.addClass("searchadd").removeClass("add");
              btns.hint.addClass("hidden");
              btns.results.removeClass("hidden").text('Search results for "' + (lastQuery.length > 40 ? "..." + lastQuery.substr(lastQuery.length - 20) : lastQuery) + '":');
            }
            updateList();
            retrieveThings();
            searchField.removeClass('searching');

            ajaxQueryOld = ajaxQueryCurrent;

          });

        }, 100);

      });

      $("#toggleBulk").live("click", function(e) {
        var bulkControls = $("#bulkControls");
        if (bulkControls.is(":visible")) {
          hideBulk();
        } else {
          showBulk();
        }
        return false;
      });

      $("#closeBulk").click(function() {
        hideBulk();
        return false;
      });

      $("#toggleAllChecked").click(function(e) {
        var ch = this.checked;
        $("section#things li input.bulk").each(function(i) {
          if (e.shiftKey) this.checked = !this.checked;
          else this.checked = ch;
          data[i].checked = this.checked;
        });
      });

      $("button.bulk").click(function() {
        var checked = $("section#things li:has(input.bulk:checked)");
        var el = this;

        var formSubmit = function(r) {
            if (r == "error" || typeof(r) == "string") {
              $.prompt("An error was reported from the server, please try again." /* + r */ );
              return;
            }

            var ids = {};
            for (var i = 0, l = r.length; i < l; i++) {
              ids[r[i]._id] = r[i];
            }

            var activeIndex = $("section#things li.active").index();
            var updateWholeList = false;
            for (var i = data.length - 1; i >= 0; i--) {
              var j = data[i]._id;
              if (typeof ids[j] == "undefined") continue;
              if (typeof ids[j].deleted != "undefined" && ids[j].deleted) {
                data.splice(i, 1);
                updateWholeList = true;
                continue;
              }
              data[i] = ids[j];
              data[i].checked = true;
              updateList(i);
              if (activeIndex == i) {
                updatePublicPrivate(i);
                updateFlyout(i);
              }
            }
            if (updateWholeList) {
              updateList();
            }
            if (!(el.name == "public" || el.name == "private")) {
              reloadSidebar();
            }
            if (data.length) {
              showBulk();
            } else {
              if (tag != "") loadTag("");
              hideBulk();
            }
          };

        var sendForm = function() {
            var form = $("form[name=bulk]");
            $.post(form.attr("action"), form.serialize() + "&" + el.name + "=" + encodeURIComponent(el.value), formSubmit);
          };

        switch (this.name) {
        case "add-tag":
          if (checked.length == 0) {
            action = "add a tag to";
            break;
          }
          $.prompt('<h1 class="border">Add which tag?</h1><input type="text" name="add-tag" data-only-one="1" /><div class="status"></div>', {
            buttons: {
              "Add tag": true,
              "Cancel": false
            },
            callback: function(buttonClicked, message, fields) {
              if (!buttonClicked) return;
              el.value = fields["add-tag"];
              sendForm();
            },
            loaded: function(v) {
              $("input[name=add-tag]:visible").focus().keyup(function(e) {
                if (e.altKey || e.metaKey || e.ctrlKey) return true;
                var keyCode = (e == null) ? event.keyCode : e.which;
                switch (keyCode) {
                case 13:
                  $(this).closest("#jqi").find("button").eq(0).click();
                }
              });
            },
            submit: function(buttonClicked) {
              if (!buttonClicked) return true;
              var input = $("input[name=add-tag]:visible");
              if ($.trim(input.val()) == "") {
                input.closest("#jqi").find("div.status").addClass("error").html("Please enter a tag.");
                input.focus();
                return false;
              }
              return true;
            }
          });
          return false;

        case "remove-tag":
          if (checked.length == 0) {
            action = "remove a tag from";
            break;
          }

          $.prompt('<h1 class="border">Remove which tag?</h1><input type="text" name="remove-tag" data-only-one="1" /><div class="status"></div>', {
            buttons: {
              "Remove tag": true,
              "Cancel": false
            },
            callback: function(buttonClicked, message, fields) {
              if (!buttonClicked) return;
              el.value = fields["remove-tag"];
              sendForm();
            },
            loaded: function(v) {
              $("input[name=remove-tag]:visible").focus().keyup(function(e) {
                if (e.altKey || e.metaKey || e.ctrlKey) return true;
                var keyCode = (e == null) ? event.keyCode : e.which;
                var jqi = $(this).closest("#jqi");
                switch (keyCode) {
                case 13:
                  jqi.find("button").eq(0).click();
                  return;
                }

                var affected = checked.find("span.tags a[data-tag=\"" + $.trim(this.value).replace('"', '\\"') + "\"]").length;
                if (!affected) {
                  $("div.status", jqi).removeClass("ok").addClass("error").text("None of your selected things have that tag.");
                } else {
                  $("div.status", jqi).removeClass("error").addClass("ok").text(affected + " selected thing" + (affected == 1 ? " has" : "s have") + " this tag.");
                }

              });
            },
            submit: function(buttonClicked) {
              if (!buttonClicked) return true;
              var input = $("input[name=remove-tag]:visible");
              input.val($.trim(input.val()));
              if ($.trim(input.val()) == "") {
                input.closest("#jqi").find("div.status").addClass("error").html("Please enter a tag.");
                input.focus();
                return false;
              }
              var affected = checked.find("span.tags a[data-tag=\"" + input.val().replace('"', '\\"') + "\"]").length;
              if (!affected) return false;
              return true;
            }
          });
          return false;

        case "delete":
          if (checked.length == 0) {
            action = "delete";
            return false;
          }
          var t = checked.length + " thing" + (checked.length == 1 ? "" : "s");
          var buttons = {};
          buttons["Yes, delete " + t] = true;
          buttons["Cancel"] = false;
          $.prompt("<h1 class='Delete'></h1>This will delete " + t + ". This cannot be undone. Are you sure?", {
            buttons: buttons,
            classes: "delete",
            callback: function(buttonClicked) {
              if (!buttonClicked) return;
              sendForm();
            }
          });
          return false;

        case "public":
          action = "publish";
          break;
        case "private":
          action = "make private";
          break;
        case "archive":
          action = "archive";
          break;
        }

        if (checked.length == 0) {
          $.prompt("You haven't marked any things to " + action + ".");
          return false;
        }

        sendForm();
        return false;
      });
    },
    showBulk: showBulk,
    hideBulk: hideBulk,
    tag: function(t) {
      tag = t;
    }
  };
})();

var waiting = {},
  timeout = {},
  last = {};
var showStatus = function(t, status, req, container) {
    if (typeof status == "undefined") status = "ok";

    if (timeout[t]) clearTimeout(timeout[t]);
    if (typeof req == "undefined" || waiting[t] == req) {
      container.find("div.loading img").hide();
    } else {
      return;
    }
    var div = $("div.status", container).text(status).removeClass("untouched");
    if (status == "ok") {
      div.addClass("ok").removeClass("error");
    } else if (status == "") {
      div.removeClass("error").removeClass("ok");
    } else {
      div.addClass("error").removeClass("ok");
    }
  };


var checkField = function(inputField, name) {
    if (timeout[name]) clearTimeout(timeout[name]);
    var container = $(inputField).closest("div");
    timeout[name] = setTimeout(function() {
      container.find("div.loading img").show();
      $("div.status", container).text("");
    }, 100);
    if (typeof waiting[name] == "undefined") waiting[name] = 1;
    else waiting[name] += 1;
    if ($.trim(inputField.value) != inputField.value) inputField.value = $.trim(inputField.value);
    var post = {
      js: 1,
      req: waiting[name]
    };
    post[name] = inputField.value;
    $.post(container.closest("form").attr("action"), post, function(t) {
      var i = t.indexOf(":");
      var status = t.substr(i + 1);
      var req = t.substr(0, i);
      showStatus(name, status, req, container);
    });
  };

$(document).ready(function() {

  $(".toggle").live("click", function() {
    $(this).toggleClass("closed").next().slideToggle("slow");
  });


  var searchInput = $('#search-input input');
  var placeholder = $("#search-input #placeholder");
  if (!isTouchDevice) {
    placeholder.click(function() {
      $(this).hide();
      searchInput.focus();
      return false;
    });
  }

  if (isIPad) {
    $('#search-input').css("marginLeft", "40px");
    searchInput.css("width", "80%");
  }

  var makeFavoriteTag = function(e) {
      var el = $(e.target);
      var li = el.closest("li");
      var tag = li.data("tag");
      if (li.closest("ul").is("#favoriteTags")) {
        li.appendTo("ul#nonFavoriteTags");
        $.post("/favorite-tag.php", {
          remove: tag
        });
      } else {
        li.appendTo("ul#favoriteTags");
        $.post("/favorite-tag.php", {
          add: tag
        });
      }
      var ul = $("ul#favoriteTags");
      ul.children().length ? ul.show() : ul.hide();
    };

  $("#edittags").live("click", function() {
    var lis = $("nav#menu ul li");
    if ($("nav#menu ul li.edit").length) {
      $(this).text("Tag settings");
      $(this).removeClass("active");
      lis.removeClass("edit");
      return false;
    }
    $(this).text("Save settings");
    $(this).addClass("active");

    lis.addClass("edit");
    if (lis.find("div.fav").length) return false; // just display them
    lis.each(function() {
      if (!$(this).data("tag")) return true;
      $("<div>").addClass("fav").click(makeFavoriteTag).prependTo(this);
    });
    return false;
  });

  var hidePlaceholderHelper = function(e) {
      if (e.altKey || e.metaKey || e.ctrlKey) return true;
      var keyCode = (e == null) ? event.keyCode : e.which;
      switch (keyCode) {
      case 38:
        // up
      case 40:
        // down
        this.blur();
        //if (keyCode == 40) {
        //	el = $("section#things li.active").next().click();
        //	scrollIntoView(el);
        //}
        return true;
      }

      if ($.trim(this.value) == "") {
        if (!isTouchDevice && placeholder.is(":hidden")) {
          placeholder.show();
        }
        return true;
      }
      if (placeholder.is(":visible")) {
        placeholder.hide();
      }
      return true;
    };

  var getUrlParameter = function(name) {
      name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
      var regexS = "[\\?&]" + name + "=([^&#]*)";
      var regex = new RegExp(regexS);
      var results = regex.exec(location.href);
      if (!results) return false;
      return results[1];
    };

  searchInput.focus(hidePlaceholderHelper).keyup(hidePlaceholderHelper);
  if (getUrlParameter("from") != "bookmarklet") searchInput.focus();
  else hidePlaceholderHelper({
    which: 0
  });
  searchInput.closest("form").submit(function() {
    if ($.trim(searchInput.val()).length == 0) return false;
  });

  var hover = {
    "section#things ul li": {
      "": {
        "-webkit-transition": "background 250ms linear",
        "-moz-transition": "background 250ms linear",
        "-o-transition": "background 250ms linear",
        transition: "background 250ms linear",
        cursor: "pointer"
      },
      ".actions": {
        "-thinkery-timeout": 400,
        display: "inline-block",
        margin: 0
      },
      ".actions a": {
        border: 0,
        margin: "0 0.5em 0 0",
        "padding-top": "0.25em",
        display: "inline-block"
      },
      ".drag": {
        "-thinkery-timeout": 400,
        display: "block"
      }
    }
  };
  var hoverTimeouts = {};

  if (isTouchDevice) { // apply some hovers on touch device
    for (var selector in hover) {
      for (subselector in hover[selector]) {
        if (!hover[selector][subselector]['-thinkery-mobile']) continue;
        $(this).find(subselector).css(hover[selector][subselector]).addClass("hover");
      }
    }
  } else {
    for (var selector in hover) {
      $(selector).live("mouseenter", function() {
        var t = $(this);
        for (subselector in hover[selector]) {
          if (hover[selector][subselector]["-thinkery-timeout"]) {
            (function(selector, subselector) {
              hoverTimeouts[selector + subselector] = setTimeout(function() {
                if (subselector != "") {
                  t.find(subselector).css(hover[selector][subselector]).end();
                } else t.css(hover[selector][subselector]);
              }, hover[selector][subselector]["-thinkery-timeout"]);
            })(selector, subselector);
          } else {
            if (subselector != "") t.find(subselector).css(hover[selector][subselector]).addClass("hover").end();
            else t.css(hover[selector][subselector]).addClass("hover");
          }
        }
      });
      $(selector).live("mouseleave", function() {
        for (var subselector in hover[selector]) {
          var css = {};
          for (var c in hover[selector][subselector]) {
            if (c.indexOf("transition") > 0) css[c] = hover[selector][subselector];
            else css[c] = "";
          }
          if (hoverTimeouts[selector + subselector]) clearTimeout(hoverTimeouts[selector + subselector]);
          if (subselector != "") $(this).find(subselector).css(css).removeClass("hover").end();
          else $(this).css(css).removeClass("hover");
        }
      });
    }
  }


  Thinkery.registerLazyLoad();

  $(document).keydown(function(e) {
    if (e.altKey || e.metaKey || e.ctrlKey) return true;
    var target = $(e.target);
    var keyCode = (e == null) ? event.keyCode : e.which;

    var autocompleteDiv = $('#tag-autocomplete');
    var el;

    switch (keyCode) {
    case 27:
      // escape
      var display = $('section#flyout .content.display');
      if (display.is(":hidden")) {
        display.show();
        $('section#flyout .content.edit').hide();
      }
      if ($("#jqi").is(":visible")) {
        $.prompt.close();
        return false;
      }

      if ($("#bulkControls").is(":visible")) {
        Thinkery.hideBulk();
        return false;
      }
      if (!autocompleteDiv.is(':hidden')) {
        autocompleteDiv.empty().hide();
      }
      if (searchInput.val() != "") searchInput.trigger('stop').val("").keyup();

      return false;
    }


    if (autocompleteDiv.size() != 0 && !autocompleteDiv.is(':hidden') && $("#searchadd").data('tag.added') !== true && autocompleteDiv.find('li').size() !== 0) {

      switch (keyCode) {
      case 13:
        // enter
      case 9:
        // tab
        // load tag 
        var t = autocompleteDiv.find("li.active").attr('data-tag');
        if (t && autocompleteDiv.find("li.active").size()) {
          searchInput.trigger('tag-autocomplete', t);
          return false;
        }
      case 38:
        // up
        // top
        if (autocompleteDiv.find("li.active").index() == 0) {
          searchInput.focus();
          return true;
        }
        if (autocompleteDiv.find("li").size() == 1) {
          var t = autocompleteDiv.find("li").attr('data-tag');
          searchInput.trigger('tag-autocomplete', t);
          return false;
        }
        autocompleteDiv.find('li.active').removeClass('active').prev().addClass('active');
        return false;
      case 40:
        // down
        if (autocompleteDiv.find("li").size() == 1) {
          var t = autocompleteDiv.find("li").attr('data-tag');
          searchInput.trigger('tag-autocomplete', t);
          return false;
        }
        if (autocompleteDiv.find('li.active').next().size()) {
          autocompleteDiv.find('li.active').removeClass('active').next().addClass('active');
        }
        return false;
      }
      // return;
    }

    if (target.is("input,select,textarea,button") && target.is(":visible")) {
      return true;
    }

    switch (keyCode) {
    case 9:
      // tab
      // searchInput.keyup();
      return false;
    case 13:
      // enter
      if ($.trim(searchInput.val()).length > 0) {
        searchInput.trigger('stop');
        return true;
      }
      var link = $("div.embed a");
      if (!link.length) {
        link = $("section#flyout div.content.edit input.url").val();
        if (link) {
          location.href = link;
          return false;
        }
      }
      location.href = link.eq(0).attr("href");
      return false;
    case 38:
      // up
      if ($("section#things li.active").index() == 0) {
        searchInput.focus();
        return true;
      }
      el = $("section#things li.active").prev().click();
      scrollIntoView(el);
      return false;
    case 40:
      // down
      el = $("section#things li.active").next().click();
      scrollIntoView(el);
      return false;
    }

    var keyPressed = String.fromCharCode(keyCode);
    keyPressed = e.shiftKey ? keyPressed.toUpperCase() : keyPressed.toLowerCase();
    switch (keyPressed) {
    case "e":
      $("section#things li.active a.edit").click();
      return false;
    case "a":
      $("section#things li.active a.archive").click();
      return false;
    case "b":
      $('#toggleBulk').click();
      return false;
    case "m":
      $("section#things li.active input.bulk").click();
      return false;
    case "d":
      $("section#things li.active a.delete").click();
      return false;
    case "s":
      $("#searchadd").focus();
      return false;
    }
    return true;
  });

  $("a.login").live("click", function() {
    $.prompt.close();
    $.prompt($('#loginPopup').html(), {
      buttons: {},
      classes: 'login',
      loaded: function(v) {
        $("input[name=username]:visible").focus();
      }
    });
    return false;
  });

  $("div#notifications a.clear").live("click", function(e) {
    $(e.target).siblings().remove();
    $("a.notifications").closest("li").remove();
    $.post("/notifications.php", {
      clear: 1
    });
    return false;
  });

  if (!isTouchDevice) { // don't use tooltips on mobile device
    $(".tip").tipTip({
      delay: 100,
      edgeOffset: 5
    });
  }

  $('div.expandable').expander({
    slicePoint: 500,
    // default is 100
    expandText: '[More]',
    // default is 'read more...'
    collapseTimer: 0,
    // re-collapses after 5 seconds; default is 0, so no re-collapsing
    userCollapseText: '[Less]' // default is '[collapse expanded text]'
  });

  $("ul.dropdown li.dir").live("click", function(e) {
    var $this = $(e.target);
    if ($this.closest("li.open").length) return true;
    $this.closest("li").addClass("open");
    return false;
  });

  $("body").live('click touchend', function(e) {
    if ($(e.target).closest("li.open").length > 0) return true; // click within the dropdown: ok
    var openDropdown = $("ul.dropdown li.open");
    if (openDropdown.length == 0) return true;
    openDropdown.removeClass("open");
    return false;
  });

  /*
   * @group Tag Autocompleter fuer Edit, Bulk Edit/Remove Forms
   */
  ;
  (function() {
    var slStart;

    function check_tag_autocomplete(inp) {
      try {
        slStart = inp.get(0).selectionStart || slStart;
      } catch (err) {}
      var sval = inp.val();
      if (sval[sval.length - 1] == " ") return false;
      if (!slStart) {
        var tmp = $.trim(sval).split(" ");
      } else {
        var tmp = $.trim(sval);

        tmp = tmp.substr(0, slStart + 1);

        if (tmp[tmp.length - 1] == " ") return false;
        tmp = tmp.split(" ");
        tmp.reverse();
        if (tmp.length) return tmp[0];

      }

      tmp.reverse();
      if (tmp.length) return tmp[0];

      return false;
    }

    function tag_autocomplete_render(tagName, autocompleteUL, inp) {
      $("<li>" + tagName + " <span class=\"grey flr\">" + Thinkery.tags[tagName].count + "</span></li>").attr('data-tag', tagName).appendTo(autocompleteUL).click(function() {
        inp.trigger('tag-autocomplete', tagName);
      });
    }

    $('input.tags,input[name=add-tag],input[name=remove-tag]').live('tag-autocompleter', function(e) {
      var that = $(this),
        autoTag = check_tag_autocomplete(that),
        autocompleteUL = that.next('.tag-autocomplete');

      var oldv = that.data('oldv');
      if (oldv != that.val()) {
        that.data('oldv', that.val());
        if (autoTag) {
          if (!autocompleteUL.size()) {
            autocompleteUL = $('<ul class="tag-autocomplete edit">').insertAfter(that);
            autocompleteUL.parents('#jqibox,form,#container').bind('mousedown', function(e) {
              if (e.target && $(e.target).parent('.tag-autocomplete').size()) {
                return false;
              }
              autocompleteUL.hide();
            });
          }
          autocompleteUL.empty().hide();
          var ql = autoTag.length,
            k, qk;
          var tags = ("|" + that.val().split(" ").join("|") + "|").toLowerCase();
          autoTag = autoTag.toLowerCase();
          for (k in Thinkery.tags) {
            qk = Thinkery.tags[k].q;
            if (qk.substr(0, ql) == autoTag && autoTag !== qk && tags.indexOf("|" + qk + "|") == -1) {
              tag_autocomplete_render(k, autocompleteUL, that);
            }
          }
          if (autocompleteUL.find('li').size()) {
            autocompleteUL.find('li:first').addClass('active');
            autocompleteUL.show();
          } else {
            autocompleteUL.hide();
          }
        } else {
          autocompleteUL.hide();
        }
      }

    }).live('tag-autocomplete', function(e, tagName) {
      var that = $(this),
        tmp = $.trim(that.val()).split(" "),
        onlyone = that.attr('data-only-one') ? true : false,
        autocompleteUL = that.next('.tag-autocomplete');

      //slStart = this.selectionStart || slStart;
      //if( slStart > -1 ) {
      //}
      if (onlyone) {
        that.val(tagName);
      } else {
        tmp.reverse();
        for (var i = 0, l = tmp.length; i < l; i++) {
          tmp[i] = tagName + " ";
          break;
        }
        tmp.reverse();
        that.val(tmp.join(" "));
      }

      autocompleteUL.empty().hide();
      that.focus();
    }).live('keyup', function() {
      var that = $(this);
      that.trigger('tag-autocompleter');

    }).live('keydown', function(e) {
      if (!e) return;
      var keyCode = e.which,
        that = $(this),
        keyPressed = String.fromCharCode(keyCode),
        autocompleteUL = that.next('.tag-autocomplete');

      that.trigger('tag-autocompleter');


      switch (keyCode) {
      case 9:
        // tab
        // case 13: // enter
        if (autocompleteUL.find('li.active').size()) {
          autocompleteUL.find('li.active').trigger('click');
          return false;
        }
        return true;
        break;
      case 38:
        // up
        if (autocompleteUL.find('li.active').prev().size()) {
          autocompleteUL.find('li.active').removeClass('active').prev().addClass('active');
        } else {
          autocompleteUL.find('li.active').trigger('click');
        }
        if (autocompleteUL.find('li.active').size()) return false;
        return true;
        break;
      case 40:
        // down
        if (autocompleteUL.find('li.active').next().size()) {
          autocompleteUL.find('li.active').removeClass('active').next().addClass('active');
        } else {
          autocompleteUL.find('li.active').trigger('click');
        }
        if (autocompleteUL.find('li.active').size()) return false;
        return true;
        break;
      }
    });
  })(); /* @end */

  /* @group dragAndDrop for Things in Sidebar tags */
  ;
  (function() {
    var menu = $('#menu'),
      dragOptions = {
        opacity: 0.7,
        zIndex: 600,
        helper: 'clone',
        // scope: 'tags',
        appendTo: 'body',
        handle: '.drag',
        cursorAt: {
          left: 50
        },
        start: function() {
          menu.addClass('drag-drop-enabled');
        },
        stop: function() {
          menu.removeClass('drag-drop-enabled');
        }
      },
      dropOptions = {
        accept: '.thing-list-item',
        activeClass: 'ui-state-highlight',
        hoverClass: 'drophover',
        tolerance: 'pointer',
        // scope: 'tags',
        drop: function(event, ui) {
          var drag = ui.draggable;
          if (!drag.size()) return;
          var id = drag.find('.bulk').val(),
            tag = $(this).attr('data-tag');

          var thing = Thinkery.findThingById(id);
          if (!thing) {
            // error
            return;
          }

          if (!tag) {
            // prompt new tag window
            $.prompt('<h1 class="border">Add which tag?</h1><input type="text" name="add-tag" data-only-one="1" /><div class="status"></div>', {
              buttons: {
                "Add tag": true,
                "Cancel": false
              },
              callback: function(buttonClicked, message, fields) {
                if (!buttonClicked) return;
                Thinkery.saveThing({
                  id: thing._id,
                  title: thing.title,
                  tags: $.trim(thing.textTags + " " + fields["add-tag"])
                }, function() {
                  Thinkery.reloadSidebar();
                });
                return;
              },
              loaded: function(v) {
                $("input[name=add-tag]:visible").focus().keyup(function(e) {
                  if (e.altKey || e.metaKey || e.ctrlKey) return true;
                  var keyCode = (e == null) ? event.keyCode : e.which;
                  switch (keyCode) {
                  case 13:
                    $(this).closest("#jqi").find("button").eq(0).click();
                  }
                });
              },
              submit: function(buttonClicked) {
                if (!buttonClicked) return true;
                var input = $("input[name=add-tag]:visible");
                if ($.trim(input.val()) == "") {
                  input.closest("#jqi").find("div.status").addClass("error").html("Please enter a tag.");
                  input.focus();
                  return false;
                }
                return true;
              }
            });
            return;
          }

          Thinkery.saveThing({
            id: thing._id,
            title: thing.title,
            tags: $.trim(thing.textTags + " " + tag)
          });
        }
      };


    $(window).bind('things-list-updated', function(event, data) {
      $('#things .thing-list-item').draggable(dragOptions);
    });

    $(window).bind('reloadSidebar', function(event, data) {
      $("#nonFavoriteTags li,#favoriteTags li,#menu .create-new-tag").droppable(dropOptions);
    });

    $('#things .thing-list-item').draggable(dragOptions);
    $("#nonFavoriteTags li,#favoriteTags li,#menu .create-new-tag").droppable(dropOptions);

/*
		$('#things .thing-list-item').live( 'mousedown', function( e ){
			e.preventDefault();
			console.log( e );
			
		} ).live( 'mouseup mousleave', function(){
			
		} )
		*/
  })(); /* @end */
});
var scrollIntoView = function(el) {
	if (!el || !el.length) return;
	var h = window.innerHeight - $("section#things").position().top, eh = el.height();
	var p = el.position().top, b = $(window).scrollTop();
	if (p + eh > b + h || p < b) {
		$("html,body").stop().animate({scrollTop: Math.floor(p + eh - h / 2) + "px"}, 400);
	}
};

var implodeTextList = function(list) {
	var startTag = "<b>", endTag = "</b>";
	if (typeof list[0] != "string") return list;
	if (list.length == 1) return startTag + list[0] + endTag;
	var tempList = list.slice();
	var last = startTag + tempList.pop() + endTag;
	return startTag + tempList.join(endTag + ", " + startTag) + endTag + " and " + last;
};

var isTouchDevice = (function() {
	var android = navigator.userAgent.indexOf('Android') != -1;
	return android || !!('createTouch' in document);
	//return typeof Touch == "object";
})();
var isIPad = navigator.userAgent.match(/iPad/i) != null;

var Thinkery = (function() {
	var username, tag, data, originalData, singlePage, currentQuery = false;
	if (typeof jQuery.prompt != 'undefined') jQuery.prompt.setDefaults({
		persistent: false,
		opacity: 0.7,
		show: "fadeIn",
		overlayspeed: "fast",
		promptspeed: "fast",
		top: "25%"
	});
	
	// impromptu for mobile devices
	if (typeof jQuery.prompt != 'undefined' && isTouchDevice) jQuery.prompt.setDefaults({
		persistent: false,
		opacity: 0.7,
		show: "show",
		overlayspeed: "fast",
		promptspeed: "fast",
		top: "5%"
	});
	
	var updateTimeLeft = function(timeLeft) {
		var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
		function timeLeft(secs, shortDate) {
			if (typeof shortDate == "undefined") shortDate = true;
			
			var ago = false;
			if (secs < 0) {
				secs = -secs;
				ago = true;
			}
			
			var x, s, t = [];
			
			if (secs >= 3456000) { // 40 days
				s = new Date(new Date() - secs * 1000);
				return months[s.getMonth()] + " " + s.getDate() + ", " + s.getFullYear();
			}
			if (secs >= 86400) {
				s = Math.floor(secs / 86400);
				x = s + " d" + (shortDate ? "" : "ay");
				if (!shortDate && s > 1) x += "s";
				t.push(x);
				secs -= s * 86400;
			}
			
			if (secs >= 3600) {
				s = Math.floor(secs / 3600);
				x = s + " h" + (shortDate ? "r" : "our");
				if (s > 1) x += "s";
				t.push(x);
				secs -= s * 3600;
			}
			
			if (secs >= 60) {
				s = Math.floor(secs / 60);
				x = s + " min" + (shortDate ? "" : "ute");
				if (s > 1) x += "s";
				t.push(x);
				secs -= s * 60;
			}
			
			if (t.length == 0) {
				if (!secs) {
					t.push("just before");
					ago = false;
				}
				else t.push(parseInt(secs, 10) + "s");
			}
			
			var ret = "";
			s = "";
			for (var i = Math.min(1, t.length - 1); i >= 0; i--) {
				ret = t[i] + s + ret;
				s = (shortDate || s) ? ", " : " and ";
			}
			
			return ret + (ago ? " ago" : "");
		}
		$("span.dateTime").each(function() {
			var $this = $(this);
			var t = $this.attr("data-t").split(",");
			var time = new Date;
			time.setUTCHours(parseInt(t[3], 10));
			time.setUTCMinutes(parseInt(t[4], 10));
			time.setUTCSeconds(parseInt(t[5], 10));
			time.setUTCMonth(0);
			time.setUTCFullYear(t[0]);
			time.setUTCDate(parseInt(t[2], 10));
			time.setUTCMonth(parseInt(t[1], 10) - 1);
			
			var diff = (time.getTime() - new Date) / 1000;
			$this.text(timeLeft(diff, !$this.hasClass("long")));
		});
	};
	
	setInterval(updateTimeLeft, 30000);
	
	var lastTag = false;
	var loadTag = function(_tag, initialLoad, nonEmpty ) {
		if (typeof initialLoad == "undefined") initialLoad = false;
		if (!Thinkery.mainListUrl) return false;
		if (_tag == lastTag) return false;
		lastTag = _tag;
		
		var tagUrlPart = _tag ? "tag=" + encodeURIComponent(_tag) : "";
		$.getJSON(Thinkery.mainListUrl + tagUrlPart, function(r) {
			
			if (initialLoad && data.length == 0) {
				location.href = "/" + username;
				return;
			}
			var tags = $("nav#menu ul li").removeClass("active");
			if (typeof _tag == "undefined" || !_tag ) {
				if (typeof history.pushState == "function") history.pushState({tag: ""}, username, "/" + username);
				tags.filter("li:contains(All)").addClass("active");
				tag = false;
			} else {
				_tag = String(_tag);
				if (typeof history.pushState == "function") history.pushState({tag: _tag}, username + " - " + _tag, "/" + username + "/" + _tag);
				tags.filter("li[data-tag='" + _tag.replace("'", "\\'") + "']").addClass("active");
				tag = _tag;
			}
			
			_gaq.push(['_trackPageview', '/' + username + "/" + tag]);
			
			originalData = data = r;
			$("section#things ul").show(function() {
				var searchAdd = $("#searchadd");
				if (nonEmpty == true) {
					
				} else if (searchAdd.val() != "") {
					searchAdd.val("").keyup();
				}
				$("button.ir").addClass("search").removeClass("add");
				$("sub.results, sub.hint").addClass("hidden");
				updateList();
				$("section#things ul li:first").addClass("active");
				$("section#things ul").fadeIn();
				if ($("#bulkControls").is(":visible")) showBulk();
			});
			retrieveThings();
			registerLazyLoad();
			updateFlyout(0, false, true);
		});
		return false;
	};
	
	var retrieveQueue = 0, retrieveTimeout = false;
	// update items that have not been retrieved
	var retrieveThings = function() {
		if (retrieveTimeout) {
			clearTimeout(retrieveTimeout);
			if (retrieveQueue > 3) {
				retrieveTimeout = setTimeout(retrieveThings, 3000);
				return;
			}
		}
		var l = data.length;
		for (var i = 0; i < l; i++) {
			if (data[i].retrieved) continue;
			if (retrieveQueue > 3) {
				retrieveTimeout = setTimeout(retrieveThings, 3000);
				break;
			}
			retrieveQueue += 1;
			data[i].thinking = true;
			updateList(i);
			$.ajax({
				url: "/retrieve.php",
				type: "post",
				data: {id: data[i]._id},
				success: function(r) {
					retrieveQueue -= 1;
					if (typeof r._id == "undefined") return false;
					for (var i = 0, l = data.length; i < l; i++) {
						if (data[i]._id != r._id) continue;
						data[i] = r;
						if ($("section#things li.active").index() == i) updateFlyout(i);
						updateList(i);
						break;
					}
				},
				error: function() {
					retrieveQueue -= 1;
				}
			});
		}
	};
	
	/* Check if more things can be loaded */
	var checkMore = function() {
		var l = $('section#things li:not(.no-thing)').length;
		var s = $('#searchadd');
		var num = parseInt($('#menu li.active .num').text(), 10);
		if (isNaN(num)) num = 0;
		
		if (!l || l >= num || (s.length !== 0 && s.val() !== '')) {
			$('.loadmore').addClass('inactive').find('a').text('');
			return false;
		}
		
		$('.loadmore').removeClass('inactive').find('a').text('Show more ↓');
		return true;
	};
	
	/* init Lazy Loading */
	var registerLazyLoad = function(initLoad) {
		if (typeof initLoad == 'undefined') initLoad = false;
		
		//page init
		$('section#things').data('page', 0);
		checkMore();
		
		$(window).unbind('scroll').bind('scroll', function() {
			if ($(window).scrollTop() != $(document).height() - $(window).height()) return;
			
			setTimeout(function() {
				if ($(window).scrollTop() != $(document).height() - $(window).height()) return;
				loadThings(initLoad);
			}, 300);
		});
		
		$('.loadmore a').unbind('click').live('click', function(e) {
			e.preventDefault();
			loadThings(initLoad);
		});
	};
	
	/* load more things */
	var loadThings = function(noargs) {
		if (!checkMore()) return;
		
		//show loader, increment page count
		$('section#things, .loadmore').addClass('loading');
		$('section#things').data('page', parseInt($('section#things').data('page'), 10) + 1);

		if (typeof noargs !== 'undefined' && noargs ) {
			var _data = {
				'page': 0
			};
		} else {
			var tag = $('#menu ul li.active').attr('data-tag');
			var page = $('section#things').data('page');
			
			var _data = {
				'page': page
			};
			if (typeof tag !== 'undefined' && tag !== '') {
				$.extend(_data, {'tag': encodeURIComponent(tag)});
			}
			if (document.URL.split("?")[1] == 'archived') {
				$.extend(_data, {'archived': true});
			}
			if ( $('#search h4 a').text() !== "" ) {
				$.extend(_data, {'username': $('#search h4 a').text()});
			}
		}
		var url, _type = "get";
		if (currentQuery) {
			url = '/search.php';
			_type = "post";
		} else if (typeof Thinkery.mainListUrl == "undefined") {
			url = '/mainlist.php';
		} else {
			url = Thinkery.mainListUrl;
		}
		
		$.ajax({
			url: url,
			dataType: 'json',
			data: _data,
			type: _type,
			success: function(r) {
				if (r == '') {
					$('.loadmore').addClass('inactive').find('a').text('');
				} else {
					updateData(r);
					retrieveThings();
				}
				$('section#things, .loadmore').removeClass('loading');
			}
		});
	};
	
	var reloadSidebar = function(full) {
		if (typeof full == "undefined") full = false;
		var sidebarUrl = "/sidebar.php?username=" + encodeURIComponent(username);
		if (tag) sidebarUrl += "&tag=" + encodeURIComponent(tag);
		if (location.search == "?archived") sidebarUrl += "&archived";
		if (full) sidebarUrl += "&full";
		var favorites = $("#edittags").hasClass("active");
		
		$("nav#menu").load(sidebarUrl + " nav#menu>*", function() {
			if ($("#bulkControls").is(":visible")) {
				$('#toggleBulk').addClass("active");
			}
			if (favorites) {
				$("#edittags").click();
			}
			$(window).trigger( 'reloadSidebar' );
		});
		
		
	};
	
	var updateData = function(d) {
		if (!d) {
			$('.loadmore').addClass('inactive').find('a').text('');
			return;
		}
		for (i = 0, l = d.length; i < l; i++) {
			data.push(d[i]);
		}
		originalData = data;
		updateList();
	};
	
	var getPrivacyIcon = function(tmp) {
		return '<span class="icn grey ' + getPrivacyClass(tmp) + ' tip ' + (tmp.canEdit ? 'canEdit' : '') + ' title="' + getPrivacyTitle(tmp) + '"></span>';
	};
	
	var getPrivacyTitle = function(tmp, html) {
		if (typeof html == "undefined") html = false;
		var privacyTitle = "Private: only you can see it";
		if (!tmp["private"]) {
			privacyTitle = "Public: everybody can see it";
			if (tmp.shared) {
				privacyTitle += '; also shared between ' + implodeTextList(tmp.shared);
			}
		} else if (tmp.shared) {
			privacyTitle = 'Shared between ' + implodeTextList(tmp.shared);
		}
		if (!html) privacyTitle = privacyTitle.replace(/</g, "&lt;").replace(/>/g, "&gt;");
		return privacyTitle;
	};
	
	var getPrivacyIconText = function(tmp) {
		var friends = tmp.shared ? tmp.shared.length - 1 : 0;
		var privacyIconText = "Private";
		if (!tmp["private"]) {
			privacyIconText = "Public" + (friends > 0 ? " + " + friends + ' Friend' + (friends == 1 ? "" : "s") : "");
		} else if (tmp.shared) {
			privacyIconText = friends + ' Friend' + (friends == 1 ? "" : "s");
		}
		return privacyIconText;
	};
	
	var getPrivacyClass = function(tmp) {
		var privacyClass = "private";
		if (!tmp["private"]) {
			privacyClass = "public";
		} else if (tmp.shared) {
			privacyClass = "shared";
		}
		return privacyClass;
	};
	
	var updateList = function(i) {
		bulkedit = $("#bulkControls").is(":visible");
		var listItem;
		
		if (typeof i != "undefined") {
			var tmp = data[i];
			listItem = $("section#things li").eq(i);
			if (tmp.archived) {
				listItem.addClass("archived");
			} else {
				listItem.removeClass("archived");
			}
			var allClasses = listItem[0].className.split(" ");
			for (var o = 0, l = allClasses.length; o < l; o++) {
				if (allClasses[o].substr(0, 6) == "thing-") listItem.removeClass(allClasses[o]);
			}
			for (var o = 0, l = tmp.classNames.length; o < l; o++) {
				listItem.addClass(tmp.classNames[o]);
			}
			$("article", listItem).html(tmp.htmlTitle + ((typeof tmp.thinking != "undefined" && tmp.thinking) ? '<img src="/img/loading.gif" class="loader" /> <span class="smaller grey">thinking...</span>' : "")).highlight(currentQuery);
			$("span.tags", listItem).html(tmp.tags);
			var p = $("span.public, span.private, span.shared", listItem);
			
			var privacyClass = getPrivacyClass(tmp);
			p.removeClass("private public shared").addClass(privacyClass).attr("title", getPrivacyTitle(tmp, true)).tipTip();
			if (privacyClass == "private") $("div.privacy", listItem).hide();
			else $("div.privacy", listItem).show();
			
			var bulk = $("input.bulk", listItem);
			bulk.attr("checked", typeof tmp.checked != "undefined" && tmp.checked);
			if (tmp.canEdit && bulkedit) {
				bulk.show();
			} else {
				bulk.hide();
			}
			return;
		}
		var actions, active;
		
		if (typeof i == "undefined" && $('section#things li.active').length != 0) {
			active = $("section#things li.active").index();
		}

		if (data.length == 0) {
			$("section#things ul").text("").append($("ul#noThingTemplate li").clone());
			return;
		}
		
		var list = $("section#things ul"), html = "", oldFirstId = $("section#flyout input.id").val(), firstId = false, tmp, l;
		for (j = 0, l = data.length; j < l; j++) {
			tmp = data[j];
			listItem = "<li class=\"thing-list-item";
			if (tmp.archived) listItem += ' archived';
			if (tmp.classNames) listItem += ' ' + tmp.classNames.join(" ");
			if (tmp.todoStatus) listItem += ' checked';
			listItem += '">';
			if (tmp.canEdit) listItem += '<span class="drag"></span>';
			var privacyIcon = getPrivacyIcon(tmp);
			listItem += '<div class="privacy"' + ((!tmp.shared || !tmp.shared.length) && tmp["private"] ? ' style="display: none"' : '') + '>' + privacyIcon + "</div>";
			listItem += '<input type="checkbox" name="bulk[]" value="' + tmp._id + '" class="bulk" ' + (typeof tmp.checked != "undefined" && tmp.checked ? ' checked="checked"' : '') + ' />';
			listItem += '<input type="checkbox" class="todo" ' + (typeof tmp.todoStatus != "undefined" && tmp.todoStatus ? ' checked="checked"' : '') + ' />';
			listItem += '<article>' + tmp.htmlTitle + ((typeof tmp.thinking != "undefined" && tmp.thinking) ? '<img src="/img/loading.gif" class="loader" /> <span class="smaller grey">thinking...</span>' : "") + "</article>";
			actions = "";
			actions += privacyIcon;
			if (tmp.canEdit) {
				actions += "<a href=\"\" class=\"icn edit tip\" title=\"Edit\">&nbsp;</a>"+
					"<a href=\"\" class=\"icn archive tip\" title=\""+(tmp.archived ? "Unarchive" : "Move to archive")+"\">&nbsp;</a>"+
					"<a href=\"\" class=\"icn delete tip\" title=\"Delete\">&nbsp;</a>";
			}
			listItem += "<sub class=\"meta\">" +
						"<span class=\"tags\">" + tmp.tags + "</span> <span data-t=\"" + tmp.date + "\" class=\"info grey dateTime\">just before</span>" +
						"<span class=\"actions\">"+ actions + "</span>"+
					"</sub>";
			listItem += "</li>";
			
			html += listItem;
		}
		list.html(html);
		
		//check if element and/or edit-mode is active
		if (typeof i == 'undefined') i = active;
		if (typeof i != "undefined") {
			if ($('section#flyout .content.edit').is(":hidden")) {
				updateFlyout(i);
			}
			$('section#things li').eq(i).addClass('active');
		}
		
		$("section#things li article").highlight(currentQuery);
		$("section#things li span.tags").highlight(currentQuery);
		
		checkMore();
		if (typeof data[0] == "undefined") {
			$("section#flyout .content").hide();
			
		} /*else if (oldFirstId) {
			updateFlyout(0, false, false);
		}*/
		
		updateTimeLeft();
		$(window).trigger( 'things-list-updated', data );
	};
	
	var updatePublicPrivate = function(i) {
		var content = $("section#flyout div.content.display");
		var active = $("section#things li").eq(i).hasClass("active");
		var a = $("nav#sharing ul.dropdown>li>a>span"), pp = $("span.publicprivate", content), permalink = $("a.permalink", content);
		var tmp = data[i];
		if (active) {
			if (tmp.canEdit) $("nav#sharing").show(); else $("nav#sharing").hide();
			$("nav#sharing ul ul a").removeClass("active");
		}
		var friends = tmp.shared ? tmp.shared.length - 1 : 0;
		
		var text = getPrivacyIconText(tmp);
		var privacyClass = getPrivacyClass(tmp);
		pp.text(text).removeClass("private public shared").addClass(privacyClass).attr("title", getPrivacyTitle(tmp, true)).tipTip();
		permalink.attr("title", privacyClass == "private" ? "Private Permalink" : "Public Permalink: use this URL to share it with shared").tipTip();
		if (active) {
			a.text(text).removeClass("private public shared").addClass(privacyClass);
			$("nav#sharing ul ul a." + privacyClass).addClass("active");
		}
	};
	
	var updateFlyout = function(i, showEdit, fade) {
		if (typeof showEdit == "undefined") showEdit = false;
		if (typeof data[i] == "undefined") return false;
		if (typeof fade == "undefined") fade = true;
		var tmp = data[i];
		
		$("section#things li").eq(i).addClass("active").siblings().removeClass("active");
		var content = $("section#flyout div.content.display");
		var edit = $("section#flyout div.content.edit");
		var show = showEdit ? edit : content;
		var showIt = function() {
			if (tmp.url) {
				$("h1.linked a", content).html(tmp.htmlTitle).attr("href", tmp.url).highlight(currentQuery);
				$("h1.linked", content).show();
				$("h1.unlinked", content).hide();
			} else {
				$("h1.unlinked", content).html(tmp.htmlTitle).show().highlight(currentQuery);
				$("h1.linked", content).hide();
			}
			$("div.embed", content).html(tmp.html).highlight(currentQuery);
			$("span.tags", content).html(tmp.tags).highlight(currentQuery);
			$("span.dateTime", show).attr("data-t", tmp.date);
			if (tmp.htmlNote && $.trim(String(tmp.htmlNote).replace("<br>", "")).length) {
				$("details", content).html(tmp.htmlNote).show().highlight(currentQuery);
				$("a.icn.edit.note", content).hide();
			} else {
				$("details", content).hide();
				$("a.icn.edit.note", content).show();
			}
			$("a.icn.archive", content).text(tmp.archived ? "Unarchive" : "Archive").attr("title", tmp.archived ? "Unarchive" : "Move to archive");
			$("a.permalink", content).attr("href", tmp.permalink);
			if (tmp.canEdit) $("nav.actions").show(); else $("nav.actions").hide();
			updatePublicPrivate(i);
			
			$("input.title", edit).val(tmp.title);
			$("input.url", edit).val(tmp.url ? tmp.url : "");
			$("input.tags", edit).val(tmp.textTags);
			$("input.id", edit).val(tmp._id);
			$("textarea.note", edit).val(tmp.note ? tmp.note : "");
			$("select[name=private]", edit).eq(0).attr("selectedIndex", tmp["private"] ? 0 : 1);
			
			updateTimeLeft();
			var afterShow = function() {
				if (showEdit) {
					var editor = $("textarea.note", edit).cleditor({
					width: "99%",
						height: "12%",
						controls: "bold italic underline strikethrough | bullets numbering | link unlink | style highlight | undo redo | source",
						styles: [["Paragraph", "<p>"], ["Header 1", "<h1>"], ["Header 2", "<h2>"],
						["Header 3", "<h3>"],  ["Header 4","<h4>"],  ["Header 5","<h5>"],
						["Header 6","<h6>"]]
					})[0].updateFrame().focus();
					var resizeEditor = function() {
						var d = $("div.cleditorMain");
						var p = d.offset();
						d.height(Math.max(200, $(window).height() - p.top - 135));
						editor.refresh();
					};
					
					resizeEditor();
					if ($(window).scrollTop() == $(document).height() - $(window).height()) {
						$(window).scrollTop( $(window).scrollTop()- 50);
					}
					//$('#flyout .content.edit').scrollTop(0);
					$(window).unbind("resize").resize(resizeEditor);
					$("input.title", edit).focus();
				}
			};
			if (fade) {
				show.fadeIn(20, afterShow);
			} else {
				show.show();
				afterShow();
			}
		};
		if (fade) {
			$(content).add(edit).filter(":visible").fadeOut(10, showIt);
		} else {
			$(content).add(edit).filter(":visible").hide();
			showIt();
		}
	};
	
	var showBulk = function() {
		var bulkControls = $("#bulkControls").show();
		
		var c = 0;
		var unarchive = bulkControls.find("button[name=unarchive]"),
		    archive   = bulkControls.find("button[name=archive]"),
		    publ   = bulkControls.find("button[name=public]"),
		    priv   = bulkControls.find("button[name=private]");
		
		if ($("section#things li.archived").length) {// has things that are archived
			unarchive.parent().show(); // so offer the unarchive button
			c++;
		} else {
			unarchive.parent().hide();
		}
		
		if ($("section#things li:not(.archived)").length) { // has things that are not archived
			archive.parent().show(); // so offer the archive button
			c++;
		} else {
			archive.parent().hide();
		}
		
		if ($("section#things li span.private").length) { // has things that are private
			publ.parent().show(); // so offer the public button
			c++;
		} else {
			publ.parent().hide();
		}
		
		if ($("section#things li span.public").length) { // has things that are public
			priv.parent().show(); // so offer the private button
			c++;
		} else {
			priv.parent().hide();
		}
		
		if (c > 3) {
			publ.text("public");
			priv.text("private");
		} else {
			publ.text("make public");
			priv.text("make private");
		}
		
		if (c > 2) {
			$("#closeBulk").text("[x]");
		} else {
			$("#closeBulk").text("[x] close");
		}
		$("section#things li").addClass("bulkedit");
		$("#toggleAllChecked").attr("checked", false);
		$('#toggleBulk').addClass("active");
	};
	
	var hideBulk = function() {
		$("#bulkControls").hide();
		$("section#things li").removeClass("bulkedit");
		$('#toggleBulk').removeClass("active");
	};
	
	var tags = {};
	
	return {
		registerLazyLoad: registerLazyLoad,
		loadTag: loadTag,
		loadThings: loadThings,
		updateList: updateList,
		reloadSidebar: reloadSidebar,
		findThingById: function( _id ){
			for( var i=0, l = data.length; i < l; i++ ) {
				if( data[i]._id == _id ) return data[i];
			}
			return false;
		},
		saveThing: function( thing, cb, err ){
			$.post("/save.php", thing, function( r ) {
				if( !r || !r._id ) {
					if( err ) err();
					return;
				}
				for(var i = 0, l = data.length; i < l; i++) {
					if ( data[i]._id != r._id ) continue;
					data[i] = r;
					updateFlyout(i);
					updatePublicPrivate(i);
					updateList(i);
				}
				if( cb ) cb();
			});
		},
		load: function(_username, _data, _singlePage, _tags ) {
			for( var k in _tags ) {
				_tags[k]['q'] = k.toLowerCase();
				tags[k] = _tags[k];
			}
			Thinkery.tags = tags;
			
			username = _username;
			originalData = data = _data;
			singlePage = typeof _singlePage == "boolean" ? _singlePage : false;
			$('#main').attr('username', username);
			
			retrieveThings();
			
			$("nav#menu ul li a").live("click", function(e) {
				if (!Thinkery.mainListUrl) return true;
				var li = $(e.target).closest("li");
				if (li.closest("nav#filter").length) return true;
				
				var _tag = li.data("tag");
				
				if (!li.data("all") && (typeof _tag == "undefined" || !_tag)) {
					if (!tag) return true;
					location.href = "/" + username + "/" + tag + (e.target.search == "?archived" ? "?archived" : "");
					return false;
				}
				
				if (li.hasClass("smart")) _tag = "smart:" + _tag;
				
				loadTag(_tag);
				return false;
			});
			
			$("nav#menu ul li span.settings, nav#menu #addsmartfolder").live("click", function(e) {
				$.prompt($("#smartfolderTemplate").html(), {
					buttons: {"Save": true, "Cancel": false},
					classes: 'share',
					loaded: function(v) {
						var buttons = $("button", "#jqi table");
						function firstRemoveButton() {
							var rows = $("tr", "#jqi table");
							var firstRemove = rows.find("button.remove");
							if (rows.length == 1) firstRemove.attr("disabled", true);
							else firstRemove.attr("disabled", false);
						}
						firstRemoveButton();
						
						buttons.live("click", function(r) {
							var button = $(r.target);
							if (button.hasClass("add")) {
								$("#jqi table").append($("#smartfolderTemplate tr").clone());
							} else if (button.hasClass("remove")) {
								button.closest("tr").remove();
							}
							firstRemoveButton();
						});
					}
				});
				return false;
			});
			
			$("a[data-tag]").live("click", function(e) {
				if (!Thinkery.mainListUrl) return true;
				var _tag = $(e.target).data("tag");
				if (typeof _tag == "undefined" || !_tag) return true;
				loadTag(_tag);
				return false;
			});
			
			$('nav#menu .moretags a').live("click", function(e) {
				var $this = $(this);
				var expanded = !$this.hasClass('expanded');
				var p = $this.parent();
				var loaded = p.hasClass('loaded');

				if (expanded) {
					$this.html("Fewer tags &uarr;");
					this.className = "expanded";
					
					if (!loaded) {
						$this.html("<img src='/img/loading.gif' />");
						reloadSidebar(true);
					} else {
						$("ul#nonFavoriteTags li").show();
					}
				} else {
					$this.html("All tags &darr;");
					this.className = "collapsed";
					$("ul#nonFavoriteTags li:gt(9)").hide();
				}
				
				$('nav#menu').css("position", expanded ? "absolute" : "fixed");
				return false;
			});
			
			$("section#things li").live("click", function(e) {
				if (e.shiftKey) {
					var i = $("section#things li.active").index();
					var j = $(this).index();
					if (j < i) {
						var k = j;
						j = i;
						i = k;
					}
					var bulks = $("section#things li input.bulk");
					if ($("#bulkControls").is(":hidden")) bulks.attr("checked", false);
					for (; i <= j; i++) {
						data[i].checked = true;
						bulks.eq(i).attr("checked", true);
					}
					showBulk();
					return false;
				}
				updateFlyout($(this).index());
			});
			
			$("section#things li input.todo").live("click", function(e) {
				var li = $(this).closest("li");
				var i = li.index();
				data[i].todoStatus = this.checked;
				if (this.checked) li.addClass("checked"); else li.removeClass("checked");
				$.post("/save.php", {id: data[i]._id, "todo": this.checked ? "checked" : "not-checked" });
			});
			
			$("section#things li input.bulk").live("click", function(e) {
				data[$(this).closest("li").index()].checked = this.checked;
			});
			
			if (isTouchDevice) {
				var touchStartThing = false, touchStartTag = false, touchMoves = 0;
				$("section#things li").live("touchstart", function(e) {
					touchStartThing = $(this).index();
					touchMoves = 3;
				});
				$("section#things li").live("touchmove", function(e) {
					if (--touchMoves > 0) return;
					touchStartThing = false;
				});
				$("section#things li").live("touchend", function(e) {
					if (touchStartThing === false) return;
					if (isIPad) {
						updateFlyout($(this).index());
					} else {
						location.href = data[$(this).index()].permalink;
					}
				});
				$("a[data-tag]").live("touchstart touchmove", function(e) {
					touchStartThing = false;
				});
				$("a[data-tag]").live("touchend", function(e) {
					e.preventDefault();
					if (!Thinkery.mainListUrl) return true;
					touchStartThing = false;
					var _tag = $(e.target).data("tag");
					if (typeof _tag == "undefined" || !_tag) return true;
					loadTag(_tag);
					return false;
				});
			}
			
			$("section#things li a.edit").live("click", function(e) {
				e.preventDefault();
				updateFlyout($(this).closest("li").index(), /* edit */ true);
				return false;
			});
			
			$('section#flyout .content .icn.edit').live("click", function(e)  {
				e.preventDefault();
				$("section#things li.active a.edit").click();
				return false;
			});

			$('section#flyout .content.edit nav.actions button.cancel').live("click", function()  {
				if (isTouchDevice) return location.reload();
				$('section#flyout .content.display').show();
				$('section#flyout .content.edit').hide();
				$('section#flyout').css("position", "fixed");
				return false;
			});
			
			var updatePrivacy = function(r) {
				for (var i = 0, l = data.length; i < l; i++) {
					if (data[i]._id != r._id) continue;
					data[i] = r;
					updateFlyout(i);
					updateList(i);
					updatePublicPrivate(i);
					break;
				}
			};
			
			$('section#flyout .meta .publicprivate, section#things li span.private, section#things li span.public, section#things li span.shared').live('click', function(e) {
				var i = $(this).closest("section#flyout").length ? $("section#things li.active").index() : $(this).closest("li").index();
				if (!data[i].canEdit) return false;
				var newPrivate = !data[i]["private"];
				var id = data[i]._id;
				$("#tiptip_holder").hide();
				$.post("/save.php", {id: id, "private": newPrivate ? "private" : "public" }, updatePrivacy);
			});
			
			$('nav#sharing li').live('click', function(e) {
				var $this = $(this);
				if ($this.hasClass("dir")) return false;
				
				var i = $("section#things li.active").index();
				if (!data[i].canEdit) return false;
				
				var newPrivate = true;
				var id = data[i]._id;
				switch ($this.text()) {
					
					case "Public":
						newPrivate = false;
					case "Private":
						$.post("/save.php", {id: id, "private": newPrivate ? "private" : "public" }, updatePrivacy);
						break;
						
					case "Friends":
						$.prompt($('#shareTagPopup').html(), {
							buttons: {},
							classes: 'share',
							loaded: function(v) {
								var buttons = $("button", "#jqi");
								$("input[name=users]:visible").focus().keyup(function(e) {
									if (e.altKey || e.metaKey || e.ctrlKey) return true;
									var keyCode = (e == null) ? event.keyCode : e.which;
									switch (keyCode) {
										case 13:
											// buttons.eq(0).click();
											return false;
									}
								});
								buttons.eq(0).click(function() {
									var users = $("input[name=users]:visible").val();
									$.post("/share.php", {id: id, users: users, allowChange: $("input[name=allowChange]:visible").is(":checked")}, function(v) {
										$.prompt.close();
										if (typeof v.thing != "undefined") {
											data[i] = v.thing;
											updateFlyout(i);
											updateList(i);
											updatePublicPrivate(i);
										}
										$.prompt("Now these users can view this item: " + v.users.join(", "));
									});
									return false;
								});
								buttons.eq(1).click(function() {
									$.prompt.close();
									return false;
								});
							}
						});
						break;
					
				}
				return false;
			});
			
			$('section#flyout .content.edit nav.actions button.save').live("click", function()  {
				var edit = $("section#flyout .content.edit");
				var title = edit.find("input.title").val();
				if ($.trim(title).length == 0) {
					$.prompt("The title can't be empty.");
					return false;
				}
				var id = edit.find("input.id").val();
				var tags = $.trim(edit.find("input.tags").val());
				
				$.post("/save.php", {id: id, title: title, tags: tags, url: edit.find("input.url").val(), note: edit.find("textarea.note").val(), "private": edit.find("select[name=private]").val() }, function(r) {
					if (isTouchDevice) return location.reload();
					
					for (var i = 0, l = data.length; i < l; i++) {
						if (data[i]._id != id) continue;
						data[i] = r;
						updateFlyout(i);
						updateList(i);
						reloadSidebar();
						
						break;
					}
				});
				$('section#flyout').css("position", "fixed");
				
				return false;
			});
			
			$("section#flyout a.delete, section#things li a.delete, section#flyout a.archive, section#things li a.archive").live("click", function() {
				var question, buttons, del = $(this).hasClass("delete");
				var i = $(this).closest("section#flyout").length ? $("section#things li.active").index() : $(this).closest("li").index();
				if (del) {
					question = "<h1 class='border'>Delete</h1>Really delete <i>" + data[i].title + "</i>?";
					buttons = {"Yes, delete it": true, "Cancel": false};
				} else {
					if (data[i].archived) {
						question = "<h1 class='border'>Unarchive</h1>Really unarchive <i>" + data[i].title + "</i>?";
						buttons = {"Yes, unarchive it": true, "Cancel": false};
					} else {
						question = "<h1 class='border'>Archive</h1>Really archive <i>" + data[i].title + "</i>?";
						buttons = {"Yes, archive it": true, "Cancel": false};
					}
				}
				$.prompt(question, {
					buttons: buttons,
					classes: del ? "delete" : "archive",
					callback: function(buttonClicked) {
						if (!buttonClicked || typeof data[i] == "undefined") return false;
						$.post(del ? "/delete.php" : (data[i].archived ? "/archive.php?unarchive" : "/archive.php"), {id: data[i]._id}, function(r) {
							if (singlePage) {
								if (del) { // item doesn't exist anymore, go to all things
									location.href = "/" + username;
									return;
								}
								data[i].archived = !data[i].archived;
							} else {
								if (!del && data[i].archived) {
									data[i].archived = false;
								} else {
									data.splice(i, 1);
								}
							}
							
							reloadSidebar();
							updateList();
							if ($("section#things li").length == 0) {
								$("section#things ul").append("<li>No Things found.</li>");
								$("section#flyout div.content.display").css("visibility", "hidden");
							} else {
								var el = $("section#things li").eq(i).click();
								scrollIntoView(el);
							}
						});
					}
				});
				return false;
			});
			
			var lastQuery, lastAjax, lastTimeout = null, beforeQuery = null, tmpQuery, ajaxQueryOld, ajaxQueryCurrent;
			var autocompleteDiv = $('#tag-autocomplete');
			var slStart = null;
			var searchAdd = $('#searchadd').bind('focus focusin mouseenter', function(){
				return true;
				if( check_tag_autocomplete() ) {
					// beforeQuery = null;
					searchAdd.keyup();
				}
			});
			var searchField = $('#search').bind( 'mouseleave click', function(e){
				return true;
				autocompleteDiv.empty().hide();
			} );
			var searchInput = $('#search-input');
			var btns = {
				bir: $("button.ir"),
				hint: $("sub.hint"),
				results: $("sub.results")
			};
			
			function tag_autocomplete_render( tagName ){
				$("<li>"+tagName+" <span class=\"grey flr\">"+tags[tagName].count+"</span></li>").attr('data-tag',tagName).appendTo( autocompleteDiv ).click( function(){
					searchAdd.trigger( 'tag-autocomplete', tagName );
				} );
			}
			
			function check_tag_autocomplete() {
				slStart = searchAdd.get(0).selectionStart || slStart;
				var sval = searchAdd.val();
				if( sval[sval.length-1] == " " ) return false;
				if( !slStart ) {
					var tmp = $.trim( sval ).split( " " );
					
				} else {
					var tmp = $.trim( sval );
					
					tmp = tmp.substr( 0, slStart+1 );
					
					if( tmp[tmp.length-1] == " " ) return false;
					tmp = tmp.split( " " );
					tmp.reverse();
					for( var i=0, l = tmp.length; i < l; i++ ) {
						if( tmp[i][0] == "#" ) {
							return tmp[i];
						} else {
							return false;
						}
					}
					tmp.reverse();
				}
				
				tmp.reverse();
				for( var i=0, l = tmp.length; i < l; i++ ) {
					if( tmp[i][0] == "#" ) {
						return tmp[i];
					}
				}
				
				return false;
			}
			
			searchAdd.bind('tag-autocomplete', function( evt, tagName ){
				if( !tagName || typeof tagName == "undefined" ) return;
				// var d = check_tag_autocomplete();
				
				var tmp = $.trim( searchAdd.val() ).split( " " );
				tmp.reverse();
				for( var i=0, l = tmp.length; i < l; i++ ) {
					if( tmp[i][0] == "#" ) {
						tmp[i] = '#' + tagName + " ";
						break;
					}
				}
				tmp.reverse();
				searchAdd.val( tmp.join( " " ) ).data( 'tag.added', true );
				autocompleteDiv.empty().hide();
				beforeQuery = null;
				
				searchAdd.focus().keyup();
				
				btns.bir.addClass("searchadd").removeClass("add");
				btns.hint.addClass("hidden");
				btns.results.removeClass("hidden");
				
			}).bind('stop',function(){
				if (lastAjax) lastAjax.abort();
				clearTimeout(lastTimeout);
				searchField.removeClass( 'searching' );
			}).keyup(function() {
				
				lastQuery = this.value;
				
				if( $.trim(this.value) == "" ) {
					searchAdd.trigger('stop');
					btns.bir.addClass("search").removeClass("add").removeClass("searchadd");
					btns.hint.addClass("hidden");
					btns.results.addClass("hidden");
					data = originalData;
					currentQuery = false;
					updateList();
					autocompleteDiv.hide();
					return true;
				}
				
				if( beforeQuery == lastQuery ) return;
				tmpQuery = beforeQuery;
				beforeQuery = lastQuery;
				
				// vorherigen ajax request abbrechen wenn neue suche angefangen wird
				searchAdd.trigger('stop');
				
				lastTimeout = setTimeout(function() {
					searchAdd.focus();
					var d = check_tag_autocomplete();
					
					if( d && d[0] == "#" && searchAdd.data( 'tag.added' ) !== true ) {
						// tags autocomplete
						if( !autocompleteDiv.size() ) {
							autocompleteDiv = $('<ul id="tag-autocomplete" class="tag-autocomplete search">').appendTo( "#container" );
						}
						autocompleteDiv.empty().hide();
						d = d.toLowerCase();
						var k, q = d.substr( 1 ), ql = q.length, qk;
						for( k in tags ) {
							qk = tags[k].q;
							if( qk.substr( 0, ql ) == q && k != q ) {
								tag_autocomplete_render( k );
							}
						}
						if( autocompleteDiv.find( 'li:first' ).addClass('active').size() ) {
							autocompleteDiv.show();
							// beforeQuery = null;
							return;
						} else {
							autocompleteDiv.hide();
						}
					} else {
						autocompleteDiv.hide();
					}
					
					searchAdd.data( 'tag.added', false );
					//if( $trim(tmpQuery) == $.trim(beforeQuery) ) {
						
					//}
					ajaxQueryCurrent = $.trim(lastQuery);
					if( ajaxQueryOld == ajaxQueryCurrent ) return;
					
					
					searchAdd.trigger('stop');
					searchField.addClass( 'searching' );
					lastAjax = $.post("/search.php", { q: lastQuery }, function(r) {
						
						ajaxQueryOld = ajaxQueryCurrent;
						
						// if (lastQuery != r.q) return;
						data = r.result;
						currentQuery = r.q;
						if (data.length == 0) {
							btns.bir.addClass("add").removeClass("search").removeClass("searchadd");
							btns.hint.removeClass("hidden");
							btns.results.addClass("hidden");
						} else {
							btns.bir.addClass("searchadd").removeClass("add");
							btns.hint.addClass("hidden");
							btns.results.removeClass("hidden").text(
								'Search results for "' + (lastQuery.length > 40 ? "..." + lastQuery.substr(lastQuery.length - 20) : lastQuery) + '":'
							);
						}
						updateList();
						retrieveThings();
						searchField.removeClass( 'searching' );
						
						ajaxQueryOld = ajaxQueryCurrent;
						
					});
					
				}, 100 );
				
			});
			
			$("#toggleBulk").live("click", function(e) {
				var bulkControls = $("#bulkControls");
				if (bulkControls.is(":visible")) {
					hideBulk();
				} else {
					showBulk();
				}
				return false;
			});
			
			$("#closeBulk").click(function() {
				hideBulk();
				return false;
			});
			
			$("#toggleAllChecked").click(function(e) {
				var ch = this.checked;
				$("section#things li input.bulk").each(function(i) {
					if (e.shiftKey) this.checked = !this.checked;
					else this.checked = ch;
					data[i].checked = this.checked;
				});
			});
			
			$("button.bulk").click(function() {
				var checked = $("section#things li:has(input.bulk:checked)");
				var el = this;
				
				var formSubmit = function(r) {
					if (r == "error" || typeof(r) == "string") {
						$.prompt("An error was reported from the server, please try again." /* + r */);
						return;
					}
					
					var ids = {};
					for (var i = 0, l = r.length; i < l; i++) {
						ids[r[i]._id] = r[i];
					}
					
					var activeIndex = $("section#things li.active").index();
					var updateWholeList = false;
					for (var i = data.length - 1; i >= 0; i--) {
						var j = data[i]._id;
						if (typeof ids[j] == "undefined") continue;
						if (typeof ids[j].deleted != "undefined" && ids[j].deleted) {
							data.splice(i, 1);
							updateWholeList = true;
							continue;
						}
						data[i] = ids[j];
						data[i].checked = true;
						updateList(i);
						if (activeIndex == i) {
							updatePublicPrivate(i);
							updateFlyout(i);
						}
					}
					if (updateWholeList) {
						updateList();
					}
					if (!(el.name == "public" || el.name == "private")) {
						reloadSidebar();
					}
					if (data.length) {
						showBulk();
					} else {
						if (tag != "") loadTag("");
						hideBulk();
					}
				};
				
				var sendForm = function() {
					var form = $("form[name=bulk]");
					$.post(form.attr("action"), form.serialize() + "&" + el.name + "=" + encodeURIComponent(el.value), formSubmit);
				};
				
				switch (this.name) {
					case "add-tag":
						if (checked.length == 0) {
							action = "add a tag to";
							break;
						}
						$.prompt('<h1 class="border">Add which tag?</h1><input type="text" name="add-tag" data-only-one="1" /><div class="status"></div>', {
							buttons: { "Add tag": true, "Cancel": false},
							callback: function (buttonClicked, message, fields) {
								if (!buttonClicked) return;
								el.value = fields["add-tag"];
								sendForm();
							},
							loaded: function(v) {
								$("input[name=add-tag]:visible").focus().keyup(function(e) {
									if (e.altKey || e.metaKey || e.ctrlKey) return true;
									var keyCode = (e == null) ? event.keyCode : e.which;
									switch (keyCode) {
										case 13:
											$(this).closest("#jqi").find("button").eq(0).click();
									}
								});
							},
							submit: function(buttonClicked) {
								if (!buttonClicked) return true;
								var input = $("input[name=add-tag]:visible");
								if ($.trim(input.val()) == "") {
									input.closest("#jqi").find("div.status").addClass("error").html("Please enter a tag.");
									input.focus();
									return false;
								}
								return true;
							}
						});
						return false;
						
					case "remove-tag":
						if (checked.length == 0) {
							action = "remove a tag from";
							break;
						}
						
						$.prompt('<h1 class="border">Remove which tag?</h1><input type="text" name="remove-tag" data-only-one="1" /><div class="status"></div>', {
							buttons: { "Remove tag": true, "Cancel": false},
							callback: function (buttonClicked, message, fields) {
								if (!buttonClicked) return;
								el.value = fields["remove-tag"];
								sendForm();
							},
							loaded: function(v) {
								$("input[name=remove-tag]:visible").focus().keyup(function(e) {
									if (e.altKey || e.metaKey || e.ctrlKey) return true;
									var keyCode = (e == null) ? event.keyCode : e.which;
									var jqi = $(this).closest("#jqi");
									switch (keyCode) {
										case 13:
											jqi.find("button").eq(0).click();
											return;
									}
									
									var affected = checked.find("span.tags a[data-tag=\"" + $.trim(this.value).replace('"', '\\"') +  "\"]").length;
									if (!affected) {
										$("div.status", jqi).removeClass("ok").addClass("error").text("None of your selected things have that tag.");
									} else {
										$("div.status", jqi).removeClass("error").addClass("ok").text(affected + " selected thing" + (affected == 1 ? " has" : "s have") + " this tag.");
									}
									
								});
							},
							submit: function(buttonClicked) {
								if (!buttonClicked) return true;
								var input = $("input[name=remove-tag]:visible");
								input.val( $.trim(input.val()) );
								if ($.trim(input.val()) == "") {
									input.closest("#jqi").find("div.status").addClass("error").html("Please enter a tag.");
									input.focus();
									return false;
								}
								var affected = checked.find("span.tags a[data-tag=\"" + input.val().replace('"', '\\"') +  "\"]").length;
								if (!affected) return false;
								return true;
							}
						});
						return false;
						
					case "delete":
						if (checked.length == 0) {
							action = "delete";
							return false;
						}
						var t = checked.length + " thing" + (checked.length == 1 ? "" : "s");
						var buttons = {};
						buttons["Yes, delete " + t] = true;
						buttons["Cancel"] = false;
						$.prompt("<h1 class='Delete'></h1>This will delete " + t + ". This cannot be undone. Are you sure?", {
							buttons: buttons,
							classes: "delete",
							callback: function(buttonClicked) {
								if (!buttonClicked) return;
								sendForm();
							}
						});
						return false;
						
						case "public": action = "publish"; break;
						case "private": action = "make private"; break;
						case "archive": action = "archive"; break;
				}
				
				if (checked.length == 0) {
					$.prompt("You haven't marked any things to " + action + ".");
					return false;
				}
				
				sendForm();
				return false;
			});
		},
		showBulk: showBulk,
		hideBulk: hideBulk,
		tag: function(t) {
			tag = t;
		}
	};
})();

var waiting = {}, timeout = {}, last = {};
var showStatus = function(t, status, req, container) {
	if (typeof status == "undefined") status = "ok";
	
	if (timeout[t]) clearTimeout(timeout[t]);
	if (typeof req == "undefined" || waiting[t] == req) {
		container.find("div.loading img").hide();
	} else {
		return;
	}
	var div = $("div.status", container).text(status).removeClass("untouched");
	if (status == "ok") {
		div.addClass("ok").removeClass("error");
	} else if (status == "") {
		div.removeClass("error").removeClass("ok");
	} else {
		div.addClass("error").removeClass("ok");
	}
};


var checkField = function(inputField, name) {
	if (timeout[name]) clearTimeout(timeout[name]);
	var container = $(inputField).closest("div");
	timeout[name] = setTimeout(function() {
		container.find("div.loading img").show();
		$("div.status", container).text("");
	}, 100);
	if (typeof waiting[name] == "undefined") waiting[name] = 1;
	else waiting[name] += 1;
	if ($.trim(inputField.value) != inputField.value) inputField.value = $.trim(inputField.value);
	var post = {js: 1, req: waiting[name]};
	post[name] = inputField.value;
	$.post(container.closest("form").attr("action"), post, function(t) {
		var i = t.indexOf(":");
		var status = t.substr(i + 1);
		var req = t.substr(0, i);
		showStatus(name, status, req, container);
	});
};

$(document).ready(function() {
	
	$(".toggle").live("click", function () {
		$(this).toggleClass("closed").next().slideToggle("slow");
	});
	
	
	var searchInput = $('#search-input input');
	var placeholder = $("#search-input #placeholder");
	if (!isTouchDevice) {
		placeholder.click(function() {
			$(this).hide();
			searchInput.focus();
			return false;
		});
	}
	
	if (isIPad) {
		$('#search-input').css("marginLeft", "40px");
		searchInput.css("width", "80%");
	}

	var makeFavoriteTag = function(e) {
		var el = $(e.target);
		var li = el.closest("li");
		var tag = li.data("tag");
		if (li.closest("ul").is("#favoriteTags")) {
			li.appendTo("ul#nonFavoriteTags");
			$.post("/favorite-tag.php", {remove: tag});
		} else {
			li.appendTo("ul#favoriteTags");
			$.post("/favorite-tag.php", {add: tag});
		}
		var ul = $("ul#favoriteTags");
		ul.children().length ? ul.show() : ul.hide();
	};
	
	$("#edittags").live("click", function() {
		var lis = $("nav#menu ul li");
		if ($("nav#menu ul li.edit").length) {
			$(this).text("Tag settings");
			$(this).removeClass("active");
			lis.removeClass("edit");
			return false;
		}
		$(this).text("Save settings");
		$(this).addClass("active");
		
		lis.addClass("edit");
		if (lis.find("div.fav").length) return false; // just display them
		lis.each(function() {
			if (!$(this).data("tag")) return true;
			$("<div>").addClass("fav").click(makeFavoriteTag).prependTo(this);
		});
		return false;
	});
	
	var hidePlaceholderHelper = function(e) {
		if (e.altKey || e.metaKey || e.ctrlKey) return true;
		var keyCode = (e == null) ? event.keyCode : e.which;
		switch (keyCode) {
			case 38: // up
			case 40: // down
				this.blur();
				//if (keyCode == 40) {
				//	el = $("section#things li.active").next().click();
				//	scrollIntoView(el);
				//}
				return true;
		}
		
		if ($.trim(this.value) == "") {
			if (!isTouchDevice && placeholder.is(":hidden")) {
				placeholder.show();
			}
			return true;
		}
		if (placeholder.is(":visible")) {
			placeholder.hide();
		}
		return true;
	};
	
	var getUrlParameter = function(name) {
		name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
		var regexS = "[\\?&]" + name + "=([^&#]*)";
		var regex = new RegExp(regexS);
		var results = regex.exec(location.href);
		if (!results) return false;
		return results[1];
	};
	
	searchInput.focus(hidePlaceholderHelper).keyup(hidePlaceholderHelper);
	if (getUrlParameter("from") != "bookmarklet") searchInput.focus(); else hidePlaceholderHelper({which: 0});
	searchInput.closest("form").submit(function() {
		if ($.trim(searchInput.val()).length == 0) return false;
	});
	
	var hover = {
		"section#things ul li": {
			"": {
				"-webkit-transition": "background 250ms linear",
				"-moz-transition": "background 250ms linear",
				"-o-transition": "background 250ms linear",
				transition: "background 250ms linear",
				cursor: "pointer"
			},
			".actions": {
				"-thinkery-timeout": 400,
				display: "inline-block",
				margin: 0
			},
			".actions a": {
				border: 0,
				margin: "0 0.5em 0 0",
				"padding-top": "0.25em",
				display: "inline-block"
			},
			".drag": {
				"-thinkery-timeout": 400,
				display: "block"
			}
		}
	};
	var hoverTimeouts = {};
	
	if (isTouchDevice) { // apply some hovers on touch device
		for (var selector in hover) {
			for (subselector in hover[selector]) {
				if (!hover[selector][subselector]['-thinkery-mobile']) continue;
				$(this).find(subselector).css(hover[selector][subselector]).addClass("hover");
			}
		}
	} else {
		for (var selector in hover) {
			$(selector).live("mouseenter", function() {
				var t = $(this);
				for (subselector in hover[selector]) {
					if (hover[selector][subselector]["-thinkery-timeout"]) {
						(function(selector, subselector) {
							hoverTimeouts[selector + subselector] = setTimeout(function() {
								if (subselector != "") {
									t.find(subselector).css(hover[selector][subselector]).end();
								}
								else t.css(hover[selector][subselector]);
							}, hover[selector][subselector]["-thinkery-timeout"]);
						})(selector, subselector);
					} else {
						if (subselector != "") t.find(subselector).css(hover[selector][subselector]).addClass("hover").end();
						else t.css(hover[selector][subselector]).addClass("hover");
					}
				}
			});
			$(selector).live("mouseleave", function() {
				for (var subselector in hover[selector]) {
					var css = {};
					for (var c in hover[selector][subselector]) {
						if (c.indexOf("transition") > 0) css[c] = hover[selector][subselector];
						else css[c] = "";
					}
					if (hoverTimeouts[selector + subselector]) clearTimeout(hoverTimeouts[selector + subselector]);
					if (subselector != "") $(this).find(subselector).css(css).removeClass("hover").end();
					else $(this).css(css).removeClass("hover");
				}
			});
		}
	}
	

	Thinkery.registerLazyLoad();
	
	$(document).keydown(function(e) {
		if (e.altKey || e.metaKey || e.ctrlKey) return true;
		var target = $(e.target);
		var keyCode = (e == null) ? event.keyCode : e.which;
		
		var autocompleteDiv = $('#tag-autocomplete');
		var el;
		
		switch (keyCode) {
			case 27: // escape
				var display = $('section#flyout .content.display');
				if (display.is(":hidden")) {
					display.show();
					$('section#flyout .content.edit').hide();
				}
				if ($("#jqi").is(":visible")) {
					$.prompt.close();
					return false;
				}
				
				if ($("#bulkControls").is(":visible")) {
					Thinkery.hideBulk();
					return false;
				}
				if( !autocompleteDiv.is(':hidden') ) {
					autocompleteDiv.empty().hide();
				}
				if (searchInput.val() != "") searchInput.trigger('stop').val("").keyup();
				
				return false;
		}
		
		
		if( autocompleteDiv.size() != 0 && !autocompleteDiv.is(':hidden') && $("#searchadd").data( 'tag.added' ) !== true && autocompleteDiv.find('li').size() !== 0 ) {
			
			switch (keyCode) {
				case 13: // enter
				case 9: // tab
					// load tag 
					var t = autocompleteDiv.find("li.active").attr('data-tag');
					if( t && autocompleteDiv.find("li.active").size() ) {
						searchInput.trigger( 'tag-autocomplete', t );
						return false;
					}
				case 38: // up
					// top
					if ( autocompleteDiv.find("li.active").index() == 0 ) {
						searchInput.focus();
						return true;
					}
					if( autocompleteDiv.find("li").size() == 1 ) {
						var t = autocompleteDiv.find("li").attr('data-tag');
						searchInput.trigger( 'tag-autocomplete', t );
						return false;
					}
					autocompleteDiv.find('li.active').removeClass('active').prev().addClass('active');
					return false;
				case 40: // down
					if( autocompleteDiv.find("li").size() == 1 ) {
						var t = autocompleteDiv.find("li").attr('data-tag');
						searchInput.trigger( 'tag-autocomplete', t );
						return false;
					}
					if( autocompleteDiv.find('li.active').next().size() ) {
						autocompleteDiv.find('li.active').removeClass('active').next().addClass('active');
					}
					return false;
			}
			// return;
		}
		
		if (target.is("input,select,textarea,button") && target.is(":visible")) {
			return true;
		}
		
		switch (keyCode) {
			case 9: // tab
				// searchInput.keyup();
				return false;
			case 13: // enter
				if ($.trim(searchInput.val()).length > 0) {
					searchInput.trigger( 'stop' );
					return true;
				}
				var link = $("div.embed a");
				if (!link.length) {
					link = $("section#flyout div.content.edit input.url").val();
					if (link) {
						location.href = link;
						return false;
					}
				}
				location.href = link.eq(0).attr("href");
				return false;
			case 38: // up
				if ($("section#things li.active").index() == 0) {
					searchInput.focus();
					return true;
				}
				el = $("section#things li.active").prev().click();
				scrollIntoView(el);
				return false;
			case 40: // down
				el = $("section#things li.active").next().click();
				scrollIntoView(el);
				return false;
		}
		
		var keyPressed = String.fromCharCode(keyCode);
		keyPressed = e.shiftKey ? keyPressed.toUpperCase() : keyPressed.toLowerCase();
		switch (keyPressed) {
			case "e":
				$("section#things li.active a.edit").click();
				return false;
			case "a":
				$("section#things li.active a.archive").click();
				return false;
			case "b":
				$('#toggleBulk').click();
				return false;
			case "m":
				$("section#things li.active input.bulk").click();
				return false;
			case "d":
				$("section#things li.active a.delete").click();
				return false;
			case "s":
				$("#searchadd").focus();
				return false;
		}
		return true;
	});
	
	$("a.login").live("click", function() {
		$.prompt.close();
		$.prompt($('#loginPopup').html(), {
			buttons: {},
			classes: 'login',
			loaded: function(v) {
				$("input[name=username]:visible").focus();
			}
		});
		return false;
	});
	
	$("div#notifications a.clear").live("click", function(e) {
		$(e.target).siblings().remove();
		$("a.notifications").closest("li").remove();
		$.post("/notifications.php", { clear: 1 });
		return false;
	});
	
	if (!isTouchDevice) { // don't use tooltips on mobile device
		$(".tip").tipTip({
			delay: 100,
			edgeOffset: 5}
		);
	}
	
	$('div.expandable').expander({
		slicePoint: 500,  // default is 100
		expandText: '[More]', // default is 'read more...'
		collapseTimer: 0, // re-collapses after 5 seconds; default is 0, so no re-collapsing
		userCollapseText: '[Less]'  // default is '[collapse expanded text]'
	});
	
	$("ul.dropdown li.dir").live("click", function(e) {
		var $this = $(e.target);
		if ($this.closest("li.open").length) return true;
		$this.closest("li").addClass("open");
		return false;
	});
	
	$("body").live('click touchend', function(e) {
		if ($(e.target).closest("li.open").length > 0) return true; // click within the dropdown: ok
		var openDropdown = $("ul.dropdown li.open");
		if (openDropdown.length == 0) return true;
		openDropdown.removeClass("open");
		return false;
	});
	
	/*
	 * @group Tag Autocompleter fuer Edit, Bulk Edit/Remove Forms
	 */
	;(function(){
		var slStart;
		
		function check_tag_autocomplete( inp ){
			try {
				slStart = inp.get(0).selectionStart || slStart;
			} catch(err) {}
			var sval = inp.val();
			if( sval[sval.length-1] == " " ) return false;
			if( !slStart ) {
				var tmp = $.trim( sval ).split( " " );
			} else {
				var tmp = $.trim( sval );
				
				tmp = tmp.substr( 0, slStart+1 );
				
				if( tmp[tmp.length-1] == " " ) return false;
				tmp = tmp.split( " " );
				tmp.reverse();
				if( tmp.length )
					return tmp[0];
				
			}
			
			tmp.reverse();
			if( tmp.length )
				return tmp[0];
			
			return false;
		}
		
		function tag_autocomplete_render( tagName, autocompleteUL, inp ){
			$("<li>"+tagName+" <span class=\"grey flr\">"+Thinkery.tags[tagName].count+"</span></li>").attr('data-tag',tagName).appendTo( autocompleteUL ).click( function(){
				inp.trigger( 'tag-autocomplete', tagName );
			} );
		}
		
		$('input.tags,input[name=add-tag],input[name=remove-tag]').live('tag-autocompleter', function(e){
			var that = $(this),
					autoTag = check_tag_autocomplete( that ),
					autocompleteUL = that.next('.tag-autocomplete');
			
			var oldv = that.data('oldv');
			if( oldv != that.val() ) {
				that.data('oldv', that.val() );
				if( autoTag ) {
					if( !autocompleteUL.size() ) {
						autocompleteUL = $( '<ul class="tag-autocomplete edit">' ).insertAfter(that);
						autocompleteUL.parents( '#jqibox,form,#container' ).bind( 'mousedown', function( e ){
							if( e.target && $(e.target).parent('.tag-autocomplete').size() ) {
								return false;
							}
							autocompleteUL.hide();
						} );
					}
					autocompleteUL.empty().hide();
					var ql = autoTag.length, k, qk;
					var tags = ("|" + that.val().split( " " ).join("|") + "|").toLowerCase();
					autoTag = autoTag.toLowerCase();
					for( k in Thinkery.tags ) {
						qk = Thinkery.tags[k].q;
						if( qk.substr( 0, ql ) == autoTag && autoTag !== qk && tags.indexOf( "|" + qk + "|" ) == -1 ) {
							tag_autocomplete_render( k, autocompleteUL, that );
						}
					}
					if( autocompleteUL.find('li').size() ) {
						autocompleteUL.find('li:first').addClass('active');
						autocompleteUL.show();
					} else {
						autocompleteUL.hide();
					}
				} else {
					autocompleteUL.hide();
				}
			}
				
		} ).live('tag-autocomplete', function( e, tagName ){
			var that = $(this),
					tmp = $.trim( that.val() ).split( " " ),
					onlyone = that.attr( 'data-only-one' ) ? true : false,
					autocompleteUL = that.next('.tag-autocomplete');
			
			//slStart = this.selectionStart || slStart;
			//if( slStart > -1 ) {
			//}
			if( onlyone ) {
				that.val( tagName );
			} else {
				tmp.reverse();
				for( var i=0, l = tmp.length; i < l; i++ ) {
					tmp[i] = tagName + " ";
					break;
				}
				tmp.reverse();
				that.val( tmp.join( " " ) );
			}
			
			autocompleteUL.empty().hide();
			that.focus();
		} ).live('keyup', function(){
			var that = $(this);
			that.trigger( 'tag-autocompleter' );
			
		}).live( 'keydown', function( e ){
			if( !e ) return;
			var keyCode = e.which,
					that = $(this),
					keyPressed = String.fromCharCode(keyCode),
					autocompleteUL = that.next('.tag-autocomplete');
			
			that.trigger( 'tag-autocompleter' );
			
			
			switch (keyCode) {
				case 9: // tab
				// case 13: // enter
					if( autocompleteUL.find('li.active').size() ) {
						autocompleteUL.find('li.active').trigger('click');
						return false;
					}
					return true;
					break;
				case 38: // up
					if( autocompleteUL.find('li.active').prev().size() ) {
						autocompleteUL.find('li.active').removeClass('active').prev().addClass('active');
					} else {
						autocompleteUL.find('li.active').trigger('click');
					}
					if( autocompleteUL.find('li.active').size() ) return false;
					return true;
					break;
				case 40: // down
					if( autocompleteUL.find('li.active').next().size() ) {
						autocompleteUL.find('li.active').removeClass('active').next().addClass('active');
					} else {
						autocompleteUL.find('li.active').trigger('click');
					}
					if( autocompleteUL.find('li.active').size() ) return false;
					return true;
					break;
			}
		} );
	})();
	/* @end */
	
	/* @group dragAndDrop for Things in Sidebar tags */
	;(function(){
		var menu = $('#menu'),
			dragOptions = {
				opacity: 0.7,
				zIndex: 600,
				helper: 'clone',
				// scope: 'tags',
				appendTo: 'body',
				handle: '.drag',
				cursorAt: { left: 50 },
				start: function(){
					menu.addClass('drag-drop-enabled');
				},
				stop: function(){
					menu.removeClass('drag-drop-enabled');
				}
			},
			dropOptions = {
				accept: '.thing-list-item',
				activeClass: 'ui-state-highlight',
				hoverClass: 'drophover',
				tolerance: 'pointer',
				// scope: 'tags',
				drop: function( event, ui ) {
					var drag = ui.draggable;
					if( !drag.size() ) return;
					var id = drag.find('.bulk').val(),
							tag = $(this).attr('data-tag');
					
					var thing = Thinkery.findThingById( id );
					if( !thing ) {
						// error
						return;
					}
					
					if( !tag ) {
						// prompt new tag window
						$.prompt('<h1 class="border">Add which tag?</h1><input type="text" name="add-tag" data-only-one="1" /><div class="status"></div>', {
							buttons: { "Add tag": true, "Cancel": false},
							callback: function (buttonClicked, message, fields) {
								if (!buttonClicked) return;
								Thinkery.saveThing( {
									id: thing._id,
									title: thing.title,
									tags: $.trim( thing.textTags + " " + fields["add-tag"] )
								}, function(){
									Thinkery.reloadSidebar();
								} );
								return;
							},
							loaded: function(v) {
								$("input[name=add-tag]:visible").focus().keyup(function(e) {
									if (e.altKey || e.metaKey || e.ctrlKey) return true;
									var keyCode = (e == null) ? event.keyCode : e.which;
									switch (keyCode) {
										case 13:
											$(this).closest("#jqi").find("button").eq(0).click();
									}
								});
							},
							submit: function(buttonClicked) {
								if (!buttonClicked) return true;
								var input = $("input[name=add-tag]:visible");
								if ($.trim(input.val()) == "") {
									input.closest("#jqi").find("div.status").addClass("error").html("Please enter a tag.");
									input.focus();
									return false;
								}
								return true;
							}
						});
						return;
					}
					
					Thinkery.saveThing( {
						id: thing._id,
						title: thing.title,
						tags: $.trim( thing.textTags + " " + tag )
					} );
				}
			};
		
		
		$(window).bind( 'things-list-updated', function(event, data){
			$('#things .thing-list-item').draggable( dragOptions );
		} );
		
		$(window).bind( 'reloadSidebar', function(event, data){
			$( "#nonFavoriteTags li,#favoriteTags li,#menu .create-new-tag" ).droppable( dropOptions );
		} );
		
		$('#things .thing-list-item').draggable( dragOptions );
		$( "#nonFavoriteTags li,#favoriteTags li,#menu .create-new-tag" ).droppable( dropOptions );
		
		/*
		$('#things .thing-list-item').live( 'mousedown', function( e ){
			e.preventDefault();
			console.log( e );
			
		} ).live( 'mouseup mousleave', function(){
			
		} )
		*/
	})();
	/* @end */
});