[Bese-devel] say a warm welcome to ucw+, event-based ucw implementing ajax.
Lou Vanek
vanek at acd.net
Tue Jul 11 23:16:35 UTC 2006
wow!
it took me awhile to process and integrate, but with not too much
effort it seems to do everything you say.
I've appended a new 02_dom file to get around an IE7b3 security
constraint. IE7 uses mime sniffing
(http://www.microsoft.com/technet/prodtechnol/winxppro/maintain/mangxpsp2/mngieps.mspx)
so trying to load an ajax 'text/html' response in ie7 will immediately abort if
a javascript tag is parsed at read time. The 02 file also corrects
the problem of accidentally inserting a whitespace dom node instead of
the nodeType 1 dom node that contains the actual html/script/css.
The corresponding server-side code is slightly revised to sneak
the javascript past ie7 by embedding it in a DIV:
(defmethod render-ajax ((window ajax-window))
(let ((dirty-components (context.dirty-components *context*)))
(dolist (ajax-widget dirty-components)
;;; walk dirty-components list and look for self's parent nodes. we
;;; don't need to render html if a parent node already exists.
;;; this is not the case with css, we render css if it's dirty
;;; anyway.
(let ((found-p nil))
(dolist (parent-component dirty-components)
(when (and (not found-p)
(descendant-p parent-component ajax-widget t))
(setf found-p t)))
(<:div :class "component"
:id (dom-id ajax-widget)
(when (not found-p)
(<:div :class "html"
(render ajax-widget)))
(<:div :class "css"
(<:style :type "text/css"
(render-css ajax-widget)))))))
;; All javascript which is to be immediately evaluated is embedded within
;; a div to sneak past IE7's mime sniffer.
;; Otherwise IE7 will stop loading the file if the mime type isn't text/javascript.
;; (Dojo would try to immediately eval this entire script if it
;; thought the whole file was javascript, which it isn't because there's also html.)
(<:div :class "script"
(render-javascript window))
;; This works on ff but not ie7 (see above comment).
;(<:script :type "text/javascript"
; (<:as-is ~% "// <![CDATA[" ~%)
; (render-javascript window)
; (<:as-is ~% "// ]]>" ~%))
) ;; render-ajax
;; Adding 'typeof' fixes an ie7 problem where if the javascript object has already been defined
;; jscript will error-out instead of just overwriting the previous object.
;; FF doesn't have this problem, but the fix wont hurt.
(defmethod render-javascript :before ((self ajax-widget))
(<:ai
(js:js*
`(when (= (typeof ,(js-component-id self)) "undefined")
(setf ,(js-component-id self) (new (*object)))))))
In your test application you probably want to change ":www-root" to
":www-roots". That bug cost me almost 2 hours of my life. heh.
And you may want to revise the 01 file to something like the following.
This keeps the encoding from being set to 'NIL', which i had problems with.
:call-action
(lambda (action-id element-id)
(let ((url (+ window.location.pathname
"?" ,+session-parameter-name+ "=" server.current-session
"&" ,+frame-parameter-name+ "=" server.current-frame
"&" ,+action-parameter-name+ "=" action-id))
(enc ,(or (and ( application.charset (context.application *context*))
(symbol-name (application.charset (context.application *context*))))
"UTF-8")))
(dojo.debug "calling-action:" url)
(if (= "FORM" (slot-value ($ element-id) 'node-name))
(dojo.io.bind
(create :url url
:load server.dom.eval-response
:prevent-cache t
:form-node element-id
:method "post"
;; don't change this to 'text/javascript' or else dojo will try to eval
;; the entire blob that is returned to the client as javascript!
:mimetype "text/html"
:encoding enc))
(dojo.io.bind
(create :url url
:load server.dom.eval-response
:prevent-cache t
:mimetype "text/html"
:encoding enc)))
(return false)))
Nice work,
Lou Vanek
Evrim ULU wrote:
> Hi,
>
> I'm very proud to announce ucw+ implementing ajax.
>
> * What is ucw+?
>
> This is an add-on to ucw_dev repository implementing event-based web
> programming. It makes easier to write web applications and provides a
> desktop like programming style to web applications.
[snip]
>
> Have a nice day.
> Evrim.
> _______________________________________________
> bese-devel mailing list
> bese-devel at common-lisp.net
> http://common-lisp.net/cgi-bin/mailman/listinfo/bese-devel
>
revised 02_dom.lisp (works with ie7b3 and ff 1.5.0.4):
;; One note of caution: the code below may break if using broken-parenscript
;; that is unable to accurately generate 'default' cases on switch statements.
;; If working with broken-parenscript you should be able to just comment out
;; the default case.
`(setf server.dom
(create
:is-script-node
(lambda (node)
(return
(and (not (= nil node))
(= (slot-value node 'node-name) "SCRIPT")
(= "text/javascript" (node.get-attribute "type")))))
:is-embedded-script-node
(lambda (node)
(return
(= (dojo.html.get-class node) "script")))
:is-component-node
(lambda (node)
(dj_debug (+ "is-component-node: " (dojo.html.get-class node)))
(return
(= (dojo.html.get-class node) "component")))
;;;; This function parses ajax response and calls specific
;;;; loading functions. Ajax response is:
;;;; <div class="component" id="dynamic-component-id">
;;;; <div class="html">
;;;; HTML Content rendered by render-html
;;;; </div>
;;;; <div class="css">
;;;; CSS Content rendered by render-css
;;;; </div>
;;;; </div>
;;;; <div class="component" id="next-component-id">
;;;; .... similar to above
;;;; </div>
;;;; <div class="javascript">
;;;; controller for this window, evaluated automagically
;;;; to refresh actions and frames.
;;;; </div>
;;;; Ajax response is created by refresh-coretal-component action.
:eval-response
(lambda (type result evt)
(setf root (document.create-element "div"))
(setf root.inner-h-t-m-l result)
(server.event.disconnect-events)
(dolist (child root.child-nodes)
(dj_debug (+ "* current child innerHTML: " child.inner-h-t-m-l))
(when (server.dom.is-script-node child)
(try
(dj_eval child.inner-h-t-m-l)
(:catch (error)
(dj_debug (+ "error while evaluating controller:" error))))
continue)
(when (server.dom.is-embedded-script-node child)
(dj_debug "found embedded script node")
(try
(dolist (script-node (slot-value child 'child-nodes))
(when (= 1 script-node.node-type) ;; skip over whitespace text nodes
(dj_debug "found embedded script node with node type 1; eval it.")
(dj_eval script-node.inner-h-t-m-l)
break))
(:catch (error)
(dj_debug (+ "error while evaluating controller for embedded script:" error))))
continue)
(when (server.dom.is-component-node child)
(try (server.dom.parse-component child)
(:catch (error)
(dj_debug (+ "got error while parsing component response:" error))))
continue)
(dj_debug "evalResponse: neither script nor component node.")
)
(server.event.connect-events)
(dj_debug "ended eval response"))
;;;; This function parses any <div class="component"></div> and loads
;;;; the data into current document.
:parse-component
(lambda (item)
(let ((id (dojo.html.get-attribute item "id")))
(dj_debug (+ "parsing component:" item ", id:" id))
(dolist (sub-item (slot-value item 'child-nodes))
(dj_debug (+ "parse-component: class: "
(dojo.html.get-class sub-item)))
(case (dojo.html.get-class sub-item)
("html" (progn
;debugger
(this.parse-html id sub-item)))
("css" (this.parse-css id sub-item))
(default (dj_debug "ALERT: invalid class? (or no class)."))
))))
;;;; This function parses <div class="html></div> and loads html content
;;;; into current document via altering innerHTML property of the HTML
;;;; element. Event callbacks are temporarily disconnected to avoid
;;;; memory leak in IE.
;; 'let' acts like 'let*' in parenscript.
:parse-html
(lambda (id new-html-node)
(let ((old-html-node (document.get-element-by-id id))
(parent-html-node (slot-value old-html-node 'parent-node)))
(if old-html-node
(progn
(dj_debug "replacing previous node")
(dolist (a-child (slot-value new-html-node 'child-nodes))
(when (= 1 a-child.node-type) ;; skip over whitespace text nodes
(parent-html-node.replace-child a-child old-html-node)
break)))
(progn
(dj_debug "appending node to document")
(document.body.append-child new-html-node)))))
:style-index (new (*object))
:style-index-size
(lambda ()
(return (slot-value (document.get-elements-by-tag-name "style") 'length)))
:parse-css
;;;; This function parses <div class="css"></div> html element and
;;;; loads css into current document via modifying browsers style
;;;; cache.
(lambda (id new-style-node)
(let ((css-index (slot-value this.style-index id))
new-node
(head (aref (document.get-elements-by-tag-name "head") 0)))
(dolist (a-child (slot-value new-style-node 'child-nodes))
(when (= 1 a-child.node-type) ;; skip over whitespace text nodes
(setf new-node a-child)
break))
(if (and new-node (> css-index -1))
(let ((old-style-node (aref (document.get-elements-by-tag-name "style") css-index)))
(head.replace-child new-node old-style-node))
(let ((css-index (this.style-index-size)))
(head.append-child new-node);;new-style-node)
(setf (slot-value server.dom.style-index id) css-index)))))))
More information about the bese-devel
mailing list