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 /// Character data // // interface CharacterData : Node { // attribute DOMString data; // // raises(DOMException) on setting // // raises(DOMException) on retrieval // readonly attribute unsigned long length; // DOMString substringData(in unsigned long offset, // in unsigned long count) // raises(DOMException); // void appendData(in DOMString arg) // raises(DOMException); // void insertData(in unsigned long offset, // in DOMString arg) // raises(DOMException); // void deleteData(in unsigned long offset, // in unsigned long count) // raises(DOMException); // void replaceData(in unsigned long offset, // in unsigned long count, // in DOMString arg) // raises(DOMException); // }; // //--- 'insert-data' and friends would benefit from a ... define open abstract class (, ) end class ; define sealed method do-clone-node (node :: , new-node :: ) => () // We need a fresh copy of the string data in the new node data(new-node) := copy-string(data(node)) end method do-clone-node; define sealed inline method data (cdata :: ) => (data :: ) node-value(cdata) end method data; define sealed inline method data-setter (data :: , cdata :: ) => (data :: ) node-value(cdata) := data end method data-setter; define sealed inline method length (cdata :: ) => (length :: ) size(node-value(cdata)) end method length; define sealed method insert-data (cdata :: , offset :: , string :: ) => () check-read-only(cdata); let data :: = data(cdata); let length :: = length(cdata); let slength :: = size(string); when (offset < 0 | offset > length) error(make(, format-string: "Offset %d is wrong for character data node %=", format-arguments: vector(offset, cdata))) end; let new-data :: = make(, size: length + slength); copy-string-into!(data, 0, offset, new-data, 0); copy-string-into!(string, 0, slength, new-data, offset); copy-string-into!(data, offset, length, new-data, offset + slength); data(cdata) := new-data end method insert-data; define sealed method append-data (cdata :: , string :: ) => () check-read-only(cdata); let data :: = data(cdata); let length :: = length(cdata); let slength :: = size(string); let new-data :: = make(, size: length + slength); copy-string-into!(data, 0, length, new-data, 0); copy-string-into!(string, 0, slength, new-data, length); data(cdata) := new-data end method append-data; define sealed method replace-data (cdata :: , offset :: , count :: , string :: ) => () check-read-only(cdata); check-read-only(cdata); let data :: = data(cdata); let length :: = length(cdata); let slength :: = size(string); when (offset < 0 | offset > length | count < 0) error(make(, format-string: "Offset %d or count %d is wrong for character data node %=", format-arguments: vector(offset, count, cdata))) end; let new-data :: = make(, size: length - count + slength); copy-string-into!(data, 0, offset, new-data, 0); copy-string-into!(string, 0, slength, new-data, offset); copy-string-into!(data, offset + count, length, new-data, offset + slength); data(cdata) := new-data end method replace-data; define sealed method delete-data (cdata :: , offset :: , count :: ) => () check-read-only(cdata); let data :: = data(cdata); let length :: = length(cdata); when (offset < 0 | offset > length | count < 0) error(make(, format-string: "Offset %d or count %d is wrong for character data node %=", format-arguments: vector(offset, count, cdata))) end; let new-data :: = make(, size: length - count); copy-string-into!(data, 0, offset, new-data, 0); copy-string-into!(data, offset + count, length, new-data, offset); data(cdata) := new-data end method delete-data; define sealed method substring-data (cdata :: , offset :: , count :: ) => (string :: ) let data :: = data(cdata); let length :: = length(cdata); when (offset < 0 | offset > length | count < 0) error(make(, format-string: "Offset %d or count %d is wrong for character data node %=", format-arguments: vector(offset, count, cdata))) end; let _start :: = offset; let _end :: = min(_start + count, length); if ((_end - _start) = 0) "" else let string :: = make(, size: _end - _start); copy-string-into!(data, _start, _end, string, 0); string end end method substring-data; define function copy-string (string :: , #key start: _start :: = 0, end: _end :: = size(string)) => (new-string :: ) if ((_end - _start) = 0) "" else let new-string :: = make(, size: _end - _start); copy-string-into!(string, _start, _end, new-string, 0); new-string end end function copy-string; define sealed method copy-string-into! (from :: , start1 :: , end1 :: , to :: , start2 :: ) => () without-bounds-checks for (i :: from start1 below end1, j :: from start2) to[j] := from[i] end end end method copy-string-into!; define sealed method copy-string-into! (from :: , start1 :: , end1 :: , to :: , start2 :: ) => () without-bounds-checks for (i :: from start1 below end1, j :: from start2) to[j] := from[i] end end end method copy-string-into!; /// Text // // interface Text : CharacterData { // readonly attribute boolean isWhitespaceInElementContent; // readonly attribute DOMString wholeText; // Text splitText(in unsigned long offset) // raises(DOMException); // Text replaceWholeText(in DOMString content) // raises(DOMException); // }; // define sealed class () keyword type: = $text-node; end class ; define sealed method split-text (text :: , offset :: ) => (new-text :: ) do-split-text(text, offset, create-text-node) end method split-text; define sealed method do-split-text (text :: , offset :: , creator :: ) => (new-text :: ) check-read-only(text); let data :: = data(text); let length :: = length(text); when (offset < 0 | offset > length) error(make(, format-string: "Offset %d is wrong for text node %=", format-arguments: vector(offset, text))) end; let string1 :: = make(, size: offset); let string2 :: = make(, size: length - offset); copy-string-into!(data, 0, offset, string1, 0); copy-string-into!(data, offset, length, string2, 0); data(text) := string1; let new-text :: = creator(owner-document(text), string2); insert-before(node-parent(text), new-text, next-sibling(text)); new-text end method do-split-text; define sealed method normalize-text (node :: ) => () let text :: = node.%value; let length :: = size(text); let space? :: = #f; // previous character is whitespace let j :: = 0; for (i :: from 0 below length) let char :: = text[i]; if (xml-whitespace?(char)) unless (space?) space? := #t; text[j] := ' '; inc!(j) end else space? := #f; text[j] := text[i]; inc!(j) end end; let _start :: = if (j > 0 & text[0] = ' ') 1 else 0 end; let _end :: = if (j > 0 & text[j - 1] = ' ') j - 1 else j end; if (_start < _end) node.%value := copy-string(text, start: _start, end: _end) else node.%value := "" end end method normalize-text; /// CDATA sections // // interface CDATASection : Text { // }; // define sealed class () keyword type: = $CDATA-section-node; end class ; define sealed method split-text (text :: , offset :: ) => (new-text :: ) do-split-text(text, offset, create-CDATA-section) end method split-text; /// Comments // // interface Comment : CharacterData { // }; // define sealed class () keyword type: = $comment-node; end class ;