Chuck Everson

Navigation

Skip navigation.

Search

Site navigation

Email conversation

FromChuck Everson
ToMe
SubjectUsing insertAdjacentHTML with window.external.menuArguments
Date7 April 2007 12:17
Attachmentscreenshot showing DIVs inserted before tables
Hello Tarquin,

First off - thanks for the work you do on your website.

It is well done, a great resource and I've learned a lot reading there -
much appreciated.

I'm sure your busy and I hate to bother you, but I've read over the emails
on your site regarding external.menuArguments and you really seem to have a
grasp on it better than anyone I've seen.

As such, I'm hoping you can spare a moment or two for me.

I've been working on a project that ties into the IE context menu.  I've
been [searching] and downloading various example bits of code to study and test
with.

Slowly but surely I am starting to get my head around it<g>.

Right now I am trying to create a script that would simply read in the
elements on the page and insert a <div> in front of them.  The <div> would
provide a simple outline so that the layout of the entire page could be
visible.

I've found code examples that show how to add a border to images and tables,
but what I have in mind is to use the insertAdjacentHTML (or something
similar) to put my <div> in before them.

This would allow me to assign a unique ID to each one as it was added - then
I could manipulate or access the content of "my" <div> with the innerHTML
reference (knowing exactly which <div> was being accessed).

So - on to my questions:

1)  Could you suggest what is the best method to find the insertion points -
Is there a way to insert before all elements, or do I need to do it based on
the element types (by calling the code multiple times - such as first for
TABLES, then DIVS, etc)?

2)  I have tried this code, which will tell me (for example) how many tables
are on the page and insert the <div> - but I am not getting the  desired
results.

<script type="text/javascript" defer="defer">
var w = window.external.menuArguments;

if ( w != null )
{
  var doc = w.document;
  var tablelist
  var cnt

 tablelist = doc.getElementsByTagName("TABLE");

 alert( 'There are ' + tablelist.length + ' tables'  );

  for ( cnt = 0; cnt < tablelist.length; cnt++)
  {
   var thistable = tablelist[ cnt ];
   thistable.insertAdjacentHTML( 'beforeBegin',
     '<div style="border:2px solid red;"></div>');
   }
}


This seems to insert the <div> before the table - but the table does not
appear to be "contained" within the <div> as you can see in this test ran on
a sample page with two small tables on it:

[See attachment]

I tried changing to use insertAdjacentElement so that the <div> would become
part of the document as an element (and hopefully then contain the table),
but I get errors that seem to tell me that I am not referencing the element
(where the insertion occurs) correctly.

I really hope that what I am saying makes sense here and I feel that the
answer is (or should be) obvious and perhaps just some sort of syntax error
on my part.

I know that when operating inside the external.menuArguments realm that
things seem to get even more picky than usual about how you refer to an
object and its properties and I've been digging for a while to try and see
what I am doing wrong.

I really appreciate whatever help and advice you can offer.

Many thanks!


Chuck
FromMe
ToChuck Everson
SubjectRe: Using insertAdjacentHTML with window.external.menuArguments
Date8 April 2007 16:35
Chuck,

> Is there a way to insert before all elements, or do I need to do it based
> on the element types

Pity IE does not support XPath, because that could easily select all
relevant elements in one simple step. As it is, you will need to repeatedly
use getElementsByTagName to select each different kind of element you are
interested in (be _very_ careful when selecting DIVs because
getElementsByTagName returns a live NodeList, and if you add extra DIVs, it
will be updated to include them, and you will get an infinite loop).

You can then use something like this to insert the new DIVs, using DOM
instead of IE's HTML insertion methods:
var oWindow = window.external.menuArguments;
var oTables = oWindow.document.getElementsByTagName('table'), foo;
for( var i = 0; i < oTables.length; i++ ) {
  foo = oWindow.document.createElement('div');
  foo.innerHTML = 'whatever you want the content to be';
  foo.style.border = '2px solid red';
  oTables[i].parentNode.insertBefore(foo,oTables[i]);
}

