reptile7's JavaScript blog
Wednesday, June 30, 2010
 
Custom-Built for Linking
Blog Entry #183

Today we will address the use of a custom dialog box to solicit a link URL from the user for Microsoft's "execCommand Example: Creating a Link" demo. In the sections below, we'll craft such a box from scratch and then integrate it with the non-MSIE demo code that we developed in the previous entry, with a separate demo to follow.

The box

Our custom dialog box will be modeled on Microsoft's own document.execCommand("createLink"); "Hyperlink" dialog box and will look like this:

[Our custom dialog box]

The library blues

I walked over to my local library hoping to obtain a screen shot file of the Microsoft "Hyperlink" box, but it was not to be:

(1) I took an Alt-PrtSc screen shot of the "Hyperlink" box and could paste it into a Microsoft Word window, but was unable to save it to the desktop because the Save commands of the Word version on the library's computers have somehow been disabled.

(2) Neither Microsoft Paint nor any other graphics editor is installed on the library's computers. (Application-wise, these computers are stripped rather cleanly vis-à-vis a normal PC.)

(3) The "Hyperlink" box screen shot would not paste into a Gmail "Compose Mail" message field.

Arrggghhhh!!!!! I tried. But I was at least able to write down enough information about the box for us to move forward...

Basic structure and functionality

Microsoft's "Hyperlink" box basically comprises a set of four controls:
(1) a selection list for choosing a URL scheme;
(2) a text field for holding the link URL;
(3) an OK button for sending the link URL to the opener document; and
(4) a Cancel button.

The selection list contains ten options, in source order:
(other), file:, ftp:, gopher:, http:, https:, mailto:, news:, telnet:, wais:
The http: option is selected initially.



<select id="select0" onchange="getScheme(this);">
<option value="">(other)</option>
<option value="file://">file:</option>
...
<option value="http://" selected="selected">http:</option>
...
<option value="telnet://">telnet:</option>
<option value="wais://">wais:</option>
</select>


The option values can be loaded into the text field

<input type="text" id="input0" name="myURL" value="http://" />

via the following getScheme( ) function:
function getScheme(mySelect) {
	var sI = mySelect.selectedIndex;
	var oV = mySelect.options[sI].value;
	document.getElementById("input0").value = oV; }
Of course, for entering a relative URL into the field, the user is free to delete the preloaded scheme.

We will detail the action of the OK button

<button type="button" id="b1" onclick="getURL( );">OK</button>

in the "The return" section below. As for the Cancel button, it must at least close the box, but you also might want it to pop up a message for the user:
<button type="button" id="b2" onclick="ifClose( );">Cancel</button>
...
function ifClose( ) {
	window.alert("You can't create a link if you don't input a URL.");
	window.close( ); }
Layout and related extras

The Type: and URL: captions that respectively precede the selection list and text field are semantically labels, so let's mark them up that way. Moreover, the selection list and text field appear to be 'structured' with fieldset and legend elements, so let's add those guys too:

#fieldset0 { float: left; height: 65px; }
...
<fieldset id="fieldset0">
<legend>Hyperlink Information</legend>
<label for="select0">Type:</label> <select id="select0" onchange="getScheme(this);"> ... </select>
<label for="input0">URL:</label> <input type="text" id="input0" name="myURL" value="http://" />
</fieldset>


The fieldset must be floated left in order to flow the OK and Cancel buttons down its right side.

Let's give all the controls specific widths - this doesn't guarantee that they'll have the same size across browsers, but it helps:

#select0 { width: 70px; }
#input0 { width: 300px; }
#b1, #b2 { width: 60px; }


The field of a conventional prompt( ) box will hold, depending on the browser, 30-40 characters. Giving the input0 control a size="40" attribute does not produce a uniform-width field, FYI.

To make the OK and Cancel buttons look more like 'real' dialog box buttons, I've given them both outset border-styles and have also slightly thickened the OK button border-width. (Check out HTML Goodies' indispensable "CSS and Borders" tutorial, which is illustrated with various CSS borders.) And true to the Aqua GUI, the OK and Cancel buttons have respectively been given bluish and off-white background-colors - interestingly, doing this causes their shapes to change from oval to rectangular - they're a dull gray in Microsoft's original box, if I recall correctly:

#b1 { border: outset 4px; background-color: #cae3fd; }
#b2 { border: outset; background-color: #fefefe; }


