diff --git a/pkgs/plt-services/meta/pkg-index/official/.gitignore b/pkgs/plt-services/meta/pkg-index/official/.gitignore index cd3d01855c..ae6f4494c4 100644 --- a/pkgs/plt-services/meta/pkg-index/official/.gitignore +++ b/pkgs/plt-services/meta/pkg-index/official/.gitignore @@ -1 +1,5 @@ /root +/static/pkgs +/static/pkg +/static/pkgs-all +*json diff --git a/pkgs/plt-services/meta/pkg-index/official/common.rkt b/pkgs/plt-services/meta/pkg-index/official/common.rkt new file mode 100644 index 0000000000..8c5f70b814 --- /dev/null +++ b/pkgs/plt-services/meta/pkg-index/official/common.rkt @@ -0,0 +1,31 @@ +#lang racket/base +(require racket/file + racket/runtime-path + pkg/util + racket/string + web-server/http/id-cookie) + +(define-runtime-path src ".") + +(define-runtime-path root "root") +(make-directory* root) +(define secret-key + (make-secret-salt/file + (build-path root "secret.key"))) +(define users-path (build-path root "users")) +(make-directory* users-path) +(define users.new-path (build-path root "users.new")) +(make-directory* users.new-path) + +(github-client_id (file->string (build-path root "client_id"))) +(github-client_secret (file->string (build-path root "client_secret"))) + +(define pkgs-path (build-path root "pkgs")) +(make-directory* pkgs-path) + +(define static-path (build-path src "static")) + +(define (author->list as) + (string-split as)) + +(provide (all-defined-out)) diff --git a/pkgs/plt-services/meta/pkg-index/official/main.rkt b/pkgs/plt-services/meta/pkg-index/official/main.rkt index 55ad024f9a..1203290f0f 100644 --- a/pkgs/plt-services/meta/pkg-index/official/main.rkt +++ b/pkgs/plt-services/meta/pkg-index/official/main.rkt @@ -2,6 +2,7 @@ (module+ test (require rackunit)) (require web-server/http + "common.rkt" web-server/servlet-env racket/file xml @@ -38,24 +39,6 @@ (define (salty str) (sha1 (open-input-string str))) -(define-runtime-path src ".") - -(define-runtime-path root "root") -(make-directory* root) -(define secret-key - (make-secret-salt/file - (build-path root "secret.key"))) -(define users-path (build-path root "users")) -(make-directory* users-path) -(define users.new-path (build-path root "users.new")) -(make-directory* users.new-path) - -(github-client_id (file->string (build-path root "client_id"))) -(github-client_secret (file->string (build-path root "client_secret"))) - -(define pkgs-path (build-path root "pkgs")) -(make-directory* pkgs-path) - (define id-cookie-name "pnrid") ;; XXX Add a caching system @@ -159,9 +142,6 @@ new-v])) #f))) -(define (author->list as) - (string-split as)) - (define (page/rss req) (define ps (sort (map package-info (package-list)) @@ -1132,7 +1112,7 @@ #:ssl-cert (build-path root "server-cert.pem") #:ssl-key (build-path root "private-key.pem") #:extra-files-paths - (list (build-path src "static")) + (list static-path) #:servlet-regexp #rx"" #:port port)) diff --git a/pkgs/plt-services/meta/pkg-index/official/static.rkt b/pkgs/plt-services/meta/pkg-index/official/static.rkt new file mode 100644 index 0000000000..0e70592971 --- /dev/null +++ b/pkgs/plt-services/meta/pkg-index/official/static.rkt @@ -0,0 +1,75 @@ +#lang racket/base +(require web-server/http + racket/file + racket/match + json + net/url + racket/list + racket/path + racket/promise + meta/pkg-index/basic/main) + +(define convert-to-json + (match-lambda + [(? list? l) + (map convert-to-json l)] + [(? string? s) + s] + [(? hash? ht) + (for/hash ([(k v) (in-hash ht)]) + (values (convert-to-json-key k) + (convert-to-json v)))] + [(? number? n) + n] + [#f + #f] + [(? symbol? s) + (symbol->string s)] + [(? keyword? s) + (hasheq 'kw (keyword->string s))] + [x + (error 'convert-to-json "~e" x)])) +(define convert-to-json-key + (match-lambda + [(? string? s) + (string->symbol s)] + [(? symbol? s) + s] + [x + (error 'convert-to-json-key "~e" x)])) + +(module+ main + (require "common.rkt") + + (define pkg-list + (map path->string (directory-list pkgs-path))) + + (define dispatch + (pkg-index/basic + (λ () pkg-list) + (λ (pkg-name) + (define ht (file->value (build-path pkgs-path pkg-name))) + (hash-set* ht + 'name pkg-name + 'tags (hash-ref ht 'tags empty) + 'authors (author->list (hash-ref ht 'author "")))))) + + (define (url->request u) + (make-request #"GET" (string->url u) empty + (delay empty) #f "1.2.3.4" 80 "4.3.2.1")) + + (define (cache url file) + (define p (build-path static-path file)) + (make-directory* (path-only p)) + (with-output-to-file p + #:exists 'replace + (λ () ((response-output (dispatch (url->request url))) (current-output-port)))) + (with-output-to-file (path-add-suffix p #".json") + #:exists 'replace + (λ () (write-json (convert-to-json (file->value p))))) + (void)) + + (cache "/pkgs" "pkgs") + (cache "/pkgs-all" "pkgs-all") + (for ([p (in-list pkg-list)]) + (cache (format "/pkg/~a" p) (format "pkg/~a" p)))) diff --git a/pkgs/plt-services/meta/pkg-index/official/static/index.html b/pkgs/plt-services/meta/pkg-index/official/static/index.html new file mode 100644 index 0000000000..18fdb9b081 --- /dev/null +++ b/pkgs/plt-services/meta/pkg-index/official/static/index.html @@ -0,0 +1,39 @@ + + + + Packages > Search > !main-distribution > !main-tests + + + + + + + + +