> This seems to insert the <div> before the table - but the table does not
> appear to be "contained" within the <div>

Aha, so you want to put the table inside it, not after it. OK, so a small
change:
var oWindow = window.external.menuArguments;
var oTables = oWindow.document.getElementsByTagName('table'), foo, bar;
for( var i = 0; i < oTables.length; i++ ) {
  foo = oWindow.document.createElement('div');
  foo.innerHTML = '<p>this appears before the table</p>';
  foo.style.border = '2px solid red';
  bar = oTables[i].parentNode.replaceChild(foo,oTables[i]);
  foo.appendChild(bar);
}


Mark 'Tarquin' Wilton-Jones - author of http://www.howtocreate.co.uk/
FromChuck Everson
ToMe
SubjectRe: Using insertAdjacentHTML with window.external.menuArguments
Date8 April 2007 18:42
> Pity IE does not support XPath, because that could easily select all
> relevant elements in one simple step.

Ah yes - IE.  I fear that is Gate's way of punishing us all for being
interested in computers<vbg>.

> As it is, you will need to repeatedly use getElementsByTagName to select
> each different kind of element you are interested in (be _very_ careful
> when selecting DIVs because getElementsByTagName returns a live NodeList,
> and if you add extra DIVs, it will be updated to include them, and you
> will get an infinite loop).

Excellent.

I'd finally came to a realization that something like that would be
required.

>   bar = oTables[i].parentNode.replaceChild(foo,oTables[i]);

I never thought of using replaceChild - good call.

My code that was somewhat working was:


function        frameDiv( divName )
{
  var thelist

  thelist = oWindow.document.getElementsByTagName( divName );

  for ( cnt = 0; cnt < thelist.length; cnt++)
  {
      var thisitem = thelist[ cnt ];
      var parent = thisitem.parentNode;
      var thisid = 'MyDiv' + cnt;
      var framestr = '<div id="' + thisid + '">';
      var frame = oWindow.document.createElement( framestr );
      frame.onclick = WhatDiv;
      frame.onmouseover = LineOn;
      frame.onmouseout  = LineOff;
      parent.insertBefore(frame, thisitem);
      parent.removeChild(thisitem);
      frame.appendChild(thisitem);
   }
}

On gathering objects like a table, it seems to work well, gives the visual
indicator when the element is selected and returns the innerHTML (the
original content) onclick.

The one thing I have found is that if I try to expand the concept to allow
selection of a table cell - the div never appears and sometimes the browser
hangs.

Using the function above I was calling it twice as:

frameDiv( 'TABLE' );
frameDiv( 'TD' );


To figure out what elements where on the page, I was playing around with
some code like this:

  var elementcount = oWindow.getElementsByTagName("*")
  var ecount
  var thiselement

  for ( ecount = 0; ecount < elementcount.length; ecount++ )
  {
      frameDiv( thiselement );
  }


If I run the code with just an alert, it will name the elements (from the !,
then html, head, etc - then finally the body and other tags).

I tried to come up with a way (using a switch statement) to only respond to
the tags I wanted, but a weird thing happens.

When the code calls frameDiv - the for loop seems to lose its mind and
starts over.

I must be missing something there!

Any suggestions on how best to do that?



One final question and/or idea...


A slightly different idea I had on this was to override the onmouseover,
onmouseout and onclick handlers for the code in the
window.external.menuArguments run.

Then I thought about just having some code in those events that put the
border on (saving any original border first - maybe as an expando?), then
restoring the original border as the mouse goes off, and finally alerting
the HTML of the object clicked in the onclick.

This would eliminate the need to insert the <div>.

