Dr John Stockton said:
H'mmm. Yes and no.
To write a freshly-computed string S into an existing page at location L
requires
X(L, S)
for some well-chosen function name X - DynWrite seems suitable.
Even if it is called from only one place in the source, the operation
should for modularity and legibility be done by a subroutine.
Modularity is good, but in projects of such miniscule size as a single
web page, it doesn't increase legibility more than a well chosen
comment. It probably even increases the size of the file.
If it is called from more than one place in the source, the operation
should also be done by a subroutine for compactness.
It is always a good idea to factor out common code. If for nothing
else, it avoids needing to syncronize the different versions. A bug
that is only fixed in some of the cases is even harder to find when
you believe you already fixed it.
The function in FAQ 4.15 seems OK to me; is improvement possible?
I positively hate it, but that is because I dislike the Function
constructor as much as eval, or even more (its scope rules irritate
me too).
Having two levels of programming language present at the same time
significantly complicates reasoning about the program.
In, e.g.,
x + Function("y","return y+x")(4)
when the "x + Function( )(4)" is executed, it is already parsed
(or even compiled in the case of JScript.NET), while "return y+x"
is living as a language level string.
Syntax highlighting fails for code-as-values, syntax errors are
caught late instead of early, ... I can't find anything good to
say about it. Function and eval should be used for dynamic code
only, not for when the programmer knows that its one of three
prewritten options.
ISTM that it uses the technique you advocate.
It does, although using other features that I don't advocate.
(what does ISTM mean, btw? I probably should know, but it escapes
me at the moment)
Here is my suggestion. It is longer, but (IMNSHO) prettier, and it
works in hypothetical browsers that support DOM but not innerHTML.
---
var getRef;
if (document.getElementById) {
getRef = function(id){return document.getElementById(id);}
} else if (document.all) {
getRef = function(id){return document.all[id];}
} else if (document.layers) {
getRef = function(id){
function searchLayers(doc) {
if (doc.layers[id]) {return doc.layers[id];}
for(var i=0;i<doc.layers.length;i++) {
var res = searchLayers(doc.layers
.document);
if (res) {return res;}
}
}
return searchLayers(document); // search layers recursively
}
}
var setText;
if (document.createTextNode) {
setText = function(node,text) {
while(node.hasChildNodes()) { // clear children
node.removeChild(elem.lastChild);
}
node.appendChild(document.createTextNode(text));
}
} else if (document.body && document.body.innerHTML) {
setText = function(node,text) {
node.innerHTML = text;
}
} else if (document.layers) {
setText = function(node,text) { // assume node is an NS4 layer
node.document.open();
node.document.write(text);
node.document.close();
}
}
function dynWrite(id,text) {
if (!getRef || !setText) {return;}
var elem = getRef(id);
if (!elem) {return;}
setText(elem,text);
}
---
(tested in Opera 7, IE6, MozFB, and Netscape 4.80)
N.B. Whether or not one wants to code positively for IE4-type &
NS4-type browsers, ISTM that for a Web page IE4 & NS4 ought at least to
fail benignly, but perceptibly.
In that case, one can drop the document.layers part of the above.
A Web user of DynWrite should program (IMHO) at least the first call of
DynWrite as
if (!DynWrite(L, S)) alert('Problem!')
or some refinement thereof, where S is a test string.
An exception handler might be better, but then it won't work in
Netscape 4. Sadly the "try/catch" construction isn't backwards
compatible (and ironically, you can't catch the error .
I believe the present FAQ version could be compacted by
if (!!document.all) DocStr="return document.all[id]" // etc.
The "!!" is not necessary in an if condition, it is converted to a
boolean anyway.
/L