+ + + + + + + + + + +
PackageAuthorsDescriptionTags
+ + + diff --git a/pkgs/plt-services/meta/pkg-index/official/static/index.js b/pkgs/plt-services/meta/pkg-index/official/static/index.js new file mode 100644 index 0000000000..cbaca5f0f0 --- /dev/null +++ b/pkgs/plt-services/meta/pkg-index/official/static/index.js @@ -0,0 +1,116 @@ +// xxx curate +// xxx rss +// xxx re-login +// xxx logout +// xxx what user am i +// xxx manage packages + +$( document ).ready(function() { + var search_terms = [ "!main-tests", "!main-distribution" ]; + + function addfilterlink ( text, term ) { + return [$('', { text: text, + href: "javascript:void(0)", + click: function () { + search_terms.push(term); + evaluate_search(); + } } ), + " " + ]; + }; + function removefilterlink ( text, term ) { + return [$('', { text: text, + href: "javascript:void(0)", + click: function () { + search_terms = $.grep( search_terms, function (v) { return v != term } ); + evaluate_search(); + } } ), + " " + ]; + }; + + $.getJSON( "/pkgs-all.json", function( resp ) { + var names = []; + $.each(resp, function(key, value) { names.push(key) }); + var snames = names.sort(function(a,b) { + return ((a < b) ? -1 : ((a > b) ? 1 : 0)); + }) + + var now = new Date().getTime() / 1000; + + $.each( snames, + function (name_i) { + var name = snames[name_i]; + var value = resp[name]; + + $('', + { class: ((now - (60*60*24*2)) < value['last-updated'] ? "recent" : "old") }). + data( "obj", value).append( + $('').html( $('', { text: value['name'], + href: "javascript:void(0)", + click: function () { + // XXX open up a subwindow + console.log(value); + } } ) ), + $('').append( $.map( value['authors'], function ( author, i ) { + return addfilterlink ( author, "author:" + author ); + } ) ), + $('').text( value['description'] ), + $('').append( $.map( value['tags'], function ( tag, i ) { + return addfilterlink ( tag, tag ); + } ) )).appendTo('#packages_table'); + }); + + evaluate_search(); + }); + + function evaluate_search_term( value, term ) { + if ( term == ":error:") { + return value['checksum-error']; + } else if ( term == ":no-tag:") { + return value['tags'].length == 0; + } else if ( term.substring(0, 5) == "ring:") { + return value['ring'] == term.substring(5); + } else if ( term.substring(0, 7) == "author:") { + return ($.inArray( term.substring(7), value['authors'] ) != -1); + } else if ( term.charAt(0) == "!" ) { + return ! evaluate_search_term( value, term.substring(1) ); + } else if ( $.inArray( term, value['tags']) != -1 ) { + return true; + } else { + return false; + } + } + + function evaluate_search () { + $.each( $('#packages_table tr'), function (key, dom) { + var value = $(dom).data("obj"); + var show = true; + + for (termi in search_terms) { + var term = search_terms[termi]; + if ( ! evaluate_search_term( value, term ) ) { + show = false; + } + } + + if ( show ) { + $(dom).show(); + } else { + $(dom).hide(); + } + + }); + + // xxx handle search button + + // xxx update menu available + $("#search_menu").html("").append( $.map( search_terms, function ( term, i ) { + return removefilterlink ( term, term ); + } ) ); + + $("#packages_table tr:visible:even").removeClass("even"); + $("#packages_table tr:visible:odd").addClass("even"); + }; + +}); diff --git a/pkgs/plt-services/meta/pkg-index/official/static/sorttable.js b/pkgs/plt-services/meta/pkg-index/official/static/sorttable.js index 4f74f1e2ea..5826672b44 100644 --- a/pkgs/plt-services/meta/pkg-index/official/static/sorttable.js +++ b/pkgs/plt-services/meta/pkg-index/official/static/sorttable.js @@ -1,42 +1,21 @@ -function TocviewToggle(glyphid, id) { - var glyph = document.getElementById(glyphid); - var s = document.getElementById(id).style; - var expand = s.display == "none"; - s.display = expand ? "block" : "none"; - glyph.innerHTML = expand ? "▼" : "►"; -} - -function ToggleOn(id) { - var s = document.getElementById(id).style; - var li = document.getElementById("li" + id); - s.display = "block"; - li.setAttribute("class", "tab-selected"); -} -function ToggleOff(id) { - var s = document.getElementById(id).style; - var li = document.getElementById("li" + id); - s.display = "none"; - li.setAttribute("class", ""); -} - /* SortTable version 2 7th April 2007 Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ - + Instructions: Download this file Add to your HTML Add class="sortable" to any table you'd like to make sortable Click on the headers to sort - + Thanks to many, many people for contributions and suggestions. Licenced as X11: http://www.kryogenix.org/code/browser/licence.html This basically means: do what you want with it. */ - + var stIsIE = /*@cc_on!@*/false; sorttable = { @@ -47,19 +26,19 @@ sorttable = { arguments.callee.done = true; // kill the timer if (_timer) clearInterval(_timer); - + if (!document.createElement || !document.getElementsByTagName) return; - + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; - + forEach(document.getElementsByTagName('table'), function(table) { if (table.className.search(/\bsortable\b/) != -1) { sorttable.makeSortable(table); } }); - + }, - + makeSortable: function(table) { if (table.getElementsByTagName('thead').length == 0) { // table doesn't have a tHead. Since it should have, create one and @@ -70,9 +49,9 @@ sorttable = { } // Safari doesn't support table.tHead, sigh if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; - + if (table.tHead.rows.length != 1) return; // can't cope with two header rows - + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as // "total" rows, for example). This is B&R, since what you're supposed // to do is put them in a tfoot. So, if there are sortbottom rows, @@ -94,7 +73,7 @@ sorttable = { } delete sortbottomrows; } - + // work through each column and calculate its type headrow = table.tHead.rows[0].cells; for (var i=0; i fields. - + + if (!node) return ""; + hasInputs = (typeof node.getElementsByTagName == 'function') && node.getElementsByTagName('input').length; - + if (node.getAttribute("sorttable_customkey") != null) { return node.getAttribute("sorttable_customkey"); } @@ -262,7 +243,7 @@ sorttable = { } } }, - + reverse: function(tbody) { // reverse the rows in a tbody newrows = []; @@ -274,14 +255,14 @@ sorttable = { } delete newrows; }, - + /* sort functions each sort function takes two parameters, a and b you are comparing a[0] and b[0] */ sort_numeric: function(a,b) { aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); if (isNaN(aa)) aa = 0; - bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); if (isNaN(bb)) bb = 0; return aa-bb; }, @@ -320,7 +301,7 @@ sorttable = { if (dt1