I can make the code work in a static web page with code like this  (some
stuff I hacked together from other code I've seen)...


function LineOn(e)
{
var targ
if (!e) var e = window.event
  if (e.target) targ = e.target
  else if (e.srcElement) targ = e.srcElement
  if (targ.nodeType == 3) // defeat Safari bug
    targ = targ.parentNode
    var tname
    tname=targ.tagName
    targ.style.border = "2px solid red";
}


function LineOff(e)
{
var targ
if (!e) var e = window.event
  if (e.target) targ = e.target
  else if (e.srcElement) targ = e.srcElement
  if (targ.nodeType == 3) // defeat Safari bug
    targ = targ.parentNode
    var tname
    tname=targ.tagName
    targ.style.border = "none";
}


function whichElement(e)
{
var targ
if (!e) var e = window.event
  if (e.target) targ = e.target
  else if (e.srcElement) targ = e.srcElement
  if (targ.nodeType == 3) // defeat Safari bug
    targ = targ.parentNode
    var tname
    tname=targ.tagName

    alert(targ.innerHTML)
}

Then in the body statement I have:

<body onmousedown="whichElement(event)" onmouseover="LineOn(event)"
onmouseout="LineOff(event)"></body>



As I said, this code works pretty well to the same effect, but I have not
figured out how to get the the onmouseover, onmouseout and onclick handlers
for the code in the window.external.menuArguments run.



Also if I went that route - I'd need to somehow store the original border
state (for whatever element type it was) and then "restore" it on the
onmouseout.

I noticed that on tables = the table border disappears (visually), but the
correct HTML is returned.



One more thing (if I may...)

After I visually modify the code (say for example I took a modified version
of this and used it to outline elements on a page on a double-click, and the
outlines "stay"), is there a statement that will let me capture the HTML of
the document in the modified state?

What I'd like to be able to do with that is take the modified HTML and put
it into a new window (or perhaps send it to another app) - but without
losing the formatting applied.


Hey thanks again for your help!

It is nice to see that my studies have been apparently heading in the right
direction and get some confirmation that I am starting to get my head around
this stuff.

I look forward to hearing from you as I feel I'm making some progress here.

Chuck
FromChuck Everson
ToMe
SubjectRe: Using insertAdjacentHTML with window.external.menuArguments
Date8 April 2007 19:45
Hi Tarquin,

Here is a strange one...

> var oWindow = window.external.menuArguments;
> var oTables = oWindow.document.getElementsByTagName('table'), foo, bar;
> [...]

If I try to use this to add a div around a div...

> var oTables = oWindow.document.getElementsByTagName('div'), foo, bar;

Then IE seems to lock up every time.

I wonder if this is related to the issue I mentioned in my last email where
I said that when I call my frameDiv function that the for loop seemed to
jump back to the top?

I'll dig around some more on this - but since more and more sites are using
CSS for layout instead of tables - I really need to be able to get the
contents of a div as well.

Thanks for any ideas...


Chuck
FromMe
ToChuck Everson
SubjectRe: Using insertAdjacentHTML with window.external.menuArguments
Date8 April 2007 19:48
Chuck,

>       var framestr = '<div id="' + thisid + '">';
>       var frame = oWindow.document.createElement( framestr );

Just so you know, this is invalid. createElement should only be passed the
name of an element, not actual markup. IE allows it anyway, so it should not
matter for your use in an IE context menu, but they may just fix that bug at
some point, at which point it will break. This is a valid alternative:
var frame = oWindow.document.createElement( 'div' );
frame.id = thisid;

> frameDiv( 'TD' );

Divs are not allowed around a TD. TDs can only have a TR as their parent.

> When the code calls frameDiv - the for loop seems to lose its mind and
> starts over.

This is because getElementsByTagName returns a live NodeList. Every time you
create a div, it is added to that collection. Then your code calls frameDiv
for that new entry, which creates another entry, etc. This makes an infinite
loop. To avoid it, make an array first. Use getElementsByTagName)'*'), loop
through it, add each element in turn into your array. Then perform your
normal loop on the array instead. it will not change as you add extra DIVs
to the document.

> Then I thought about just having some code in those events that put the
> border on (saving any original border first - maybe as an expando?), then
> restoring the original border as the mouse goes off, and finally alerting
> the HTML of the object clicked in the onclick.

This would be so much more easy if IE supported event capturing. But no.

> As I said, this code works pretty well to the same effect, but I have not
figured out how to get the the onmouseover, onmouseout and onclick handlers
for the code in the window.external.menuArguments run.

window.external.menuArguments maps to the window object of the page, and the
event attributes on body are normally mapped to window (for legacy reasons).
So ...

window.external.menuArguments.onclick = function () {
  alert(...);
};

or using the actual body instead:

window.external.menuArguments.document.body.onclick = function () {
  alert(...);
};

> After I visually modify the code (say for example I took a modified
> version of this and used it to outline elements on a page on a double-
> click, and the outlines "stay"), is there a statement that will let me
> capture the HTML of the document in the modified state?

alert(document.documentElement.innerHTML)
(that will be missing the <html> tags and doctype, but will contain
everything inside the <html> tags)


Tarquin
FromChuck Everson
ToMe
SubjectRe: Using insertAdjacentHTML with window.external.menuArguments
Date8 April 2007 22:09
Hi Tarquin,

> This is a valid alternative:
> var frame = oWindow.document.createElement( 'div' );
> frame.id = thisid;

Ah - thanks for the pointer.  I didn't know that one.

I'm using that method to set other properties of the newly created div, so
I'll move that one as well.

>> frameDiv( 'TD' );
> Divs are not allowed around a TD. TDs can only have a TR as their parent.

I figured that was the case (or something like it).

I wonder if I could get away with some other markup (short of building a
nested table/tr/td)?  I tried  a span just now - but that did not seem to
work either

> This is because getElementsByTagName returns a live NodeList.

Ah - that makes sense.

> This would be so much more easy if IE supported event capturing. But no.

Well thanks for confirming that before I wasted a lot of time on it!

> window.external.menuArguments.onclick = function () {
>   alert(...);
> };

Cool - I'll play around with that.

It seemed like I should have been able to do it - just never could get my
events to fire.

> alert(document.documentElement.innerHTML)

Thanks - I'll give that a go.

;-)

Thanks again for the help.

Chuck
FromChuck Everson
ToMe
SubjectRe: Using insertAdjacentHTML with window.external.menuArguments
Date9 April 2007 12:57
Hi Tarquin,

I hope your doing well today.

I know your busy and hate to bother you again - but feel like I'm making
some progress and hopefully just have a kink or two to work out.

I've been successful at creating a function that parses all the elements and
adds them to an array, then I take that array and add divs using your code
example.  I skip over the TD and TR tags for now (although if I get the rest
of this working I have an idea to pull the TD data out - wrap it in a <span>
with the same actions and replace it where it came from...


But back to my code:


As the divs are created, I assign an onmouseover onmouseout and onclick
event to them.

The mouseover, mouseout and onclick work fine ... for a while.

Then they just stop responding and my page has to be refreshed before they
work again.

:-(


The code I am using is:

var oWindow = window.external.menuArguments;

if ( oWindow != null )
{

  var oDoc                      = oWindow .document;     //The document

  var thelist
  var thistag
  var cnt
  var flag_body

  var theelements = new Array();
  var elementcount

  thelist = oDoc.getElementsByTagName( '*' );

  for ( cnt = 0; cnt < thelist.length; cnt++)
  {
     thistag = thelist[cnt].tagName;

    if( thistag == 'BODY' )
    {

           // set our flag and continue to the next element
           flag_body = true;
                continue;
         }

         // If we are past the body tag
         if( flag_body == true )
          {
           // If this is a <br> tag - continue to the next element
                if( thistag == 'BR' )
                  continue;
           // If this is a <tbody> tag - continue to the next element
                if( thistag == 'TBODY' )
                  continue;
           // If this is a <TR> tag - continue to the next element
                if( thistag == 'TR' )
                  continue;

          // Add the element to our array
          theelements.push( thelist[cnt] );
          elementcount = theelements.length
           }
     }


    var newDiv
    var newHTML
    var thiselement
    var divID
    var newElementsAdded = 0;

    for ( cnt = 0; cnt < theelements.length; cnt++)
    {
       theelements[cnt].getAttribute("id") );
       thiselement = theelements[cnt];

       if( thiselement.tagName == 'TD' )
          continue;
       if( thiselement.tagName == 'TR' )
          continue;

        newDiv = psDocument.createElement('div');
        newDiv.style.border = '2px solid black';
        newDiv.style.backgroundColor = 'yellow'

        newDiv.onclick = whatDiv;
        newDiv.onmouseover = RedLineOn;
        newDiv.onmouseout  = RedLineOff;

        divID = 'MyDiv' + newElementsAdded;
        newDiv.id = divID;

        newHTML = theelements[cnt].parentNode.replaceChild( newDiv,
theelements[cnt] );
        newDiv.appendChild( newHTML );

        newElementsAdded += 1;

      }

      alert( 'There were ' + newElementsAdded + ' new divs added' );

}



The other functions are:

function RedLineOn()
{
   this.style.border = '2px solid red'

    if (psMenuWindow.event.stopPropagation) {
             psMenuWindow.event.stopPropagation();
    } else {
            psMenuWindow.event.cancelBubble = true;
    }
}

function RedLineOff()
{
    this.style.border = 'none'

    if (psMenuWindow.event.stopPropagation) {
             psMenuWindow.event.stopPropagation();
    } else {
            psMenuWindow.event.cancelBubble = true;
    }

}


function  whatDiv()
{
        var divName = this.getAttribute("id");

  alert( ' this id name is ' + divName );
  alert( this.innerHTML );

    if (psMenuWindow.event.stopPropagation) {
             psMenuWindow.event.stopPropagation();
    } else {
            psMenuWindow.event.cancelBubble = true;
    }
}



I though it might be the event bubble and tried it with/without it to no
avail.

I am just running this against a simple test html page like this (and I am
activating it from the context menu of course)

<body>
<div>
<table border="2">
<tr>
<td>T1r1c1</td>
<td>T1r1c2</td>
<td>T1r1c3</td>
</tr>
<tr>
<td>T1r2c1</td>
<td>T1r2c2</td>
<td>T1r2c3</td>
</tr>
</table>

<br><br>
<h2 id="h2-1">Text in a div!</h2>

</div>
</body>


I've done some [searching] but am not finding any references as to why the
events would stop responding.

I see it happen with either a series of mouse on/offs, clicks or both.


Any ideas or suggestions are appreciated.

Thanks!


Chuck
FromMe
ToChuck Everson
SubjectRe: Using insertAdjacentHTML with window.external.menuArguments
Date14 April 2007 10:35
Chuck,

> Then they just stop responding and my page has to be refreshed before
> they work again.

I think this is because you define your event handlers inside the context
menu file. IE has several scoping issues with dependent pages like this, and
it does not carry the event handler functions into the target page.
Therefore when the invisible context menu page gets destroyed (because its
threads have finished, and the garbage collector mistakenly thinks they are
not being used any more) the event handlers disappear.

There is one way I managed to work out to create non-dependent functions
inside another page like this (it creates a timeout thread in the other
page, and evaluates code as a string, menaing that it adopts the scope of
the page it is running in, not the page that created it):

otherwindow.setTimeout(
  'var somefunction = function () { if(event.etc) { ... } }',
  10
);

But then, I am not sure how to attach this function as an event handler,
since it will not yet exist before you try to attach it to the elements you
are creating.
FromChuck Everson
ToMe
SubjectRe: Using insertAdjacentHTML with window.external.menuArguments
Date15 April 2007 18:19
Hi Tarquin,

Thanks for the reply.

> when the invisible context menu page gets destroyed [...] the event
> handlers disappear.

That makes perfect sense and I figured something like that was going on.

> otherwindow.setTimeout(

Interesting ...

I'll play around with the idea some and see if I can come up with anything.


Just a WAG - but I was wondering if another approach that might work would
be to copy the document into a string (in the context document), parse
through it and simply create a document on the fly - either adding elements,
etc. from the original one or adding the new ones in the places where they
go.

This would (hopefully) build a new HTML document with all the ducks in a row
and everything set, then just somehow swap that document back into place in
the parent.


Another thing I thought of was to construct the new document - then pass it
into a modal dialog window, let the event handlers run in the context of
that window and do what I wanted to do there.

I haven't tried that yet - so I don't know if that is just wishful thinking
or not<g>.


Let me know if either of these ideas possibly inspires something else in you
- or if you have any thoughts on it.

Thanks again for the help!

Chuck
FromMe
ToChuck Everson
SubjectRe: Using insertAdjacentHTML with window.external.menuArguments
Date21 April 2007 11:32
Chuck,

> copy the document into a string (in the context document), parse through
> it and simply create a document on the fly

This will pick up several problems, especially if it interacts with forms.
They do not have all their contents available through innerHTML. You can do
this, but expect it to break things all over the place :)

I would suggest you play with the evaluate-as-string thing I suggested
earlier. Perhaps it will work if you give the new elements a unique ID, and
add the event handler using that - use a simple counter to make sure each
one gets a unique ID:

n++;
the_new_div_you_created.id = 'chuckdiv'+n;
otherwindow.setTimeout(
  "document.getElementById('chuckdiv"+n+"').onclick = "+
  "function () { if(event.etc) { ... } }",
  10
);
FromChuck Everson
ToMe
SubjectRe: Using insertAdjacentHTML with window.external.menuArguments
Date22 April 2007 02:32
Hi Tarquin,

> This will pick up several problems, especially if it interacts with forms

Thanks for the heads up - I just ran across a page today where they were
talking about the forms issue.

> give the new elements a unique ID, and add the event handler using that

OK - will take a look at it that way.

I was already building the unique IDs as they were assigned.

The evaluate-as-string stuff seems to have some potential here.

Thanks again for your help!


Chuck
FromChuck Everson
ToMe
SubjectDetecting load completes
Date24 April 2007 22:50
Hi Tarquin,

I hope your having a good week!

Here is one that I am puzzling with a bit...

If you visit a page like [URL], you see that they are loading a ton of
SSI or other external documents in iFrames and from Javascript sources.

What I am trying to figure out is if there is a surefire way to detect when
ALL of these documents have been loaded so that my context menu code is not
"premature" in dealing with the page content.

I've been [searching] on it - but the results I am finding seem to all be
relative to issues not related to the code in the context menu.

Anyway - any ideas or suggestions are appreciated!

Chuck
FromChuck Everson
ToMe
SubjectDisplay popup from context menu
Date28 April 2007 21:41
Hi Tarquin,

Hope your having a good weekend!

Have you ever figured out a way to display a popup menu from a selection off
the IE context menu?

I've been playing around with it as a way to have multiple script options
without eating up all the space on the IE context menu.

I can do it with a call to ShowModalDialog and process a value returned from
a CSS popup in that window, but it is pretty messy to have to work with a
second html document to display in the ShowModalDialog window.


If you have any ideas on a better way to do this - I'd like to hear them.

Thanks!

Chuck
FromMe
ToChuck Everson
SubjectRe: Detecting load completes
Date1 May 2007 08:56
Chuck,

> What I am trying to figure out is if there is a surefire way to detect
> when ALL of these documents have been loaded so that my context menu code
> is not "premature" in dealing with the page content.

The onload event will only fire after the document and all those extra parts
has loaded. Of course, if it has already loaded, it can be hard to check for
it. IE has a non-standard property called document.readyState that should be
'complete' if the document has loaded, but there are some pages where it
fails to ever reach that state, and I am not sure if it waits for all
subframes first.
FromMe
ToChuck Everson
SubjectRe: Display popup from context menu
Date1 May 2007 09:05
Chuck,

> Have you ever figured out a way to display a popup menu from a selection
> off the IE context menu?

Apart from the messy approach of using window.open to create a popup, which
is what my frame tree script does...

The page you run your script in can display itself in a visible window. My
window resizer context menu script does this. All you have to do is set the
registry key:
[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\FooBar]
"Flags"=dword:00000001
FromChuck Everson
ToMe
SubjectRe: Display popup from context menu
Date1 May 2007 10:04
Hi Tarquin,

> The page you run your script in can display itself in a visible window.

Thanks - I'll take a look at that again.

I'd looked at it briefly when I first found your site but my head was in
other places then<g>.

Chuck
FromChuck Everson
ToMe
SubjectRe: Detecting load completes
Date1 May 2007 10:05
Hi Tarquin,

> IE has a non-standard property called document.readyState

Thanks - I'll look into that.

Chuck
FromChuck Everson
ToMe
SubjectDetect keypress with context item
Date17 May 2007 12:32
Hello Tarquin,

Here is a question for your:

Is it possible to detect that a key was pressed when an IE context menu item
was selected?

If so, then it seems that could work with a JS switch statement to allow you
to fire variations of the code (IOW - use a "G" and a menu selection to
search Google and a "Y" to search Yahoo.

While we're at it - if this can be done in the context script - what about
keys like ALT or CTRL (or combinations).


It seems like this should be able to be done (I know you can get it with
like a OnClick event) here was a link to an article on quirksmode

http://www.quirksmode.org/js/events_properties.html#key


Anyway - as usual I appreciate your insight.

Chuck
FromMe
ToChuck Everson
SubjectRe: Detect keypress with context item
Date17 May 2007 19:21
Chuck,

> Is it possible to detect that a key was pressed when an IE context menu
> item was selected?

Only the page itself (or a script running on it) can detect key presses. It
could, for example, use the oncontextmenu event to check the event.shiftKey
property to see if the shift key was being pressed when the context menu was
opened (not when the menu items were activated). However, this means that
you would need to have your script running on the page before the context
menu was opened. If you need to do this, you will have to install something
that allows you to write User JavaScripts that can run on every page you
visit, such as Turnabout Advanced:
http://www.reifysoft.com/turnabout.php
FromChuck Everson
ToMe
SubjectRe: Detect keypress with context item
Date18 May 2007 06:13
Hello Tarquin,

> Only the page itself (or a script running on it) can detect key presses.

OK - that is along the lines of what I was seeing.  However knowing that
sometimes the script around this context stuff gets a bit convoluted<g> I
wanted to see what you had to say on it.

> such as Turnabout Advanced

I've seen that around before (although it looks inactive for a couple of
years now).

Thanks again for the info.

Chuck
FromChuck Everson
ToMe
SubjectGetting a list of IDs
Date10 July 2007 23:55
Hi Tarquin,

I hope that the world is treating you well.  Sorry not to have chatted in a
bit.


I have what should be a simple task that is giving me fits today.

I'd like to traverse a chunk of HTML (selected by the user and passed to
window.external.menuArguments ) and get a list of all ID's that have a
specific string in the ID.

