--
You received this message because you are subscribed to the Google Groups "v8cgi" group.
To post to this group, send email to v8...@googlegroups.com.
To unsubscribe from this group, send email to v8cgi+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/v8cgi?hl=en.
Hi Ondrej,
window = global, made include(‘FOO’) work perfectly for me on js files without an export table. Thanks for that tip.
Regard the DOM, its seems that most client side library require the DOM to support some features not really required by the specification, I’d like to implement them, as a part of the client compatibility mode (As a part of JS Platform I’m working to allow the server to be able to be a ‘headless’ client), however I don’t want to pollute the DOM with things that can only be described as quirks.
Do you have any preference to how I should organize it?
1) Just add non-standard things to dom.js by default.
a. Pro : Pretty much what the browsers do, so likely to be what most programmers think of ‘correct’ dom behavior.
b. Con : Pollutes the purity of your dom.js implementation with not always nice browser inherited behavior
2) Make a sub-class of DOM something like QuirkyDOM, which builds via inheritance all the quirks that the browsers DOM have.
a. Pro : Separates the quirky stuff out, whilst sharing the core DOM behavior
b. Con : Some of the quirks are quite low level, so the master dom.js might have to be implemented with callbacks, maybe slowing down the pure DOM a bit.
3) Add a Quirks mode to DOM, which replaces the relevant functions internal to DOM with quirky ones.
a. Pro : Separates quirkyness out of the normal DOM but switchable at runtime and changes are internal to dom.js so can fiddle with the internals easier and make sure doesn’t cost pure DOM any overhead
b. Con : Requires replaces functions inside DOM if (for example) DOM.EnableQuirkMode() is called, will make dom.js a bit messier
I personally like the 3rd option, so that default is the nice pure DOM we have now, and as it grows we are still left with a pure standard complaint DOM implementation, but a quick Quirky Mode call and then the DOM objects works enough like the browser ones to fool most client side libraries that they are running in a browser DOM implementation.
A couple of examples of why this is necessary, Elements like Div come into existence on the browsers with properties like style, which are expected in browser side code (e.g. jquery does createElement(‘div’); div.style.FOO = BAR;), another is that its expected that when innerHtml is changed, that the DOM is updated to reflect the new string. Its standard practice to ‘parse’ strings into DOM just by setting innerHtml and then accessing the DOM object.
Thanks,
Deano
i.e.
var doc = new DOM.Document( "XHTML1.0 Transitional" ); // adds !DOCTYPE
header to document and uses the DTD to apply defaults and behavior implied
by this doctype.
doc.createElement( 'div' ); // would now be created standard properties and
defaults.
Implementation wise, I think most flexible would be an extension system
inside DOM.Document.
e.g.
var KnownDocType[] = { "XHTML1.0 Transitional": XHTML1TranCreateFunc,
// Other doc types can go here (or more
likely adaption of the same one)
}
var Document = function( docTypeName ) {
var docType = KnownDocType[ docTypeName || "" ];
if( docType ) {
return docType()
} else
{
// use existing non doctype'd DOM document code
}
}
Then the doctype implementation can have a hash look up in createElement
that instead standard properties and attributes based on the doctype.
Can anybody see anything wrong with that, I'm quite a newbie at Javascript
even though have been a professional C++ coder for too many years, so
perhaps I'm missing some obvious no-no in Javascript land?
Thanks,
Deano
Hi Ondrej,
Your Htmldom sounds like a nice solution to me, it allows for different implementation without messing up dom.js which can stay focused on pure DOM standards and not on lots if browser-DOM behaviours. Also if the user want it to become option a, they can with
var dom = require(“dom”)
Dom = require(“htmldom”).modify(dom);
It will also allow both to be live at the same time if I implement it properly, so that where necessarily the script writer has total control. If I also implement documentImplementation property correctly, a well written script can clone documents etc. safely.
As for when which browser-DOM features, I’m not sure… I totally agree that many make no sense. My aim is purely to provide a fairly standard complaint browser environment under v8cgi, so scripts that make sense can run headless on the server. So any that are too quirky or don’t make sense won’t be added except where specific useful client side libraries require it.
Thanks for the suggestion, I’ll get on with an implementation as per your suggestion, tackling the first few big items I’ve hit (innerHTML and standard properties), as a proof of concept and then it can reviewed (and my bad javascriptism pointed out) and then worked on further as per any suggestions.
Yep agree, I’m going to use your htmldoc approach. And happy to give the c++ side a look over J Had a quick look and it seemed fairly readable, which tbh is usually the most important thing J
Thanks,
Deano
From: Ondřej Žára
[mailto:ondre...@gmail.com]
Sent: 25 October 2010 18:39
To: v8...@googlegroups.com
Cc: DeanoC
Subject: Re: DOM DocTypes
Hi,
Hi,
I’ve produced a working htmldom, that enabled jquery and pure client side libraries to work on v8cgi. I needed to fix a few bugs and add a few features to dom.js so here is the patch for that, a separate htmldom.js incoming soon (its actually another htmlparser file as well).
What it does:
Adds document fragment nodes to dom, it should be DOM level 2 compliant (main feature is that it removes itself when appending to a normal node).
Throws some more errors when passed invalid nodes in places
Fixed bug insertBefore not set the newNodes parent
Similar bug fix for replaceChild
new Element/Attribute/etc. changed to createElement/Attribute/etc.
Exports most dom.classes to allow inheritance (unfortunately can’t fine a way to have c++ style protected, so made then public outside the module)
Patch below,
Bye,
Deano
Index: dom.js
===================================================================
--- dom.js (revision 815)
+++ dom.js (working copy)
@@ -35,11 +35,28 @@
Node.prototype.__defineGetter__("prefix", function() { return null; });
Node.prototype.appendChild = function(node) {
+ if (!node) { throw new Error("Cannot appendChild an undefined node"); }
+ if (node.nodeType == Node.DOCUMENT_FRAGMENT_NODE) {
+ var childToReturn = null;
+
+ var tmp = []
+ for (var i = 0; i < node.childNodes.length; ++i) {
+ tmp.push(node.childNodes[i])
+ }
+ for (var i = 0; i < tmp.length; ++i) {
+ var child = tmp[i];
+ child._removeReferences();
+ this.childNodes.push(child);
+ child.parentNode = this;
+ child._addReferences();
+ childToReturn = child;
+ }
+ return childToReturn;
+ }
+
node._removeReferences();
-
this.childNodes.push(node);
node.parentNode = this;
-
node._addReferences();
return node;
@@ -58,12 +75,31 @@
}
Node.prototype.insertBefore = function(newNode, referenceNode) {
+ if (!newNode) { throw new Error("Cannot appendChild an undefined node"); }
+
if (!referenceNode) { return this.appendChild(newNode); }
var index = this.childNodes.indexOf(referenceNode);
if (index == -1) { throw new Error("Cannot insert before non-existent child"); }
+
+ if (node.nodeType == Node.DOCUMENT_FRAGMENT_NODE) {
+ var childToReturn = null;
+
+ var tmp = []
+ for (var i = 0; i < node.childNodes.length; ++i) {
+ tmp.push(node.childNodes[i])
+ }
+ for (var i = 0; i < tmp.length; ++i) {
+ var child = tmp[i];
+ this.insertBefore(child, referenceNode);
+ childToReturn = child;
+ }
+ return childToReturn;
+ }
+
newNode._removeReferences();
this.childNodes.splice(index, 0, newNode);
+ newNode.parentNode = this;
newNode._addReferences();
referenceNode._addReferences();
@@ -81,6 +117,7 @@
oldChild._removeReferences();
newChild._removeReferences();
this.childNodes.splice(index, 0, newChild);
+ node.parentNode = this;
newChild._addReferences();
return newChild;
@@ -470,7 +507,7 @@
}
Document.prototype.createElementNS = function(ns, name) {
- var elm = new Element(this, name);
+ var elm = createElement(name);
elm.namespaceURI = ns;
return elm;
}
@@ -496,7 +533,7 @@
}
Document.prototype.createAttributeNS = function(ns, name) {
- var attr = new Attr(this, name);
+ var attr = createAttribute(name);
attr.namespaceURI = ns;
return attr;
}
@@ -547,6 +584,7 @@
this._map[Node.PROCESSING_INSTRUCTION_NODE] = this._serializeProcessingInstruction;
this._map[Node.COMMENT_NODE] = this._serializeComment;
this._map[Node.DOCUMENT_TYPE_NODE] = this._serializeDocumentType;
+ this._map[Node.DOCUMENT_FRAGMENT_NODE] = this._serializeDocumentFragment;
}
XMLSerializer.prototype.serializeToString = function(document) {
@@ -570,6 +608,12 @@
return str;
}
+XMLSerializer.prototype._serializeDocumentFragment = function (document) {
+ var str = "";
+ str += this._serializeChildNodes(document);
+ return str;
+}
+
XMLSerializer.prototype._serializeDocumentType = function(dt) {
var str = "<!DOCTYPE " + dt.nodeName;
var arr = [];
@@ -1160,3 +1204,10 @@
exports.XMLSerializer = XMLSerializer;
exports.DOMParser = DOMParser;
exports.Node = Node;
+exports.Attr = Attr;
+exports.Element = Element;
+exports.CharacterData = CharacterData;
+exports.Text = Text;
+exports.CDATASection = CDATASection;
+exports.Comment = Comment;
+exports.ProcessingInstruction = ProcessingInstruction;
\ No newline at end of file
From: Ondřej Žára
[mailto:ondre...@gmail.com]
Sent: 25 October 2010 18:39
To: v8...@googlegroups.com
Cc: DeanoC
Subject: Re: DOM DocTypes
Hi,
Isn’t it always the way!, I managed to use a slightly wrong file to patch from (I was being careful and reapplying and then missed a chunk grrr).
In dom.js, Line 85 insertBefore function, replace the if(node.nodeType == Node.DOCUMENT_FRAGMENT_NODE) with the following
if (newNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE) {
var childToReturn = null;
var tmp = []
for (var i = 0; i < newNode.childNodes.length; ++i) {
tmp.push(newNode.childNodes[i])
}
for (var i = 0; i < tmp.length; ++i) {
var child = tmp[i];
this.insertBefore(child, referenceNode);
childToReturn = child;
}
return childToReturn;
}
Sorry for the mistake,
Deano
Hi,
Hi Ondrej,
Below is a new patch, with the points raised fixed.
Has my bug fix applied, fixes that issues with this in create[Element|Attribute] and added the createDocumentFragment (missed as I’m mostly testing with htmldoc sub-class which I had added it). Sorry for the missing this, still a bit of javascript newbie so remembering where and how to apply this, sometimes catches me out.
Style wise I expect I should apply the special DOCUMENT_FRAGMENT_NODE behavior of appendChild and insertBefore to a custom overload of those functions… but that’s just a tidy up and a small optimization, so I’ll leave that for now, its that’s okay?
Thanks,
+ if (newNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE) {
+ var childToReturn = null;
+
+ var tmp = []
+ for (var i = 0; i < newNode.childNodes.length; ++i) {
+ tmp.push(newNode.childNodes[i])
+ }
+ for (var i = 0; i < tmp.length; ++i) {
+ var child = tmp[i];
+ this.insertBefore(child, referenceNode);
+ childToReturn = child;
+ }
+ return childToReturn;
+ }
+
newNode._removeReferences();
this.childNodes.splice(index, 0, newNode);
+ newNode.parentNode = this;
newNode._addReferences();
referenceNode._addReferences();
@@ -81,6 +117,7 @@
oldChild._removeReferences();
newChild._removeReferences();
this.childNodes.splice(index, 0, newChild);
+ node.parentNode = this;
newChild._addReferences();
return newChild;
@@ -470,7 +507,7 @@
}
Document.prototype.createElementNS = function(ns, name) {
- var elm = new Element(this, name);
+ var elm = this.createElement(name);
elm.namespaceURI = ns;
return elm;
}
@@ -496,7 +533,7 @@
}
Document.prototype.createAttributeNS = function(ns, name) {
- var attr = new Attr(this, name);
+ var attr = this.createAttribute(name);
attr.namespaceURI = ns;
return attr;
}
@@ -508,6 +545,12 @@
return dt;
}
+Document.prototype.createDocumentFragment = function () {
+ var df = new Node(this, "#document-fragment");
+ df.nodeType = Node.DOCUMENT_FRAGMENT_NODE;
+ return df;
+}
+
Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
Document.prototype.cloneNode = function(deep) {
@@ -547,6 +590,7 @@
this._map[Node.PROCESSING_INSTRUCTION_NODE] = this._serializeProcessingInstruction;
this._map[Node.COMMENT_NODE] = this._serializeComment;
this._map[Node.DOCUMENT_TYPE_NODE] = this._serializeDocumentType;
+ this._map[Node.DOCUMENT_FRAGMENT_NODE] = this._serializeDocumentFragment;
}
XMLSerializer.prototype.serializeToString = function(document) {
@@ -570,6 +614,12 @@
return str;
}
+XMLSerializer.prototype._serializeDocumentFragment = function (document) {
+ var str = "";
+ str += this._serializeChildNodes(document);
+ return str;
+}
+
XMLSerializer.prototype._serializeDocumentType = function(dt) {
var str = "<!DOCTYPE " + dt.nodeName;
var arr = [];
@@ -1160,3 +1210,10 @@
Below is a new patch, with the points raised fixed.
Has my bug fix applied, fixes that issues with this in create[Element|Attribute] and added the createDocumentFragment (missed as I’m mostly testing with htmldoc sub-class which I had added it). Sorry for the missing this, still a bit of javascript newbie so remembering where and how to apply this, sometimes catches me out.
Style wise I expect I should apply the special DOCUMENT_FRAGMENT_NODE behavior of appendChild and insertBefore to a custom overload of those functions… but that’s just a tidy up and a small optimization, so I’ll leave that for now, its that’s okay?
Oops, the patch gets broken when inserted into mail body. Please
attach the diff file as an attachment...
Sorry,
Ondrej
>
> Has my bug fix applied, fixes that issues with this in create[Element|Attribute] and added the createDocumentFragment (missed as I'm mostly testing with htmldoc sub-class which I had added it). Sorry for the missing this, still a bit of javascript newbie so remembering where and how to apply this, sometimes catches me out.
>
>
>
> Style wise I expect I should apply the special DOCUMENT_FRAGMENT_NODE behavior of appendChild and insertBefore to a custom overload of those functions... but that's just a tidy up and a small optimization, so I'll leave that for now, its that's okay?
I have added a specific cloneNode function to DocumentFragment, even tho the
DOM spec state that it should act exactly as Node, in practice I've found
that's it's expected to be able to clone itself, so either our base Node
class should also have a clone that does something or it is an area where
spec and practice differ.
Any problems, happy to fix :)
Deano
Commited in r816. Thanks!
> I have added a specific cloneNode function to DocumentFragment, even tho the
> DOM spec state that it should act exactly as Node, in practice I've found
> that's it's expected to be able to clone itself, so either our base Node
> class should also have a clone that does something or it is an area where
> spec and practice differ.
>
In my opinion, the DOM states that DocumentFragment exposes the same
interface, but it is not forbidden for DF::cloneNode()'s
implementation to differ from Node::cloneNode() or
Element::cloneNode(). This being said, I am happy with the way you
implemented DF::cloneNode(). I also refactored the inheritance code a
bit, so all instances now have correct ".constructor" property (I
initially thought that this might allow us to have only one cloneNode
implementation in Node, but it turned out I was wrong).
Now can perhaps be a good time to add DocumentFragment unit test. I
will do this, if I have some spare time later.
Sincerely,
Ondrej
Ahh think that caused the light bulb in my head to finally switch on :)
Node is what in C++ land we would think of as an abstract base class. It
sets up the shared interface for all sub-classes of nodes and shared
behavior in some cases. As cloneNode can't be implemented at the Node level
the Node::cloneNode returning null is effective the same as saying virtual
Node* cloneNode() = 0 in C++, stating that this is a part of the Node
interface and every valid child class must implement it.
Would it be better to throw an error in any of Node 'abstract' functions. As
that should only happen if a sub-class has not implemented that function (so
breaking the interface contract) or the user has explicitly created a Node,
which is also bad as its not meant to stand as a separate object?
Sorry if this is simple everyone knows Javascript, its freer implementation
of these things beyond more static languages with fixed object models, means
I'm still getting to grips with all the various forms of inheritance and
prototypes :).
Going to re-factor my HTMLDom with your new inherit function, much nicer
than the previous inherit code :)
For unit testing, would you like me to write some tonight? My testing so far
has been applying jquery and pure functions through it and eye-balling the
correct results.
Thanks,
Yeah, the correpondence with classical (class-based) inheritance is
very strong here. I am relatively indifferent about throwing an
exception in Node::cloneNode, mainly because the Node interface was
not exported (until your recent - and correct - change) so far. If you
wish, feel free to add the "throw" statement...
As for Node's creation - one can also "throw" in the Node constructor,
but there are ways to overcome this:
var tmp = function() {};
tmp.prototype = Node.prototype;
var a = new tmp();
a instanceof Node; // true, but no Node() function called!
Under these circumstances (prototypal inheritance can be tricky!), I
think that security measures preventing Node instantialization are not
very relevant.
> Going to re-factor my HTMLDom with your new inherit function, much nicer
> than the previous inherit code :)
As said before, the inheritance stuff can be complex. Feel free to ask
about how this works...
>
> For unit testing, would you like me to write some tonight? My testing so far
> has been applying jquery and pure functions through it and eye-balling the
> correct results.
>
I would appreciate that. There already is a unit test for the dom
module, written using standardized (commonjs-compliant) modules "test"
and "assert". I encourage you to modify it by adding more checks and
tests using the newly created DocumentFragment interface...
Ondrej
Attached is an extension to dom.js unit test, checks the appendTo and
insertBefore works as expected on and to doc fragments and that when
appended to another node the doc fragment transfers its children not itself.
Also patch has a bug fix to dom.js createDocumentFragment found whilst
running the test (I had always created them via the sub-class I'm working on
so had never actually called createDocumentFragment before the unit test).
HTH,
Cool, commited in r817 ;)
O.
Another patch for dom.js for you,
-------------------------
Fixes typo on removeChild
Changes all new ElementX to this.ownerDocument.createElementX in cloneNode
function, so sub-modules don't have to re-implement cloneNode just to change
new ElementX to new MyElementX
Added an early out in one place, and made newAttribute use node var name to
slightly reduce memory and be more consistent with other branch path.
Fix a typo in createDocumentFragment and exported it
Allowed _serializeNode to return undefined to skip the serialization of this
node, used in htmldom.js to skip default attribute. Making for prettier
serialization (excess white space without it)
Bye,
thanks a lot, commited in r818. I left your patch mostly unmodified -
I just simplified the attribute serialization condition so all "falsy"
values are respected.
O.
2010/11/5 Deano <dean....@gmail.com>: