Module: dom-internals Synopsis: Document Object Model Author: Scott McKay Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Implement [part of] the collection protocol for /// Note that this only deals with the element nodes of a DOM tree /// All other node types are effectively ignored /// The implication is that, e.g., 'size(child-nodes(elt))' may not /// return the same value as 'size(elt)', etc. define sealed method element (elt :: , key :: , #key default = $unsupplied) => (child :: type-union(, )) block (return) local method find-key (elt :: ) return(elt) end method; do-elements-by-tag-name(find-key, elt, name: key); if (supplied?(default)) default else error(make(, format-string: "No such element %= in %=", format-arguments: vector(key, elt))) end end end method element; // We don't provide 'element-setter' because the key is part of // the child element... define sealed method element-setter (child :: , elt :: , key :: ) => (child :: ) error("You can't set element children this way") end method element-setter; define sealed method size (elt :: ) => (size :: ) let children :: = child-nodes(elt); count(method (c) instance?(c, ) end, children) end method size; define sealed method empty? (elt :: ) => (empty? :: ) let children :: = child-nodes(elt); count(method (c) instance?(c, ) end, children) = 0 end method empty?; /// Implement [part of] the sequence protocol for define sealed method element (elt :: , index :: , #key default = $unsupplied) => (child :: type-union(, )) //--- The new Chris Double semantics just returns the n'th child if (index >= elt.child-nodes.size) if (supplied?(default)) default else error(make(, format-string: "No element with index %d in %=", format-arguments: vector(index, elt))) end else elt.child-nodes[index] end /* //--- The old Scott McKay semantics returns the n'th descendent element //--- Which is the desirable behavior? block (return) let n :: = -1; // don't count 'elt' itself... local method find-key (elt :: ) if (index = n) return(elt) else inc!(n) end end method; do-elements-by-tag-name(find-key, elt); if (supplied?(default)) default else error(make(, format-string: "No element with index %d in %=", format-arguments: vector(index, elt))) end end */ end method element; // We don't provide 'element-setter' because the key is part of // the child element... define sealed method element-setter (child :: , elt :: , key :: ) => (child :: ) error("You can't set element children this way") end method element-setter; define sealed method add! (elt :: , child :: ) => (elt :: ) append-child(elt, child); elt end method add!; define sealed method add (elt :: , child :: ) => (elt :: ) error("Use 'clone-node' and 'add!' instead of 'add'") end method add; define sealed method remove! (elt :: , child :: , #key test, count) => (elt :: ) ignore(test, count); remove-child(elt, child); elt end method remove!; define sealed method remove (elt :: , child :: , #key test, count) => (elt :: ) ignore(test, count); error("Use 'clone-node' and 'remove!' instead of 'remove'") end method remove; /// Implement [part of] the array protocol for define sealed method aref (elt :: , #rest indices) => (child :: type-union(, )) apply(element-aref, elt, indices) end method aref; define sealed inline method element-aref (elt :: , key :: , index :: ) => (child :: false-or()) block (return) let n :: = if (tag-name(elt) = key) -1 else 0 end; local method find-key (elt :: ) if (index = n) return(elt) else inc!(n) end end method; do-elements-by-tag-name(find-key, elt, name: key); #f end end method element-aref; // We don't provide 'aref-setter' because the key is part of // the child element... define sealed method aref-setter (child :: , elt :: , #rest indices) => (child :: ) error("You can't set element children this way") end method aref-setter; /// Iteration define sealed inline method forward-iteration-protocol (elt :: ) => (initial-state :: , limit :: , next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ); values(element-initial-state(elt), element-limit-state(elt), element-next-state, element-finished-state?, element-current-key, element-current-element, element-current-element-setter, element-copy-state) end method forward-iteration-protocol; define function element-initial-state (elt :: ) => (initial-state :: ) let children :: = child-nodes(elt); position-if(children, method (c) instance?(c, ) end, start: 0) | size(children) end function element-initial-state; define function element-limit-state (elt :: ) => (limit-state :: ) let children :: = child-nodes(elt); size(children) end function element-limit-state; define inline function element-next-state (elt :: , state :: ) => (next-state :: ) let children :: = child-nodes(elt); position-if(children, method (c) instance?(c, ) end, start: state + 1) | size(children) end function element-next-state; define inline function element-finished-state? (elt :: , state :: , limit :: ) => (finished? :: ) state = limit end function element-finished-state?; define inline function element-current-key (elt :: , state :: ) => (key :: ) state end function element-current-key; define inline function element-current-element (elt :: , state :: ) => (child :: ) let children :: = child-nodes(elt); children[state] end function element-current-element; define inline function element-current-element-setter (child :: false-or(), elt :: , state :: ) => () error("You can't set element children this way") end function element-current-element-setter; define function element-copy-state (elt :: , state :: ) => (new-state :: ) state end function element-copy-state; /// Trampolines from documents define sealed method element (doc :: , key :: type-union(, ), #key default = $unsupplied) => (child :: type-union(, )) let elt = document-element(doc); if (elt) element(elt, key, default: default) elseif (supplied?(default)) default else error(make(, format-string: "No top-level element in document %=", format-arguments: vector(doc))) end end method element; define sealed method element (doc :: , key :: type-union(, ), #key default = $unsupplied) => (child :: type-union(, )) let elt = body(doc); if (elt) element(elt, key, default: default) elseif (supplied?(default)) default else error(make(, format-string: "No BODY element in document %=", format-arguments: vector(doc))) end end method element; define sealed method element-setter (child :: , doc :: , key :: ) => (child :: ) error("You can't set document children this way") end method element-setter; define sealed method aref (doc :: , #rest indices) => (child :: type-union(, )) let elt = document-element(doc); if (elt) apply(element-aref, elt, indices) else error(make(, format-string: "No top-level element in document %=", format-arguments: vector(doc))) end end method aref; define sealed method aref (doc :: , #rest indices) => (child :: type-union(, )) let elt = body(doc); if (elt) apply(element-aref, elt, indices) else error(make(, format-string: "No BODY element in document %=", format-arguments: vector(doc))) end end method aref; define sealed method aref-setter (child :: , doc :: , #rest indices) => (child :: ) error("You can't set element children this way") end method aref-setter;