# HG changeset patch # User veltr # Date 1341330626 -7200 # Node ID 8ff4fd1a6e9c710b82503833097e76fe9b162d1d # Parent 0a1744477bc1d7fc5e83647e6ef86c6c962c1b1f Added categories page diff -r 0a1744477bc1 -r 8ff4fd1a6e9c web/hdalab/static/hdalab/css/cattree.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/hdalab/static/hdalab/css/cattree.css Tue Jul 03 17:50:26 2012 +0200 @@ -0,0 +1,116 @@ +.leftzone { + width: 280px; + min-height: 400px; + float: left; + height: 100%; + padding-right: 20px; + border-right: 1px solid #999; +} + +.leftzone h2 { + font-size: 16px; font-weight: bold; margin-bottom: 5px; +} + +.leftzone input { + background: #ffffff; width: 260px; font-size: 14px; font-weight: bold; margin: 5px 0; +} + +.hidden { + display: none; +} + +.results, .bloc-historique { + margin-top: 30px; +} + +.tag-results { + color: #c00000; +} + +.category-results { + color: #008000; +} + +.content-results { + color: #000060; +} + +.ui-autocomplete strong { + font-weight: bold; color: #990000; +} + +div.cattree { + margin: 10px 0 0 320px; +} + +.cattree p.category { + color: #008000; +} + +.cattree p.category:before { + content: "Catégorie "; + font-style: italic; + font-weight: normal; +} + +.cattree p.tag { + color: #c00000; +} + +.cattree p.tag:before { + content: "Tag "; + font-style: italic; + font-weight: normal; +} + +.cattree a.content { + color: #000060; text-decoration: none; +} + +.cattree li, p { + margin: 4px 0; font-size: 13px; position: relative; +} + +.cattree p { + font-weight: bold; cursor: pointer; +} + +.cattree p:after { + content: " [-]" +} + +.cattree .folded p:after { + content: " [+]" +} + +.cattree ul { + list-style: none; position: relative; overflow: hidden; padding: 0; margin: 0; +} + +.cattree .folded ul { + display: none; +} + +.cattree li { + list-style: none; +} + +.cattree ul li { + margin-left: 50px; +} + +.cattree ul li:after { + content: ""; position: absolute; left: -40px; top: 10px; width: 30px; bottom: 0; border-style: solid none none solid; border-width: 1px; border-color: #333; +} + +.cattree ul li:before { + content: ""; position: absolute; left: -40px; top: -5px; height: 15px; width: 1px; background: #333; +} + +.cattree ul li:last-child:after { + border-style: solid none none; +} + +.cattree .eltype { + font-style: italic; display: none; +} \ No newline at end of file diff -r 0a1744477bc1 -r 8ff4fd1a6e9c web/hdalab/static/hdalab/js/cattree.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/hdalab/static/hdalab/js/cattree.js Tue Jul 03 17:50:26 2012 +0200 @@ -0,0 +1,67 @@ +function render(_data) { + var _prefix = '
  • {{category}}

  • ', + _html = Mustache.to_html(_prefix, _data); + if (typeof _data.sub_categories == "object" && typeof _data.sub_categories.slice == "function") { + for (var _i = 0; _i < _data.sub_categories.length; _i++) { + _html += render(_data.sub_categories[_i]); + } + } + _html += Mustache.to_html(_suffix, _data); + return _html; +} + +function histoclick(_el) { + gettree($(_el).text()); +} + +function gettree(_label) { + $.getJSON( + endpoints.cat_tree, + { label: _label }, + function(_data) { + $(".label-name").html(_label); + if (_data) { + $("#tree").html(render(_data)); + $(".cattree p").click(function() { + $(this).parent().toggleClass("folded"); + }); + $(".results").show(); + $(".content-count").html($(".cattree a.content").length); + $(".category-count").html(Math.max(0, $("p.category").length - 1)); + $(".tag-count").html($("p.tag").length); + } else { + $("#tree").html(""); + $(".results").hide(); + } + var _hist = $(".historique"), + _html = _hist.text().length ? ' » ' : ''; + _html += '' + _label + ''; + _hist.append(_html); + $('.bloc-historique').show(); + } + ); +} + +$(function() { + $( "#catsearch" ).autocomplete({ + source: endpoints.cat_search, + minLength: 2, + select: function( event, ui ) { + gettree(ui.item.value); + } + }) + .data("autocomplete")._renderItem = function(ul, item) { + return $( "
  • " ) + .data( "item.autocomplete", item ) + .append( + "" + + item.label.replace( + new RegExp('(' + + $("#catsearch").val().replace(/(\W)/g, '\\$1') + + ')','gi') , + '$1') + + "" ) + .appendTo( ul ) + }; +}); \ No newline at end of file diff -r 0a1744477bc1 -r 8ff4fd1a6e9c web/hdalab/static/hdalab/lib/mustache.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/hdalab/static/hdalab/lib/mustache.js Tue Jul 03 17:50:26 2012 +0200 @@ -0,0 +1,436 @@ +/* + mustache.js — Logic-less templates in JavaScript + + See http://mustache.github.com/ for more info. +*/ + +var Mustache = function () { + var _toString = Object.prototype.toString; + + Array.isArray = Array.isArray || function (obj) { + return _toString.call(obj) == "[object Array]"; + } + + var _trim = String.prototype.trim, trim; + + if (_trim) { + trim = function (text) { + return text == null ? "" : _trim.call(text); + } + } else { + var trimLeft, trimRight; + + // IE doesn't match non-breaking spaces with \s. + if ((/\S/).test("\xA0")) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; + } else { + trimLeft = /^\s+/; + trimRight = /\s+$/; + } + + trim = function (text) { + return text == null ? "" : + text.toString().replace(trimLeft, "").replace(trimRight, ""); + } + } + + var escapeMap = { + "&": "&", + "<": "<", + ">": ">", + '"': '"', + "'": ''' + }; + + function escapeHTML(string) { + return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) { + return escapeMap[s] || s; + }); + } + + var regexCache = {}; + var Renderer = function () {}; + + Renderer.prototype = { + otag: "{{", + ctag: "}}", + pragmas: {}, + buffer: [], + pragmas_implemented: { + "IMPLICIT-ITERATOR": true + }, + context: {}, + + render: function (template, context, partials, in_recursion) { + // reset buffer & set context + if (!in_recursion) { + this.context = context; + this.buffer = []; // TODO: make this non-lazy + } + + // fail fast + if (!this.includes("", template)) { + if (in_recursion) { + return template; + } else { + this.send(template); + return; + } + } + + // get the pragmas together + template = this.render_pragmas(template); + + // render the template + var html = this.render_section(template, context, partials); + + // render_section did not find any sections, we still need to render the tags + if (html === false) { + html = this.render_tags(template, context, partials, in_recursion); + } + + if (in_recursion) { + return html; + } else { + this.sendLines(html); + } + }, + + /* + Sends parsed lines + */ + send: function (line) { + if (line !== "") { + this.buffer.push(line); + } + }, + + sendLines: function (text) { + if (text) { + var lines = text.split("\n"); + for (var i = 0; i < lines.length; i++) { + this.send(lines[i]); + } + } + }, + + /* + Looks for %PRAGMAS + */ + render_pragmas: function (template) { + // no pragmas + if (!this.includes("%", template)) { + return template; + } + + var that = this; + var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) { + return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g"); + }); + + return template.replace(regex, function (match, pragma, options) { + if (!that.pragmas_implemented[pragma]) { + throw({message: + "This implementation of mustache doesn't understand the '" + + pragma + "' pragma"}); + } + that.pragmas[pragma] = {}; + if (options) { + var opts = options.split("="); + that.pragmas[pragma][opts[0]] = opts[1]; + } + return ""; + // ignore unknown pragmas silently + }); + }, + + /* + Tries to find a partial in the curent scope and render it + */ + render_partial: function (name, context, partials) { + name = trim(name); + if (!partials || partials[name] === undefined) { + throw({message: "unknown_partial '" + name + "'"}); + } + if (!context || typeof context[name] != "object") { + return this.render(partials[name], context, partials, true); + } + return this.render(partials[name], context[name], partials, true); + }, + + /* + Renders inverted (^) and normal (#) sections + */ + render_section: function (template, context, partials) { + if (!this.includes("#", template) && !this.includes("^", template)) { + // did not render anything, there were no sections + return false; + } + + var that = this; + + var regex = this.getCachedRegex("render_section", function (otag, ctag) { + // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder + return new RegExp( + "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1) + + otag + // {{ + "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3) + ctag + // }} + + "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped + + otag + // {{ + "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag). + ctag + // }} + + "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped. + + "g"); + }); + + + // for each {{#foo}}{{/foo}} section do... + return template.replace(regex, function (match, before, type, name, content, after) { + // before contains only tags, no sections + var renderedBefore = before ? that.render_tags(before, context, partials, true) : "", + + // after may contain both sections and tags, so use full rendering function + renderedAfter = after ? that.render(after, context, partials, true) : "", + + // will be computed below + renderedContent, + + value = that.find(name, context); + + if (type === "^") { // inverted section + if (!value || Array.isArray(value) && value.length === 0) { + // false or empty list, render it + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } else if (type === "#") { // normal section + if (Array.isArray(value)) { // Enumerable, Let's loop! + renderedContent = that.map(value, function (row) { + return that.render(content, that.create_context(row), partials, true); + }).join(""); + } else if (that.is_object(value)) { // Object, Use it as subcontext! + renderedContent = that.render(content, that.create_context(value), + partials, true); + } else if (typeof value == "function") { + // higher order section + renderedContent = value.call(context, content, function (text) { + return that.render(text, context, partials, true); + }); + } else if (value) { // boolean section + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } + + return renderedBefore + renderedContent + renderedAfter; + }); + }, + + /* + Replace {{foo}} and friends with values from our view + */ + render_tags: function (template, context, partials, in_recursion) { + // tit for tat + var that = this; + + var new_regex = function () { + return that.getCachedRegex("render_tags", function (otag, ctag) { + return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g"); + }); + }; + + var regex = new_regex(); + var tag_replace_callback = function (match, operator, name) { + switch(operator) { + case "!": // ignore comments + return ""; + case "=": // set new delimiters, rebuild the replace regexp + that.set_delimiters(name); + regex = new_regex(); + return ""; + case ">": // render partial + return that.render_partial(name, context, partials); + case "{": // the triple mustache is unescaped + case "&": // & operator is an alternative unescape method + return that.find(name, context); + default: // escape the value + return escapeHTML(that.find(name, context)); + } + }; + var lines = template.split("\n"); + for(var i = 0; i < lines.length; i++) { + lines[i] = lines[i].replace(regex, tag_replace_callback, this); + if (!in_recursion) { + this.send(lines[i]); + } + } + + if (in_recursion) { + return lines.join("\n"); + } + }, + + set_delimiters: function (delimiters) { + var dels = delimiters.split(" "); + this.otag = this.escape_regex(dels[0]); + this.ctag = this.escape_regex(dels[1]); + }, + + escape_regex: function (text) { + // thank you Simon Willison + if (!arguments.callee.sRE) { + var specials = [ + '/', '.', '*', '+', '?', '|', + '(', ')', '[', ']', '{', '}', '\\' + ]; + arguments.callee.sRE = new RegExp( + '(\\' + specials.join('|\\') + ')', 'g' + ); + } + return text.replace(arguments.callee.sRE, '\\$1'); + }, + + /* + find `name` in current `context`. That is find me a value + from the view object + */ + find: function (name, context) { + name = trim(name); + + // Checks whether a value is thruthy or false or 0 + function is_kinda_truthy(bool) { + return bool === false || bool === 0 || bool; + } + + var value; + + // check for dot notation eg. foo.bar + if (name.match(/([a-z_]+)\./ig)) { + var childValue = this.walk_context(name, context); + if (is_kinda_truthy(childValue)) { + value = childValue; + } + } else { + if (is_kinda_truthy(context[name])) { + value = context[name]; + } else if (is_kinda_truthy(this.context[name])) { + value = this.context[name]; + } + } + + if (typeof value == "function") { + return value.apply(context); + } + if (value !== undefined) { + return value; + } + // silently ignore unkown variables + return ""; + }, + + walk_context: function (name, context) { + var path = name.split('.'); + // if the var doesn't exist in current context, check the top level context + var value_context = (context[path[0]] != undefined) ? context : this.context; + var value = value_context[path.shift()]; + while (value != undefined && path.length > 0) { + value_context = value; + value = value[path.shift()]; + } + // if the value is a function, call it, binding the correct context + if (typeof value == "function") { + return value.apply(value_context); + } + return value; + }, + + // Utility methods + + /* includes tag */ + includes: function (needle, haystack) { + return haystack.indexOf(this.otag + needle) != -1; + }, + + // by @langalex, support for arrays of strings + create_context: function (_context) { + if (this.is_object(_context)) { + return _context; + } else { + var iterator = "."; + if (this.pragmas["IMPLICIT-ITERATOR"]) { + iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; + } + var ctx = {}; + ctx[iterator] = _context; + return ctx; + } + }, + + is_object: function (a) { + return a && typeof a == "object"; + }, + + /* + Why, why, why? Because IE. Cry, cry cry. + */ + map: function (array, fn) { + if (typeof array.map == "function") { + return array.map(fn); + } else { + var r = []; + var l = array.length; + for(var i = 0; i < l; i++) { + r.push(fn(array[i])); + } + return r; + } + }, + + getCachedRegex: function (name, generator) { + var byOtag = regexCache[this.otag]; + if (!byOtag) { + byOtag = regexCache[this.otag] = {}; + } + + var byCtag = byOtag[this.ctag]; + if (!byCtag) { + byCtag = byOtag[this.ctag] = {}; + } + + var regex = byCtag[name]; + if (!regex) { + regex = byCtag[name] = generator(this.otag, this.ctag); + } + + return regex; + } + }; + + return({ + name: "mustache.js", + version: "0.5.0-dev", + + /* + Turns a template and view into HTML + */ + to_html: function (template, view, partials, send_fun) { + var renderer = new Renderer(); + if (send_fun) { + renderer.send = send_fun; + } + renderer.render(template, view || {}, partials); + if (!send_fun) { + return renderer.buffer.join("\n"); + } + } + }); +}(); diff -r 0a1744477bc1 -r 8ff4fd1a6e9c web/hdalab/templates/base.html --- a/web/hdalab/templates/base.html Mon Jul 02 19:19:02 2012 +0200 +++ b/web/hdalab/templates/base.html Tue Jul 03 17:50:26 2012 +0200 @@ -26,6 +26,7 @@

    HdA Lab

    diff -r 0a1744477bc1 -r 8ff4fd1a6e9c web/hdalab/templates/categories.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/hdalab/templates/categories.html Tue Jul 03 17:50:26 2012 +0200 @@ -0,0 +1,45 @@ +{% extends "base.html" %} + +{% block title %}{{block.super}} > Arbre des catégories Wikipedia{% endblock %} + +{% block css_import %} +{{block.super}} + + +{% endblock %} + +{% block js_import %} +{{block.super}} + + + + + +{% endblock %} + +{% block categories_actif %}actif{% endblock %} + +{% block main_content %} +
    +

    Rechercher une catégorie :

    +

    + +

    + + +
    +
    +{% endblock %} \ No newline at end of file diff -r 0a1744477bc1 -r 8ff4fd1a6e9c web/hdalab/urls.py --- a/web/hdalab/urls.py Mon Jul 02 19:19:02 2012 +0200 +++ b/web/hdalab/urls.py Tue Jul 03 17:50:26 2012 +0200 @@ -24,6 +24,7 @@ url('^jsi18n/(?P\S+?)/$', 'django.views.i18n.javascript_catalog', {'domain':'djangojs'}, name='jsi18n'), url(r'^facettes/', TemplateView.as_view(template_name="facettes.html"), name='facettes'), + url(r'^categories/', TemplateView.as_view(template_name="categories.html"), name='categories'), url(r'^$', TemplateView.as_view(template_name="index.html"), name='home'), ) @@ -33,5 +34,6 @@ (r'^a/taginfo$', 'taginfo', {}, 'tag_info'), (r'^a/sessioninfo$', 'sessioninfo', {}, 'session_info'), (r'^a/tagsearch$', 'tagsearch', {}, 'tag_search'), - (r'^a/cattree$', 'cattree', {}, 'cattree'), + (r'^a/catsearch$', 'catsearch', {}, 'cat_search'), + (r'^a/cattree$', 'cattree', {}, 'cat_tree'), ) diff -r 0a1744477bc1 -r 8ff4fd1a6e9c web/hdalab/views/ajax.py --- a/web/hdalab/views/ajax.py Mon Jul 02 19:19:02 2012 +0200 +++ b/web/hdalab/views/ajax.py Tue Jul 03 17:50:26 2012 +0200 @@ -138,7 +138,7 @@ if len(tag_list): contents = [] - datasheets = Datasheet.objects.select_related('taggedsheet__tag').filter(taggedsheet__tag__label__in = tag_list, taggedsheet__order__lte = MAX_TAG_ORDER).distinct() + datasheets = Datasheet.objects.select_related('taggedsheet__tag').filter(validated = True, taggedsheet__tag__label__in = tag_list, taggedsheet__order__lte = MAX_TAG_ORDER).distinct() for datasheet in datasheets: # Calculating where we add the datasheet in the tree maintag = None @@ -151,7 +151,7 @@ maintagscore = score maintag = label if maintag is not None: - globtags[maintag]['access']['contents'].append({'id': datasheet.id, 'title': datasheet.title}) + globtags[maintag]['access']['contents'].append({'id': datasheet.id, 'title': datasheet.title, 'url': datasheet.url}) cleantags(resobj) # resobj['contents'] = [{'id': d.id, 'title': d.title, 'tags': [t.label for t in d.tags.filter(taggedsheet__order__lte=5)]} for d in datasheets] @@ -226,6 +226,15 @@ return HttpResponse(content=json.dumps(res), mimetype='application/json') +def catsearch(request): + + q = request.GET.get('term',None) + + qs = WpCategory.objects.filter( Q(label__icontains = ' ' + q ) | Q(label__istartswith = q)) + + res = [{'value':t.label} for t in qs] + + return HttpResponse(content=json.dumps(res), mimetype='application/json') def filter(request):