IOW - the IDs (stacked here for example) might be like:

id=MyTag1
id=MyTag2
id=MyTag3
id=MyTag4

The common element would be that each ID has "MyTag" (in this example).

I don't know that the IDs would only be different by number, so I can't just
build a tag ID and increment the number to look for it.

I only know that the first xxx chars of the tag ID would be the same - after
that it could be any combination of letters or numbers.

I'd like to get these into an array, then I can traverse the array and
manipulate the elements by ID.

I know that if it was a NAME instead of ID, that getElementsByName would
give me the array, but have yet to find a simple equivalent for
getElementByID to do what I want to do.

It seems like one should be able to do this without a full out brute force
parse.

Any ideas?

Thanks!

Chuck
FromMe
ToChuck Everson
SubjectRe: Getting a list of IDs
Date12 July 2007 09:24
Chuck,

> I'd like to traverse a chunk of HTML and get a list of all ID's that have
> a specific string in the ID.
> It seems like one should be able to do this without a full out brute force
> parse.

If the browser supports XPath, this is very easy (and fast) to do with a
single XPath query:

var oList = document.evaluate("//*[starts-with(@id,'MyTag')]",
 oElement,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);
var eachElement;
while( eachElement = oList.iterateNext() ) {
  ...
}

However, IE only supports XPath on XML documents, not HTML (other browsers
that support it - such as Opera and Firefox - support it in HTML as well).
So in IE, you will need to get all tags, and check them individually.

