Changeset 3713

Show
Ignore:
Timestamp:
08/01/08 00:25:05 (4 months ago)
Author:
hans
Message:

News start working.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/bknr/web/src/rss/rss.lisp

    r3702 r3713  
    122122    (let ((month-string (bknr.web:query-param "month"))) 
    123123      (when month-string 
    124         (mapcar #'parse-integer (cl-ppcre:split "([-/]|(?<=..))" month-string :limit 2)))))) 
     124        (mapcar #'parse-integer (cl-ppcre:split "([-/]|(?<=....))" month-string :limit 2)))))) 
    125125 
    126126(defun rss-channel-archive (channel) 
    127127  "Return the channel archive consisting of lists of lists ((MONTH YEAR) ITEM...)" 
    128   (group-on (rss-channel-items channel
     128  (group-on (rss-channel-items channel :all t
    129129            :test #'equal 
    130130            :key (lambda (item) 
     
    132132                       (decode-universal-time (rss-item-pub-date item)) 
    133133                     (declare (ignore seconds minutes hours day)) 
    134                      (list month year))))) 
     134                     (list year month))))) 
    135135 
    136136(defgeneric rss-channel-items (channel &key) 
    137137  (:documentation "Return all non-expired items in channel.") 
    138   (:method ((channel rss-channel) &key days month count
     138  (:method ((channel rss-channel) &key days month count all
    139139    (unless month 
    140140      (setf month (month-from-query-parameter))) 
     
    142142      (setf days (or (days-from-query-parameter) 
    143143                     (rss-channel-max-item-age channel)))) 
    144     (let ((items (if month 
    145                      (cdr (find month (rss-channel-archive channel) :test #'equal)) 
    146                      (let ((expiry-time (- (get-universal-time) (* 60 60 24 days)))) 
    147                        (remove-if (lambda (item) (or (object-destroyed-p item) 
    148                                                      (< (rss-item-pub-date item) expiry-time))) 
    149                                   (slot-value channel 'items)))))) 
    150       (if count 
    151           (subseq items 0 (min count (length items))) 
    152           items)))) 
     144    (if all 
     145        (remove-if #'object-destroyed-p (slot-value channel 'items)) 
     146        (let ((items (if month 
     147                         (cdr (find month (rss-channel-archive channel) :test #'equal :key #'car)) 
     148                         (let ((expiry-time (- (get-universal-time) (* 60 60 24 days)))) 
     149                           (remove-if (lambda (item) (or (object-destroyed-p item) 
     150                                                         (< (rss-item-pub-date item) expiry-time))) 
     151                                      (slot-value channel 'items)))))) 
     152          (if count 
     153              (subseq items 0 (min count (length items))) 
     154              items))))) 
    153155 
    154156(defgeneric rss-channel-archived-months (channel) 
  • trunk/projects/quickhoney/src/handlers.lisp

    r3703 r3713  
    427427                      (:p ((:a :href "javascript:window.close()") "ok")))))))))))) 
    428428 
    429 (defclass news-json-handler (object-handler) 
     429(defclass rss-channel-handler (object-handler) 
    430430  () 
    431431  (:default-initargs :object-class 'rss-channel :query-function #'find-rss-channel)) 
    432432 
    433 (defvar *json-output*) 
    434  
    435 (defclass json-output-stream () 
    436   ((output-stream :reader output-stream 
    437                   :initarg :output-stream) 
    438    (stack :accessor stack 
    439           :initform nil))) 
    440  
    441 (defun next-aggregate-element () 
    442   (if (car (stack *json-output*)) 
    443       (princ #\, (output-stream *json-output*)) 
    444       (setf (car (stack *json-output*)) t))) 
    445  
    446 (defmacro with-json-output ((stream) &body body) 
    447   `(let ((*json-output* (make-instance 'json-output-stream :output-stream ,stream))) 
    448      ,@body)) 
    449  
    450 (defmacro with-json-output-to-string (() &body body) 
    451   `(with-output-to-string (s) 
    452      (with-json-output (s) 
    453        ,@body))) 
    454  
    455 (defmacro with-json-aggregate ((begin-char end-char) &body body) 
    456   `(progn 
    457      (when (stack *json-output*) 
    458        (next-aggregate-element)) 
    459      (princ ,begin-char (output-stream *json-output*)) 
    460      (push nil (stack *json-output*)) 
    461      (prog1 
    462          (progn ,@body) 
    463        (pop (stack *json-output*)) 
    464        (princ ,end-char (output-stream *json-output*))))) 
    465  
    466 (defmacro with-json-array (() &body body) 
    467   `(with-json-aggregate (#\[ #\]) 
    468      ,@body)) 
    469  
    470 (defmacro with-json-object (() &body body) 
    471   `(with-json-aggregate (#\{ #\}) 
    472      ,@body)) 
    473  
    474 (defun encode-array-element (object) 
    475   (next-aggregate-element) 
    476   (json:encode-json object (output-stream *json-output*))) 
    477  
    478 (defun encode-object-element (key value) 
    479   (next-aggregate-element) 
    480   (json:encode-json key (output-stream *json-output*)) 
    481   (princ #\: (output-stream *json-output*)) 
    482   (json:encode-json value (output-stream *json-output*))) 
    483  
    484 (defmethod handle-object ((handler news-json-handler) (channel rss-channel)) 
    485   (with-http-response (:content-type "application/json") 
    486     (with-json-output-to-string () 
     433(defclass json-news-handler (rss-channel-handler) 
     434  ()) 
     435 
     436 
     437(defgeneric json-encode-news-item (item) 
     438  (:method ((item t)) 
     439    ; do nothing 
     440    ) 
     441  (:method ((image quickhoney-image)) 
     442    (let ((vectorp (member :vector (store-image-keywords image)))) 
     443      (encode-object-element "uploader" (if vectorp "Peter" "Nana")) 
     444      (encode-object-element "category" (if vectorp "vector" "pixel")) 
     445      (encode-object-element "subcategory" "unknown") 
     446      (encode-object-element "date" (format-date-time (rss-item-pub-date image) :vms-style t :show-time nil)) 
     447      (encode-object-element "name" (store-image-name image))))) 
     448 
     449(defmethod handle-object ((handler json-news-handler) (channel rss-channel)) 
     450  (with-json-response () 
     451    (with-object-element ("items") 
    487452      (with-json-array () 
    488453        (dolist (item (rss-channel-items channel)) 
    489454          (with-json-object () 
    490             (encode-object-element "pubDate" (format-date-time (rss-item-pub-date item) :vms-style t)) 
    491             (encode-object-element "title" (rss-item-title item)) 
    492             (encode-object-element "description" (rss-item-description item)))))))) 
     455            (json-encode-news-item item))))))) 
     456 
     457(defclass json-news-archive-handler (rss-channel-handler) 
     458  ()) 
     459 
     460(defmethod handle-object ((handler json-news-archive-handler) (channel rss-channel)) 
     461  (with-json-response () 
     462    (with-object-element ("months") 
     463      (with-json-array () 
     464        (dolist (month (sort (rss-channel-archived-months channel) 
     465                              (lambda (a b) 
     466                                (if (= (first a) (first b)) 
     467                                    (> (second a) (second b)) 
     468                                    (> (first a) (first b)))))) 
     469          (with-json-array () 
     470            (encode-array-element (first month)) 
     471            (encode-array-element (second month)))))))) 
  • trunk/projects/quickhoney/src/quickhoney.asd

    r3701 r3713  
    3333               (:file "layout" :depends-on ("config")) 
    3434               (:file "imageproc" :depends-on ("config")) 
    35                (:file "handlers" :depends-on ("layout" "config" "image")) 
     35               (:file "json" :depends-on ("packages")) 
     36               (:file "handlers" :depends-on ("json" "layout" "config" "image")) 
    3637               (:file "tags" :depends-on ("image")) 
    3738               (:file "webserver" :depends-on ("handlers")) 
  • trunk/projects/quickhoney/src/webserver.lisp

    r3701 r3713  
    3434                                        ("/upload-news" upload-news-handler) 
    3535                                        ("/digg-image" digg-image-handler) 
    36                                         ("/news-json" news-json-handler) 
     36                                        ("/json-news-archive" json-news-archive-handler) 
     37                                        ("/json-news" json-news-handler) 
    3738                                        ("/" template-handler 
    3839                                         :default-template "frontpage" 
  • trunk/projects/quickhoney/website/static/javascript.js

    r3683 r3713  
    216216/* news */ 
    217217 
    218 function load_news() 
    219 
    220      
     218var month_names = [ 'January', 'February', 'March', 'April', 'May', 'June', 
     219                    'July', 'August', 'September', 'October', 'November', 'December' ]; 
     220 
     221function select_archive_year() 
     222
     223    var year = this.href.match(/#news\/(\d+)/)[1]; 
     224    map(function (element) { 
     225            if (element.href) { 
     226                ((element.href.match(/#news\/(\d+)/)[1] == year) ? addElementClass : removeElementClass)(element, 'active'); 
     227            } 
     228        }, this.parentNode.childNodes); 
     229    return true; 
     230
     231 
     232function select_archive_month() 
     233
     234    var month = this.href.match(/#news\/(\d+\/\d+)/)[1]; 
     235    loadJSONDoc('/json-news/quickhoney?month=' + month).addCallbacks(load_news, alert); 
     236    return true; 
     237
     238 
     239function load_news(data) 
     240
     241    log('load news: ' + data.items.length); 
     242    replaceChildNodes('newsentries', 
     243                      map(function (item) { 
     244                              var color = (item.category == 'pixel') ? 'ff00ff' : '00ccff'; 
     245                              return [ DIV({ 'class': 'newsentry autonews news_' + item.category }, 
     246                                         IMG({ src: "/image/" + item.name + '/cutout-button,,' + color + ',98,4'}), 
     247                                         DIV(null, 
     248                                             H1(null, item.name), 
     249                                             item.date, ' by ', item.uploader, ' | ', 
     250                                             A({ href: '/index#' + item.category + '/' + item.subcategory + '/' + item.image_name }, 'permalink'), 
     251                                             BR(), 
     252                                             item.description)), 
     253                                       DIV({ 'class': 'news_sep' }) ]; 
     254                          }, data.items)); 
     255
     256 
     257function load_news_archive(data) 
     258
     259    try { 
     260        if (!data.months) { 
     261            alert('no archive data found'); 
     262        } 
     263        var currentYear; 
     264        var active = true; 
     265        replaceChildNodes('archive-navigation', 
     266                          SPAN({ 'class': 'title' }, 'Archive'), BR(), 
     267                          map(function (entry) { 
     268                                  var year = entry[0]; 
     269                                  var month = entry[1]; 
     270                                  var result = []; 
     271                                  if (year != currentYear) { 
     272                                      if (currentYear) { 
     273                                          active = false; 
     274                                      } 
     275                                      currentYear = year; 
     276                                      var link = A({ href: '#news/' + year, 'class': 'year' }, year, BR()); 
     277                                      link.onclick = select_archive_year; 
     278                                      result.push(link); 
     279                                  } 
     280                                  var link = A({ href: '#news/' + year + '/' + month, 'class': 'month ' + (active ? ' active' : '')}, 
     281                                               month_names[month - 1], BR()); 
     282                                  link.onclick = select_archive_month; 
     283                                  result.push(link); 
     284                                  return result; 
     285                              }, data.months)); 
     286    } 
     287    catch (e) { 
     288        log('error while processing archive data: ' + e); 
     289    } 
    221290} 
    222291 
     
    392461               function() { 
    393462                   footer_hide(); 
    394                    load_news(); 
     463                   loadJSONDoc('/json-news-archive/quickhoney').addCallbacks(load_news_archive, alert); 
     464                   //                   load_news(); 
    395465               }); 
    396466 
  • trunk/projects/quickhoney/website/static/styles.css

    r3683 r3713  
    629629        visibility: hidden; 
    630630} 
     631 
     632.archive span.title, .archive a.year { font-size: 1.5em; } 
     633.archive a.month.active { display: block; } 
     634.archive a.month { display: none; } 
     635.archive { padding-left: 1em; } 
  • trunk/projects/quickhoney/website/templates/index.xml

    r3683 r3713  
    131131       
    132132      <div id="news_page"> 
    133         <p id="news_content"> 
    134           <div class="newsentry news_vector autonews"> 
    135             <img src="/image/TSG_Platforms_web/cutout-button,,00ccff,98,4"/> 
    136             <div> 
    137               <h1>Jan and Ella</h1> 
    138               March 8th, 2008 by Peter | <a href="foo">permalink</a><br/> 
    139               description 
    140             </div> 
    141           </div> 
    142           <div class="news_sep"> </div> 
    143           <br/> 
    144           <div class="newsentry news_pixel autonews"> 
    145             <img src="/image/TSG_Platforms_web/cutout-button,,00ccff,98,4"/> 
    146             <div> 
    147               March 8th, 2008 by Peter | <a href="foo">permalink</a><br/> 
    148               description 
    149             </div> 
    150           </div> 
    151         </p> 
     133        <table border="0"> 
     134          <tbody> 
     135            <tr> 
     136              <td valign="top" id="newsentries"> 
     137                <div class="newsentry news_vector autonews"> 
     138                  <img src="/image/TSG_Platforms_web/cutout-button,,00ccff,98,4"/> 
     139                  <div> 
     140                    <h1>Jan and Ella</h1> 
     141                    March 8th, 2008 by Peter | <a href="foo">permalink</a><br/> 
     142                    description 
     143                  </div> 
     144                </div> 
     145                <div class="news_sep"> </div> 
     146                <br/> 
     147                <div class="newsentry news_pixel autonews"> 
     148                  <img src="/image/TSG_Platforms_web/cutout-button,,00ccff,98,4"/> 
     149                  <div> 
     150                    March 8th, 2008 by Peter | <a href="foo">permalink</a><br/> 
     151                    description 
     152                  </div> 
     153                </div> 
     154              </td> 
     155              <td class="archive" id="archive-navigation" valign="top"> 
     156              </td> 
     157            </tr> 
     158          </tbody> 
     159        </table> 
    152160      </div> 
    153161