reptile7's JavaScript blog
Sunday, May 30, 2010
 
The Unideal Copy
Blog Entry #180

In today's post we will discuss the adaptation of the MSIE-for-Windows-specific script of HTML Goodies' "Click... It's Copied!" tutorial to other browsers. To refresh your collective memories, here's the JavaScript code that we would like to 'translate' if at all possible:
function ClipBoard( ) {
	holdtext.innerText = copytext.innerText;
	Copied = holdtext.createTextRange( );
	Copied.execCommand("Copy"); }
We noted two entries ago that non-MSIE browsers do not support the execCommand( ) method for the standard Range object, but they will allow us to pair execCommand( ) with the document object, so that's what we'll need to do. But there's actually a second and equally important support issue we need to consider vis-à-vis the Copied.execCommand("Copy"); command: What kind of browser support do we have out there for the copy execCommand( ) command?

Query it

The copy command appears on both Microsoft's list and Mozilla's list of supported execCommand( ) commands, but that doesn't mean we should take its support for granted.

Alongside the execCommand( ) method Microsoft implemented a queryCommandSupported( ) method that can be used to test support for a given execCommand( ) command independent of whether a document or any of its elements is user-editable or not. The queryCommandSupported( ) method acts on a single parameter, a case-insensitive string specifying the execCommand( ) command to be tested, and then [r]eturns a Boolean value that indicates whether the current command is supported on the current range. Like execCommand( ), queryCommandSupported( ) is applied by Microsoft to the document and TextRange objects and also to the mysterious controlRange collection.

Of the OS X GUI browsers on my computer, the queryCommandSupported( ) method is supported by Opera, Safari, and Chrome. With Safari and Chrome document.queryCommandSupported("copy"); returns true, but with Opera it returns false. In corroboration, at Mozilla's "Rich-Text Editing Demo" I am indeed able to copy text in the iframe field to the clipboard when using Safari and Chrome but not when using Opera.

The queryCommandSupported( ) method appears in Mozilla's list of document object methods but there's no separate page for it and Mozilla now maintains a separate page for it here. With Firefox and Camino*, document.queryCommandSupported returns function queryCommandSupported() { [native code] }** but document.queryCommandSupported("bold"); - bold being an execCommand( ) command that is definitely supported by these browsers - throws an NS_ERROR_NOT_IMPLEMENTED error. (The Dottoro Web Reference describes this situation as 'support but not implementation' - make of that what you will.)

*Camino does not have a native Error Console - download one here and follow the Terminal instructions on this page if necessary.

**MSIE 5.x for the Mac also returns function queryCommandSupported() { [native code] } for document.queryCommandSupported but returns undefined for any document.queryCommandSupported("commandID"); command.

Back at Mozilla's rich-text editing demo, my attempts to copy text in the iframe field to the clipboard when using Firefox and Camino met with failure, perhaps not so surprisingly given that the copy entry in Mozilla's list of execCommand( ) commands reads:

copy
Copies the current selection to the clipboard. Clipboard capability must be enabled in the user.js preference file. See [1]

The [1] hyperlink leads to a "Setting Prefs for the Mozilla Rich Text Editing Demo" page specifying a set of user preferences that, for local experimentation purposes, can be added to Firefox in order to enable Firefox's support for the cut, copy, and paste execCommand( ) commands. I followed the page's instructions as they pertain to the Firefox/ and Camino/ folders in my ~/Library/Application Support/ directory, setting the capability.policy.allowclipboard.sites preference to http://www.mozilla.org/editor/midasdemo/. Didn't help.

The MozillaZine Knowledge Base contains a "Granting JavaScript access to the clipboard" article that addresses why Mozilla-based browsers do not normally execute the cut/copy/paste commands:
By default, JavaScript is not allowed to read or set your clipboard data for security and privacy reasons. This is because Web site scripts can erase and replace what you currently have in your clipboard (data loss issue) and they can read whatever you have in your clipboard (security and privacy issue); as such, you should grant access with caution.
Interestingly, "Granting JavaScript access to the clipboard" links to a "Midas" page that in turn links to a "cuneAform HTML Editor" at which with Firefox and Camino the following alert( ) box rolls down from the browser window's title bar upon trying to invoke the editor's Copy selection, Cut selection, and Paste from clipboard operations:

['No programmatic access to cut/copy/paste' error]

Lastly, "Granting JavaScript access to the clipboard" says that Mozilla's browsers can use signed scripts to access the user's clipboard. We previously discussed signed scripts and their limitations in Blog Entry #158. IMO, the signed script business is much more trouble than it's worth, and as a Mac user I am unable to use Netscape's script-signing signtool program anyway, so perhaps we should just move on and concentrate on getting the "Click... It's Copied!" script to work with Safari and Chrome, huh?

Select and copy

According to Microsoft, the copy execCommand( ) command doesn't have an associated user interface and doesn't take a value, required or optional. We noted last time that Safari and Chrome follow the Microsoft execCommand( ) syntax model and not the Mozilla execCommand( ) syntax model; as a result, we'll be using document.execCommand("copy"); and not document.execCommand("copy", false, null); to copy a test string to the clipboard.

(Upon trying out the Mozilla rich-text editing demo and the cuneAform HTML editor at my local library today, I learned that the copy command causes MSIE 8 to pop up a confirm( )-like box asking whether or not to grant access to the clipboard - a "Community Content" commenter at Microsoft's copy page reports that MSIE 7 also does this - so it seems that copy does now have a user interface of sorts, even if it only involves making a true/false-type choice. Upon choosing true, I was able to copy text and subsequently paste it into a Microsoft Word window without any problems. Safari and Chrome do not dialogue the user in any way for cut, copy, and paste - maybe they should.)

But we'll actually need one more command to pull this off. In order to copy a string with document.execCommand("copy");, we'll first have to select that string, something Joe didn't have to do with his TextRange object. And to mimic the effect of Joe's code, we would like to select that string programmatically if at all possible, as opposed to selecting it mousically, which, after all, we could do, and then copy the string via the browser's Edit menu, without hassling with the execCommand( ) method in the first place.

As far as I know, there is no cross-browser way to programmatically select normal text (in, say, a p element) on a normal Web page. Microsoft equips its TextRange object with a select( ) method that can do this sort of thing, but the standard Range object unfortunately does not have such a method. However, classical JavaScript did give the client-side text, textarea, password, and fileUpload objects a select( ) method for selecting their values - see here, for example. It follows that retooling the "Click... It's Copied!" script for Safari and Chrome is a simple matter of
(a) putting the to-be-copied string in a visible and sized-as-desired textarea field (or text field if it's a short string) in the first place, and then
(b) recasting the ClipBoard( ) function as:
function ClipBoard( ) {
	document.getElementById("textareaID").select( );
	document.execCommand("copy"); }
Try it out below - upon clicking the button, your browser should select and copy to the clipboard the <p>This is a paragraph.</p> string, which can then be pasted wherever a Paste operation is applicable, IF you're using Safari (download it for free here) or Chrome (download it for free here), and I would think that it would work for MSIE 5.5+ as well (but I'd have to make a return trip to the library to confirm that).



There are a couple of drawbacks to the above select-and-copy method:
(1) Although CSS declarations can be used to format entire values of textarea/text objects, substrings of those values cannot be formatted individually.
(2) By default, textarea and text fields are user-editable, whereas you might want to prevent the user from editing your to-be-copied text. (Microsoft's contentEditable page claims that contentEditable applies to textarea/text fields. It should therefore be possible to use a contentEditable="false" assignment to choke off the editability of these fields, but my attempts to do so with the various non-MSIE OS X GUI browsers on my computer were unsuccessful.)

These disadvantages can be circumvented by a more laborious but more flexible select-and-copy method:
(1) Put the to-be-copied text in a separate document, where it can be marked up per your preference.
(2) Load the document into an iframe.
(3) Give the iframe element an id value and use document.getElementById("iframeID").contentDocument to access its document from the iframe's host document.
(4) To ensure the uneditability of your text, leave the designMode property of the iframe document off (I find that contentEditable="false" assignments have no effect at all on a designMode="on" document).
(5) The text can be selected with execCommand( )'s selectAll command prior to copying it.
function ClipBoard( ) {
	Copied = document.getElementById("iframeID").contentDocument;
	Copied.execCommand("selectAll");
	Copied.execCommand("copy"); }
Neither the copy command nor the selectAll command changes a document in any way, so you wouldn't think it'd be necessary to turn on a document's/element's editability for these commands, and this is indeed the case with Safari and Chrome (and also with Opera for selectAll); this would not be the case with Firefox and Camino, which do not 'expose' execCommand( ) as a 'member' of the document object in the absence of editability, but then again, we (well, I at least) can't copy with those guys anyway.

Markup subtraction

In the tutorial's "What If There Is Code?" section Joe briefly discusses the removeFormat execCommand( ) command, which [r]emoves the formatting tags from the current selection. The word "formatting" is too vague for my tastes so I decided to see what removeFormat would and would not subtract. Upon applying removeFormat to various elements, I can report that removeFormat will reliably remove the markup for inline text-related elements, specifically the font style elements (b, big, etc.) and the phrase elements (abbr, acronym, etc.) plus a few others (span, q, sup/sub, even font), but beyond that, what happens is highly browser-dependent: for example, Opera, Safari, and Chrome will remove the markup for an <a href="http://www.whatever.com/">I am a link</a> hyperlink, and thus convert I am a link to non-link text, but Firefox and Camino will not. The removeFormat command will not subtract the markup for a center element, which definitely counts as "formatting" in my book.

Joe seems to suggest that removeFormat removes <br> line breaks: not true.

Regarding the original "Click... It's Copied!" script, the use of removeFormat to remove markup would in fact be redundant because the to-be-copied string is accessed via the innerText property, which, as noted two entries ago, leaves behind all of the markup in the content of its 'calling object', including that for block-level elements, which is typically not removed by removeFormat.

In the next post, we'll wrap up our discussion of the execCommand( ) method by going through the Example on Microsoft's execCommand( ) page.

reptile7

Tuesday, May 18, 2010
 
Executorship of Command
Blog Entry #179

We continue today our discussion of HTML Goodies' "Click... It's Copied!" tutorial and its ClipBoard( ) function that uses the execCommand( ) method to copy a text string to the operating system's clipboard.

More on execCommand( )

Let's begin by fleshing execCommand( ) out a bit more. Per its name, the execCommand( ) method can execute various commands on a document or a portion thereof. As noted in the previous entry, the execCommand( ) method was implemented by Microsoft in MSIE 4 for Windows. Microsoft applied execCommand( ) initially to the document and TextRange objects and later to a "controlRange collection" (whose sketchy documentation and nonsupport on my iMac have prevented me from figuring out just what it is, so we're not gonna discuss it). Subsequently, execCommand( ) was picked up for Firefox and other browsers, which, as far as I am aware, only support it for the document object. Moreover, the W3C is bringing document.execCommand( ) into HTML5.

Microsoft posts here a "Command Identifiers" page with a list of supported (and not currently supported) execCommand( ) commands; Mozilla lists a somewhat-differing set of supported execCommand( ) commands here. Most of these commands change a document in some way, for example, by formatting text or inserting new elements, although a few do not. At least on the Mozilla side, execCommand( ) is meant to be used in conjunction with either
(a) the designMode property of the document object, which must be set to on, or
(b) the contentEditable attribute/property, which can be applied to most elements/objects and must be set to true,
and this might be the case on the Microsoft side as well, even though the MSDN Library's execCommand( ) page and its document.execCommand("CreateLink"); Example mention neither designMode nor contentEditable.

Before we go any further, I should clear up something I said at the end of the previous post, namely, that document.execCommand( ) is supported by MSIE 5.x for Mac OS X: this is true 'in theory' but not in practice. In response to the conditional below

if (document.execCommand) window.alert("Yes");
else window.alert("No");


the three versions of MSIE 5.x on my computer - MSIE 5.2.3 (OS X), MSIE 5.1.6 (Classic), and MSIE 5 (Classic) - all pop up the Yes alert( ) message*; in addition, they return function execCommand() { [native code] } for document.execCommand itself. Sounds like we're good to go, eh? However, my attempts to run actual document.execCommand( ) commands with these browsers have been uniformly unsuccessful.

*MSIE 4.5 throws an Object doesn't support this property or method error so I guess that means No. BTW, the MSIE 5.x browsers all return undefined for both document.designMode and document.body.contentEditable.

Another aside:
Support for the designMode property can be reliably assessed with an analogous
if (document.designMode) window.alert("Yes"); else window.alert("No"); statement
but the same is not always true for the contentEditable property via an
if (document.body.contentEditable) window.alert("Yes"); else window.alert("No"); statement.
Regarding the latter conditional:
• Firefox and Camino return inherit for document.body.contentEditable and thus pop up the Yes alert( ) message.
• Safari and Chrome return false as a string for document.body.contentEditable. As an if condition, a false string converts to true and therefore these browsers pop up the Yes alert( ) message.
• Opera returns false as a boolean for document.body.contentEditable and thus pops up the No alert( ) message.

In any case, document.execCommand( ), designMode, and contentEditable are supported by all of the other (non-MSIE) OS X GUI browsers on my computer. Setting document.designMode to on or equipping the body element start-tag with a contenteditable="true" attribute turns a page into one large editable field in which a user can add and edit content in various ways, somewhat like using a word processor. Manipulating such a page with document.execCommand( ) commands is easier said than done, however.

The Remarks section of the aforecited MSDN Library execCommand( ) page notes, Do not invoke the execCommand method until after the page loads. I can confirm that execCommand( ) commands have no effect if they are run as top-level code in a script element in the document head; rather, they are meant to be fired via "widgets" (user interface elements) of some sort - typically by clicking push buttons, although any mouse/keyboard-type actions on relevant elements could be used in this regard. In setting up an execCommand( ) field, it is in practice desirable to separate the interface for manipulating the field from the field itself for at least two reasons:
(1) Widgets that are part of an editable field can be deleted or otherwise edited by the user - not good, obviously.
(2) Most execCommand( ) commands act at a mouse-cursor position or selection. If a widget is part of an editable field, its use will with some browsers (notably Safari) withdraw focus from the position or selection at which the widget's associated execCommand( ) command is meant to act: loss of focus = no command effect.

One approach to achieving editable field/interface separation is to load the editable field document into an iframe and then place the execCommand( ) widgets in the iframe's host page - for an example thereof, check out Mozilla's rich-text editing demo. And if you're using designMode to make the iframe src page editable, this approach will for Firefox, Opera, and Camino circumvent a peculiar designMode aspect noted here by Mozilla: [O]nce a document is switched to designMode, all [event-triggered JavaScript commands in] that particular document are disabled (at least on my computer, this quirk is not exhibited by Safari and Chrome).

Alternatively, a simpler approach to field/interface separation is illustrated by Mark Finkle's contentEditable demo: instead of using an entire page for an editable field, code a large div element equipped with a contenteditable="true" attribute, and then place the execCommand( ) widgets outside (before or after) the div element.

Syntax

Before I roll out my own demo, we should probably discuss the execCommand( ) syntax a bit. Depending on the command and depending on the browser, the execCommand( ) method can have one, two, or three parameters:

(1) The first execCommand( ) parameter is a case-insensitive string specifying the command to be carried out: copy, indent, justifyRight, etc.

(2) There are four execCommand( ) commands - createLink, insertImage, print, and saveAs - that require or can optionally deploy an associated user interface, more specifically, a dialog box with which the user interacts in some way; for example, the image-inserting insertImage command can pop up a prompt( )-like box asking for a URL path to an image the user wants to insert. The second execCommand( ) parameter is a boolean switch for activating (true) or disabling (false) this interface.

(3) Many execCommand( ) commands can or must act on a value; these values are set out in the third execCommand( ) parameter (although sometimes they are solicited from the user, as noted above).

The Syntax box on the MSDN Library's execCommand( ) page shows the second and third execCommand( ) parameters to be optional. Microsoft's "Command Identifiers" page links to separate pages for each execCommand( ) command; going through the individual command pages reveals that:
• If a given command doesn't act on a value or if its value is optional, then the third execCommand( ) parameter can be omitted, but if a command requires a value, then the third execCommand( ) parameter must be specified.
• The second execCommand( ) parameter must be set to false for commands that require values but is optional in all other cases; for commands to which it is relevant, this parameter defaults to true if it is omitted.

On the Mozilla side, all three parameters must be specified for all execCommand( ) commands (see point #7 on this page) even though the second execCommand( ) parameter is not implemented in Mozilla and should thus be set to false in all cases (you can also set it to null - check the source of the aforelinked contentEditable demo). Mozilla's execCommand( ) commands either require values or don't take them at all - for the latter cases, the third execCommand( ) parameter should be set to null.

We can clarify the above with a few examples:

(1) The text-bolding bold command doesn't have an associated user interface and doesn't take a value, required or optional. On the Microsoft side, we can simply write
document.execCommand("bold");,
but on the Mozilla side, we have to write
document.execCommand("bold", false, null);.

(2) The text-coloring foreColor command doesn't have an associated user interface but does require a value, specifically, an RGB hex code or a recognized color name. If we want to create some red text with foreColor, then both Microsoft and Mozilla require us to write
document.execCommand("foreColor", false, "#ff0000"); // Or just "red" for the third parameter.

(3) For the aforediscussed insertImage command, Microsoft gives us the option of dialoguing the user for an image URL via
document.execCommand("insertImage"); /* You can include a true second parameter but it's not necessary. */
or hard-coding an image URL into the source via
document.execCommand("insertImage", false, "/images/myImage.gif");,
whereas Mozilla only grants us the latter option.

(4) The no-interface insertHorizontalRule command generates a new hr element. Microsoft allows us to equip the hr element with an id attribute value via an optional third execCommand( ) parameter string, i.e.,
document.execCommand("insertHorizontalRule", false, "hr1"); /* The second parameter can be omitted in this case. */
produces
<hr id="hr1">;
however, if we don't want or care about an id value, then
document.execCommand("insertHorizontalRule");
is all we need. Mozilla's insertHorizontalRule doesn't take a value** and thus we are left with
document.execCommand("insertHorizontalRule", false, null);.

**Contradicting other Mozilla materials, Mozilla's "Midas" page claims that insertHorizontalRule can indeed take an id value-providing argument. In practice on my computer, Firefox and Camino turn
document.execCommand("insertHorizontalRule", false, "hr1");
into an id-lacking
<hr style="width: 100%; height: 2px;">.

I find that Safari, Opera, and Chrome generally follow the Microsoft syntax model: only the first execCommand( ) parameter is necessary for a command that doesn't take a value but all three parameters are needed for a command that requires a value. On the other hand, and as you would expect, Firefox and Camino follow the Mozilla syntax model, i.e., all three parameters are required in all cases.

One last point regarding the Mozilla syntax model:
On its "Midas Specification" page, Mozilla states, If [the second execCommand( ) parameter] is set to true, you will get an error (NS_ERROR_NOT_IMPLEMENTED). When using Firefox, I do see this error with, say,
document.queryCommandSupported("print");
(we'll discuss the queryCommandSupported( ) method in the following entry), but not with, say,
document.execCommand("createLink", true, null);,
which does nothing at all: a dialog box does not pop up and no errors are thrown.

Demo

We'll get to this first thing next time.

reptile7

Wednesday, May 05, 2010
 
Text, Text on the Range
Blog Entry #178

In the Don't take my stuff (please...) subsection of the previous post, we demonstrated that, for a JavaScript-enabled browser, a return false; statement will prevent the mousedown-based selection and copying of text on a Web page. Today we consider the opposite situation: what if you wanted to facilitate the copying of such content?

At the MSDN Library, Microsoft prefaces its code samples with Copy hyperlinks (see here*, for example) that when clicked trigger a function that copies those samples to the operating system's clipboard IF you're an MSIE for Windows user. Actually, I can't rule out that there might be other Windows browsers that will run the Copy function, but the Copy links don't work with any of the browsers on my iMac.
(*October 2016 Update: Microsoft has evidently discontinued the Copy facility.)

We may go through Microsoft's code-copying code later, but for now let's turn to our HTML Goodies tutorial du jour, "Click... It's Copied!", which relatedly presents a script that copies a text string to the clipboard upon clicking a push button. In its original form, the "Click... It's Copied!" script is also Mac-incompatible, but all is not lost: after some experimentation I came up with a revamped script that would work with Safari and Chrome.

In this entry, we'll deconstruct the "Click... It's Copied!" script in detail; depending on how long that takes, I'll discuss my changes to the script in this or the next post.

Script overview and HTML

In brief, here's what the "Click... It's Copied!" script does:
(1) The script scoops up the text content of a span element and loads it into a textarea field.
(2) The textarea text is converted into a corresponding "TextRange object".
(3) The TextRange object text is written to the clipboard by the object's execCommand( ) method, a command available only in IE 4.0 or better at the time the tutorial was written.

The script's HTML is given below:

<span id="copytext" style="height:150;width:162;background-color:pink">This text will be copied onto the clipboard when you click the button below. Try it!</span>
<br>
<textarea id="holdtext" style="display:none;"></textarea>

<button onclick="ClipBoard( );">Copy to Clipboard</button>


Joe put the This text will be copied onto the clipboard when you click the button below. Try it! string in an id="copytext" span element, but he could have used almost any renderable non-empty element (p, div, a, etc.) for this purpose, as explained later.

Joe attempts to presentationally highlight the span element text by mounting it on a 162px-by-150px pink 'square' via a height:150;width:162;background-color:pink set of style declarations. OK, class, who can spot the problems in this run of CSS?

"You can't use width and height with spans."

Quite. Neither the CSS width property nor its height counterpart applies to "non-replaced inline elements", which would include our good friend the span element, would it not? As a result, the width:150; and height:162; declarations are ignored by pretty much all browsers except MSIE, which will indeed apply CSS widths and heights to a span element. Now, what else?

"It's illegal for CSS lengths to not have any units!"

Right you are, although in practice most if not all browsers will respectively interpret 150 and 162 to be 150px and 162px, and then apply these 'actual' values to a relevant element. Another hand...

"The pink color name isn't recognized by the W3C."

Not currently, true, but it's on track to be.

For those of you not surfing with MSIE, here's what Joe's CSS looks like when applied to a corresponding div element:

This text will be copied onto the clipboard when you click the button below. Try it!

We will in due course copy the span element text to the id="holdtext" textarea element that follows the span element. In the tutorial's "The Text To Be Copied" section, Joe notes that the textarea field has been made invisible via a display:none; style declaration. Actually, in CSS an "invisible" element still occupies its normal area on the page, you just can't see it, whereas display:none; goes beyond this and shrinks an element's area to 0. As a practical matter, it's not necessary to 'invisibilize' the textarea field, which can if desired be used to hold the This text will be copied... string in the first place.

Speaking of textarea dimensions, Joe did not equip the textarea element with cols and rows attributes, which are both #REQUIRED. It might seem silly to specify these attributes for a display:none; textarea field, but you gotta have 'em if you were to ever run this code through a validator.

Finally, the textarea element is followed by a button element that is meant to code a push button for triggering the script's ClipBoard( ) function and thus should be given a type="button" attribute. Without specifying its type, the button is in fact a submit button, not that we'll be submitting anything when we click the button given that the textarea and button elements do not have a form element parent.

Script element deconstruction

We begin by clicking the button, which calls the ClipBoard( ) function composing the script's script element. ClipBoard( )'s first statement assigns the span element's innerText to the textarea element's innerText:
function ClipBoard( ) {
	holdtext.innerText = copytext.innerText;
The innerText property was implemented by Microsoft in MSIE 4: innerText [s]ets or retrieves the text between the start and end tags of the object. Of the OS X GUI browsers on my computer, innerText is supported by MSIE, Opera, Safari, and Chrome, but not by Firefox and Camino.

Much like the DOM textContent property, innerText only picks up the #PCDATA textual content of an object; for example, for a

<span id="span1">Some like it <strong>hot</strong></span>

span object, document.getElementById("span1").innerText returns the Some like it hot string but leaves the strong element markup behind.

Joe reports that the script didn't work when he tried to use an <input type="hidden"> element instead of the textarea element: this is because innerText must be paired with a non-empty element. Moreover, the Remarks section of the MSDN Library's innerText page states, The innerText property is valid for block elements only, suggesting that innerText cannot be used with inline elements, but the Applies To box at the bottom of the page makes it clear that this is not the case. Indeed, all content-holding elements are fair game for use with innerText except for applet, colgroup, dl, dt, frameset, head, noframes, noscript, object, optgroup, and style.

Now, how 'bout them hierarchy expressions, huh? You wouldn't think (or at least I didn't think) that holdtext.innerText and copytext.innerText would be sufficient to access the textarea element and the span element, respectively, and that an absolute

document.getElementById("holdtext").innerText = document.getElementById("copytext").innerText;

statement would be needed to send the span element text to the textarea element. To sort this matter out, I tested the holdtext.innerText = copytext.innerText; command with a visible textarea box. The verdict: yep, they're sufficient - the text was successfully copied and no errors were thrown.

Relatedly, Joe notes, In case you're wondering, I tried the script changing out name for id and the JavaScript wouldn't recognize it. It's true that both the W3C and Microsoft nix the use of the name attribute with the span element. But Joe definitely could have given the textarea element a name, put it in a form, and then referenced it with a document.formObject.textareaName-type expression; for MSIE/Opera users, document.all("textareaName") could be used to reference a named textarea object even in the absence of a form.

Let's move on to the next ClipBoard( ) statement:

Copied = holdtext.createTextRange( );

The createTextRange( ) method, and the TextRange object it returns, were implemented by Microsoft in MSIE 4 for Windows. The createTextRange( ) method [c]reates a TextRange object for the element; in turn, the TextRange object [r]epresents text in an HTML element. Notwithstanding its definition, which superficially doesn't seem to be any different than that for the textContent property - substitute String for TextRange and they're dead ringers - createTextRange( ) can only be applied to a handful of elements: body, button, input, and textarea. On my computer, createTextRange( ) is only supported by Opera, and Opera only supports it for the input and textarea elements. With MSIE 5.2.3 for Mac OS X, createTextRange( ) throws an Object doesn't support this property or method runtime error for all of the aforelisted elements.

So at least with Opera, we now have a This text will be copied onto the clipboard when you click the button below. Try it! TextRange object having a Copied identifier. I should point out, however, that there is a standard version of the above createTextRange( ) operation. The DOM Level 2 Range Specification defines a Range object representing a contiguous run of content in a document and also a document.createRange( ) method that returns such an object. We can easily create a Range containing the textarea element text with:

Copied = document.createRange( );
Copied.selectNodeContents(document.getElementById("holdtext"));


All of the non-MSIE OS X GUI browsers on my computer support the Range object and the document.createRange( ) method. Up to this point, then, there's no reason why the ClipBoard( ) function couldn't be formulated in a cross-browser manner given that the initial holdtext.innerText = copytext.innerText; assignment could also be achieved via either the textContent or innerHTML property. Unfortunately, ClipBoard( )'s final command thrusts us into 'irredeemably proprietary' territory:

Copied.execCommand("Copy"); }

Also implemented by Microsoft in MSIE 4 for Windows, the execCommand( ) method [e]xecutes a command on the current document, current selection, or the given range. execCommand( ) brings us into the realm of rich-text editing, more specifically, it can be used to create the rich-text sections of Web pages: inter alia, execCommand( ) can bold/italicize/underline text, set font sizes and typefaces, and create lists and tables, at least for those browsers that support it.

Apropos the "Click... It's Copied" tutorial, execCommand( ) can also carry out Cut, Copy, and Paste operations à la a word processor. In the event, running the Copied.execCommand("Copy"); command with Opera threw a Type mismatch error, i.e., Opera evidently does not support the execCommand( ) method for the TextRange object. Ever the optimist, I tried with non-MSIE browsers to run execCommand( ) commands on a standard Range object, but those attempts were similarly unsuccessful.

On the other hand, subsequent experimentation revealed that all of the OS X GUI browsers on my computer, including MSIE, support execCommand( ) for the document object, and on that note, we will continue our execCommand( ) conversation in the following entry.

reptile7


Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)