var oList = oElement.getElementsByTagName('*');
for( var i = 0; i < oList.length; i++ ) {
  if( oList[i].id.indexOf('MyTag') == 0 ) {
[Ed. I made a mistake in that last line, see below for correction]
    ...
  }
}
FromChuck Everson
ToMe
SubjectRe: Getting a list of IDs
Date12 July 2007 11:35
Hello Tarquin,

Thanks for the tip.

That looks like it can do pretty much what I want to do, but I noticed that
if there is no MyTag on the page that I get an error saying "The object
doesn't support this property or method".

Is there a test I can put in the code to eliminate the error in such a case?

The line where it seems to fail is:

if( oList[i].id.indexOf('MyTag') == 0 ) {


If I comment those lines out and run on the page without the tag starting
with that ID - it runs w/o errors, so that seems to be the point of failure.

Thanks again for your help!

Chuck
FromChuck Everson
ToMe
SubjectRe: Getting a list of IDs
Date12 July 2007 12:53
Hello Tarquin,

A bit more on this...

For this line:

if( oList[i].id.indexOf('MyTag') == 0 ) {

The test seems to be failing when "MyTag" was not set as the ID= - but
rather as the Name= for the HTML tag.

Since the string I am searching for could be either a id or a name, it looks
like it works if I wrap the code like this:

var oList = oElement.getElementsByTagName('*');
for( var i = 0; i < oList.length; i++ ) {

  // Test for string as id
  if (typeof oList[i].id == "string") {
    if( oList[i].id.indexOf('MyTag') == 0 ) {
      ...
    }
  }

  // Test for string as name
  if (typeof oList[i].name == "string") {
    if( oList[i].name.indexOf('MyTag') == 0 ) {
      ...
    }
  }

}


Does that seem like the right way to handle that?

Thanks!

Chuck
FromMe
ToChuck Everson
SubjectRe: Getting a list of IDs
Date12 July 2007 13:09
Chuck,

>   if( oList[i].id.indexOf('MyTag') == 0 ) {

sorry, that should have been:
if( oList[i].id && oList[i].id.indexOf('MyTag') == 0 ) {
FromChuck Everson
ToMe
SubjectRe: Getting a list of IDs
Date12 July 2007 13:17
Hi Tarquin,

>>   if( oList[i].id.indexOf('MyTag') == 0 ) {
>
> sorry, that should have been:
> if( oList[i].id && oList[i].id.indexOf('MyTag') == 0 ) {

LOL - no problem.

That actually helped me solve a problem I didn't even know I had (where the
string could appear as a name instead of or an id).

I appreciate the help and learned some more today<g>.

Thanks again!

Chuck
This site was created by Mark "Tarquin" Wilton-Jones.
Don't click this link unless you want to be banned from our site.