I've shifted the buttons rightward and downward a bit, per my preference:

#b1, #b2 { margin-left: 8px; margin-top: 8px; }

The Microsoft title bar, including its close button, can be reproduced (more or less) by the following div element:

#div1 { background-color: blue; color: white; }
#b0 { position: relative; left: 350px; background-color: #fefefe; }
...
<div id="div1">Hyperlink <button type="button" id="b0" onclick="ifClose( );">X</button></div>


Finally, the box itself is framed by an outer div element:

#div0 { width: 450px; height: 110px; border: 1px solid black; }
...
<div id="div0"> ... </div>


Key effects

If you want the pressing of the enter/return key to simulate the clicking of the OK button, then that's pretty easy to do:
function keyEffects(e) {
	/* I don't know if there are any non-MSIE browsers out there that only support Microsoft's event model, but just to be on the safe side... */
	var thisKey = e ? e.which : (event ? event.keyCode : ""); // See Blog Entry #143 for more on this conditional.
	if (thisKey == 13) getURL( ); } // 13 is the decimal Unicode code position of a carriage return.
document.onkeypress = keyEffects;
Now, if we really wanted to be Windows nerds, we would include code that directs focus to the selection list and to the text field upon typing (shift-)alt-T and (shift-)alt-U, respectively, per the underlined T and U in the Type:/URL: labels; my attempts to do so have been only partially successful, however. On a Mac, the option/alt key is inter alia used to generate non-keyboard characters. Typing option-T generates a (dagger) character, whose decimal Unicode code position is 8224, whereas typing shift-option-T generates a ˇ caron phonetic modifier, whose decimal Unicode code position is 711. It follows that a

if (thisKey == 8224 || thisKey == 711) document.getElementById("select0").focus( );

conditional should bring focus to the selection list in response to the option-T or shift-option-T key combination, and this is indeed the case.

The decimal Unicode code positions for a lowercase t and an uppercase T are 116 and 84, respectively. However, an

if ((thisKey == 116 && e.altKey) || (thisKey == 84 && e.altKey)) { ... }-type

conditional cannot be used to flag the option-T and shift-option-T key combinations on a Mac, although this might work on the Windows side, I don't know.

The Mac uses the option-U and shift-option-U key combinations to place umlauts over vowels. The decimal Unicode code position for an umlaut is 168, which is the thisKey value for the shift-option-U key combination but not for the option-U key combination. Weirdly, none of the OS X GUI browsers on my computer detects a keypress event at all upon typing option-U; without getting into the details, switching from onkeypress to onkeydown or onkeyup did not help. Still, I see no harm in adding
if (thisKey == 168) document.getElementById("input0").focus( ); and
if ((thisKey == 117 && e.altKey) || (thisKey == 85 && e.altKey)) document.getElementById("input0").focus( );
conditionals to the keyEffects( ) function.

BTW, my preferred way to underline the T and U is to wrap the Type: label and selection list in a <div id="div2" class="fl"> ... </div> element and to wrap the URL: label and text field in a <div id="div3" class="fl"> ... </div> element and then give these div elements a .fl:first-letter { text-decoration: underline; } style. (The :first-letter pseudo-element cannot be applied directly to the label element, at least not without giving the latter a non-inline display.)

The return, part 1

Popping up our custom dialog box is accomplished classically via the window.open( ) method:

var newWindow = window.open("customDialog.html", "", "width=468,height=128");

The window.open( ) method returns an object reference for the new window that it opens, newWindow in this case. If the preceding command caused the operating system to block - i.e., if the computer just stopped and waited for the user to
(a) enter a URL into the custom dialog box's text field and
(b) click the OK button
before moving on to the rest of the script - then a

var linkURL = newWindow.document.getElementById("input0").value;

assignment could be used to grab the user's URL for the createLink command; alternatively, if we were to append an

<input type="hidden" id="input0" name="myURL" />

control to the opener document source, then a

opener.document.getElementById("input0").value = document.getElementById("input0").value;

customDialog.html command would similarly send the user's URL to the opener document, where it could be picked up by the AddLink( ) function via a

var linkURL = document.getElementById("input0").value;

assignment. But as discussed in the previous post, window.open( ) does not block the operating system; as a result, the user's URL does not get to the opener document in time for the createLink command to act on it. What to do? Tune in to our next episode for a not-quite-cross-browser solution to this problem.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

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