Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #38415 > unrolled thread

HTML5 embed element event

Started byAndrew Poulos <ap_prog@hotmail.com>
First post2020-05-19 16:39 +1000
Last post2020-05-23 03:06 +0200
Articles 18 — 5 participants

Back to article view | Back to comp.lang.javascript


Contents

  HTML5 embed element event Andrew Poulos <ap_prog@hotmail.com> - 2020-05-19 16:39 +1000
    Re: HTML5 embed element event "Evertjan." <exxjxw.hannivoort@inter.nl.net> - 2020-05-19 17:29 +0200
      Re: HTML5 embed element event Andrew Poulos <ap_prog@hotmail.com> - 2020-05-20 07:45 +1000
        Re: HTML5 embed element event "Evertjan." <exxjxw.hannivoort@inter.nl.net> - 2020-05-20 00:21 +0200
          Re: HTML5 embed element event rcpj@panix.com (Pierre Jelenc) - 2020-05-20 01:09 +0000
            Re: HTML5 embed element event Andrew Poulos <ap_prog@hotmail.com> - 2020-05-20 18:36 +1000
            Re: HTML5 embed element event "Evertjan." <exxjxw.hannivoort@inter.nl.net> - 2020-05-20 12:36 +0200
    Re: HTML5 embed element event "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2020-05-19 17:21 -0700
      Re: HTML5 embed element event Andrew Poulos <ap_prog@hotmail.com> - 2020-05-20 18:43 +1000
    Re: HTML5 embed element event Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2020-05-21 17:15 +0200
      Re: HTML5 embed element event "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2020-05-21 08:55 -0700
        Re: HTML5 embed element event "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2020-05-21 08:57 -0700
          Re: HTML5 embed element event Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2020-05-21 18:53 +0200
            Re: HTML5 embed element event "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2020-05-21 11:00 -0700
              Re: HTML5 embed element event Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2020-05-21 21:50 +0200
                Re: HTML5 embed element event Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2020-05-21 22:03 +0200
                Re: HTML5 embed element event "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2020-05-21 15:25 -0700
                  Re: HTML5 embed element event Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2020-05-23 03:06 +0200

#38415 — HTML5 embed element event

FromAndrew Poulos <ap_prog@hotmail.com>
Date2020-05-19 16:39 +1000
SubjectHTML5 embed element event
Message-ID<H9idncZ8Oaal4l7DnZ2dnUU7-XHNnZ2d@westnet.com.au>
I have a HTML5 page which includes this

<embed id="pdf" src="sample.pdf" type="application/pdf" title="Sample">

CSS positions and sizes the element.

What I need to do is to know when a user has selected it eg clicked it 
with a mouse. While Dr Google suggests that embed elements support 
events it may just be media events because I can't get it to respond to 
a click event. How can the parent window know when an embed has been 
clicked?

Andrew Poulos

[toc] | [next] | [standalone]


#38418

From"Evertjan." <exxjxw.hannivoort@inter.nl.net>
Date2020-05-19 17:29 +0200
Message-ID<XnsABC2B1F64AD18eejj99@194.109.6.166>
In reply to#38415
Andrew Poulos <ap_prog@hotmail.com> wrote on 19 May 2020 in 
comp.lang.javascript:

> I have a HTML5 page which includes this
> 
> <embed id="pdf" src="sample.pdf" type="application/pdf" title="Sample">
> 
> CSS positions and sizes the element.
> 
> What I need to do is to know when a user has selected it eg clicked it 
> with a mouse. While Dr Google suggests that embed elements support 
> events it may just be media events because I can't get it to respond to 
> a click event. How can the parent window know when an embed has been 
> clicked?

You can set a transparent div in front of it,
and do an onclick on tha.
You will lose the ability to select text in the embedded page.

<style>
  div {position:relative;width:300px;height:200px;border:2px black solid;}
  embed {background:#eef;}
  embed, div div {position:absolute;width:300px;height:200px;border:0;}
</style>

<div>
<embed src="test.txt">
<div onclick='alert("clicked");'></div>
</div>

-- 
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)

[toc] | [prev] | [next] | [standalone]


#38419

FromAndrew Poulos <ap_prog@hotmail.com>
Date2020-05-20 07:45 +1000
Message-ID<ztOdnaMNU77zzlnDnZ2dnUU7-aednZ2d@westnet.com.au>
In reply to#38418
On 20/05/2020 1:29 am, Evertjan. wrote:
> Andrew Poulos <ap_prog@hotmail.com> wrote on 19 May 2020 in
> comp.lang.javascript:
> 
>> I have a HTML5 page which includes this
>>
>> <embed id="pdf" src="sample.pdf" type="application/pdf" title="Sample">
>>
>> CSS positions and sizes the element.
>>
>> What I need to do is to know when a user has selected it eg clicked it
>> with a mouse. While Dr Google suggests that embed elements support
>> events it may just be media events because I can't get it to respond to
>> a click event. How can the parent window know when an embed has been
>> clicked?
> 
> You can set a transparent div in front of it,
> and do an onclick on tha.
> You will lose the ability to select text in the embedded page.
> 
> <style>
>    div {position:relative;width:300px;height:200px;border:2px black solid;}
>    embed {background:#eef;}
>    embed, div div {position:absolute;width:300px;height:200px;border:0;}
> </style>
> 
> <div>
> <embed src="test.txt">
> <div onclick='alert("clicked");'></div>
> </div>

It's nice idea but as it's a PDF I'd expect users to want to interact 
with it.

Andrew Poulos

[toc] | [prev] | [next] | [standalone]


#38420

From"Evertjan." <exxjxw.hannivoort@inter.nl.net>
Date2020-05-20 00:21 +0200
Message-ID<XnsABC33B2115C9eejj99@194.109.6.166>
In reply to#38419
Andrew Poulos <ap_prog@hotmail.com> wrote on 19 May 2020 in
comp.lang.javascript: 

> On 20/05/2020 1:29 am, Evertjan. wrote:
>> Andrew Poulos <ap_prog@hotmail.com> wrote on 19 May 2020 in
>> comp.lang.javascript:
>> 
>>> I have a HTML5 page which includes this
>>>
>>> <embed id="pdf" src="sample.pdf" type="application/pdf"
>>> title="Sample"> 
>>>
>>> CSS positions and sizes the element.
>>>
>>> What I need to do is to know when a user has selected it eg clicked it
>>> with a mouse. While Dr Google suggests that embed elements support
>>> events it may just be media events because I can't get it to respond
>>> to a click event. How can the parent window know when an embed has
>>> been clicked?
>> 
>> You can set a transparent div in front of it,
>> and do an onclick on tha.
>> You will lose the ability to select text in the embedded page.
>> 
>> <style>
>>    div {position:relative;width:300px;height:200px;border:2px black
>>    solid;} embed {background:#eef;}
>>    embed, div div
>>    {position:absolute;width:300px;height:200px;border:0;} 
>> </style>
>> 
>> <div>
>> <embed src="test.txt">
>> <div onclick='alert("clicked");'></div>
>> </div>
> 
> It's nice idea but as it's a PDF I'd expect users to want to interact 
> with it.

Your expectations are irreal.

You can't have it both ways, detecting a mouseclick, 
and having mouseclicks going on to the pdf.
 
> Andrew Poulos
> 



-- 
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)

[toc] | [prev] | [next] | [standalone]


#38422

Fromrcpj@panix.com (Pierre Jelenc)
Date2020-05-20 01:09 +0000
Message-ID<ra2007$rjp$1@reader1.panix.com>
In reply to#38420
In article <XnsABC33B2115C9eejj99@194.109.6.166>,
Evertjan. <exxjxw.hannivoort@inter.nl.net> wrote:
>Andrew Poulos <ap_prog@hotmail.com> wrote on 19 May 2020 in
>comp.lang.javascript: 
>
>> On 20/05/2020 1:29 am, Evertjan. wrote:
>>> Andrew Poulos <ap_prog@hotmail.com> wrote on 19 May 2020 in
>>> comp.lang.javascript:
>>> 
>>>> I have a HTML5 page which includes this
>>>>
>>>> <embed id="pdf" src="sample.pdf" type="application/pdf"
>>>> title="Sample"> 
>>>>
>>>> CSS positions and sizes the element.
>>>>
>>>> What I need to do is to know when a user has selected it eg clicked it
>>>> with a mouse. While Dr Google suggests that embed elements support
>>>> events it may just be media events because I can't get it to respond
>>>> to a click event. How can the parent window know when an embed has
>>>> been clicked?
>>> 
>>> You can set a transparent div in front of it,
>>> and do an onclick on tha.
>>> You will lose the ability to select text in the embedded page.
>>> 
>>> <style>
>>>    div {position:relative;width:300px;height:200px;border:2px black
>>>    solid;} embed {background:#eef;}
>>>    embed, div div
>>>    {position:absolute;width:300px;height:200px;border:0;} 
>>> </style>
>>> 
>>> <div>
>>> <embed src="test.txt">
>>> <div onclick='alert("clicked");'></div>
>>> </div>
>> 
>> It's nice idea but as it's a PDF I'd expect users to want to interact 
>> with it.
>
>Your expectations are irreal.
>
>You can't have it both ways, detecting a mouseclick, 
>and having mouseclicks going on to the pdf.

How about if you detect the click that way, and trigger a script that 
pushes the transparent div to a negative z-index? Then (if it works) use 
onblur() to bring the div back to the front. (Completely untried...)

Pierre
-- 
Pierre Jelenc	
		The Gigometer		www.gigometer.com
                The NYC Beer Guide      www.nycbeer.org

[toc] | [prev] | [next] | [standalone]


#38423

FromAndrew Poulos <ap_prog@hotmail.com>
Date2020-05-20 18:36 +1000
Message-ID<TqWdnXnqmeiBcVnDnZ2dnUU7-QfNnZ2d@westnet.com.au>
In reply to#38422
On 20/05/2020 11:09 am, Pierre Jelenc wrote:
> In article <XnsABC33B2115C9eejj99@194.109.6.166>,
> Evertjan. <exxjxw.hannivoort@inter.nl.net> wrote:
>> Andrew Poulos <ap_prog@hotmail.com> wrote on 19 May 2020 in
>> comp.lang.javascript:
>>
>>> On 20/05/2020 1:29 am, Evertjan. wrote:
>>>> Andrew Poulos <ap_prog@hotmail.com> wrote on 19 May 2020 in
>>>> comp.lang.javascript:
>>>>
>>>>> I have a HTML5 page which includes this
>>>>>
>>>>> <embed id="pdf" src="sample.pdf" type="application/pdf"
>>>>> title="Sample">
>>>>>
>>>>> CSS positions and sizes the element.
>>>>>
>>>>> What I need to do is to know when a user has selected it eg clicked it
>>>>> with a mouse. While Dr Google suggests that embed elements support
>>>>> events it may just be media events because I can't get it to respond
>>>>> to a click event. How can the parent window know when an embed has
>>>>> been clicked?
>>>>
>>>> You can set a transparent div in front of it,
>>>> and do an onclick on tha.
>>>> You will lose the ability to select text in the embedded page.
>>>>
>>>> <style>
>>>>     div {position:relative;width:300px;height:200px;border:2px black
>>>>     solid;} embed {background:#eef;}
>>>>     embed, div div
>>>>     {position:absolute;width:300px;height:200px;border:0;}
>>>> </style>
>>>>
>>>> <div>
>>>> <embed src="test.txt">
>>>> <div onclick='alert("clicked");'></div>
>>>> </div>

> How about if you detect the click that way, and trigger a script that
> pushes the transparent div to a negative z-index? Then (if it works) use
> onblur() to bring the div back to the front. (Completely untried...)

In my testing the embed doesn't trigger onfocus or onblur but I could 
try returning the div to positive when the window gets focus.

Andrew Poulos

[toc] | [prev] | [next] | [standalone]


#38425

From"Evertjan." <exxjxw.hannivoort@inter.nl.net>
Date2020-05-20 12:36 +0200
Message-ID<XnsABC3802D3A6eejj99@194.109.6.166>
In reply to#38422
rcpj@panix.com (Pierre Jelenc) wrote on 20 May 2020 in comp.lang.javascript:

>>>> <style>
>>>>    div {position:relative;width:300px;height:200px;border:2px black
>>>>    solid;} embed {background:#eef;}
>>>>    embed, div div
>>>>    {position:absolute;width:300px;height:200px;border:0;} 
>>>> </style>
>>>> 
>>>> <div>
>>>> <embed src="test.txt">
>>>> <div onclick='alert("clicked");'></div>
>>>> </div>
>>> 
>>> It's nice idea but as it's a PDF I'd expect users to want to interact 
>>> with it.
>>
>>Your expectations are irreal.
>>
>>You can't have it both ways, detecting a mouseclick, 
>>and having mouseclicks going on to the pdf.
> 
> How about if you detect the click that way, and trigger a script that 
> pushes the transparent div to a negative z-index? Then (if it works) use 
> onblur() to bring the div back to the front. (Completely untried...)

You can toggle CSS style 'pointer-events:none|all;' 
to have all mouse-events fall through the top-element:

==========================================
<style>
  * {box-sizing: border-box;}
  span {color:#f00;}

  container, divTop, divBot {display:block;width:300px;height:200px;}
  container {position:relative;border:2px black solid;}
  divTop, divBot {position:absolute;margin:10%;}
</style>

<script>
const qs = (s) => document.querySelector(s);

const fallTrough = (x) => {
	const X = qs(x);
	X.style.pointerEvents = 
		(X.style.pointerEvents == 'none')
		? 'auto'
		: 'none';
	X.innerHTML = '<br><br>Top {pointer-events: ' + X.style.pointerEvents 
+'}';
};

const show = (y) => {
	qs('span').innerHTML = 'div' + y + ' clicked';
	setTimeout('qs("span").innerHTML = "---"',1000);
};
</script>


<container>
<divBot onclick='show("bottom");'>Bottom</divBot>
<divTop onclick='show("top");'><br><br>Top {pointer-events: auto}</divTop>
</container>
<br><br>
<button onclick='fallTrough("divTop")'>Toggle</button>
<span>---</span>
==========================================

-- 
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)

[toc] | [prev] | [next] | [standalone]


#38421

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2020-05-19 17:21 -0700
Message-ID<e49275dd-289f-48a5-a233-381f09602541@googlegroups.com>
In reply to#38415
On Tuesday, May 19, 2020 at 1:40:02 AM UTC-5, Andrew Poulos wrote:
> I have a HTML5 page which includes this
> 
> <embed id="pdf" src="sample.pdf" type="application/pdf" title="Sample">
> 
> CSS positions and sizes the element.
> 
> What I need to do is to know when a user has selected it eg clicked it 
> with a mouse. While Dr Google suggests that embed elements support 
> events it may just be media events because I can't get it to respond to 
> a click event. How can the parent window know when an embed has been 
> clicked?

Does it have to be an <embed/> element? Can you use an <iframe/>?

This was a bit tricky, but I figure out how to do it:

```
<div class="click-wrapper">
    <iframe src="sample.pdf" width="640" height="480"></iframe>
</div>
<script>
    let qs = (sel, ctx) => (ctx || document).querySelector(sel),
        clickWrapper = qs('.click-wrapper'),
        iframe = qs('iframe', clickWrapper)
    iframe.style.pointerEvents = 'none'
    clickWrapper.addEventListener('click', () => {
        console.log('iframe clicked')
        iframe.style.pointerEvents = 'auto'
        iframe.focus()
    })
    document.addEventListener('click', (e) => {
        if(![clickWrapper, iframe].includes(e.target)) {
            console.log('iframe blurred')
            iframe.style.pointerEvents = 'none'
        }
    })
</script>
```

Basically you wrap the iframe with another element like Evertjan suggested and add the event listener to that element.

The iframe intercepts events though which is the problem you described, and they don't get propagated to the parent window including the wrapping element unless you happened to click on the border of the element. So Evertjan's solution is incomplete.

You can override this behavior with the css property `pointer-events: none`. This allows the wrapping element to receive the click event. onlick it will then re-enable click events and focus the iframe so the users can interact with the pdf normally.

By adding a global click listener to the document you can re-enable the original state and capture another click event.

This is imperfect, but hopefully closer to what you're looking for

[toc] | [prev] | [next] | [standalone]


#38424

FromAndrew Poulos <ap_prog@hotmail.com>
Date2020-05-20 18:43 +1000
Message-ID<a5GdneU5eZxZcFnDnZ2dnUU7-dHNnZ2d@westnet.com.au>
In reply to#38421
On 20/05/2020 10:21 am, Michael Haufe (TNO) wrote:
> On Tuesday, May 19, 2020 at 1:40:02 AM UTC-5, Andrew Poulos wrote:
>> I have a HTML5 page which includes this
>>
>> <embed id="pdf" src="sample.pdf" type="application/pdf" title="Sample">
>>
>> CSS positions and sizes the element.
>>
>> What I need to do is to know when a user has selected it eg clicked it
>> with a mouse. While Dr Google suggests that embed elements support
>> events it may just be media events because I can't get it to respond to
>> a click event. How can the parent window know when an embed has been
>> clicked?
> 
> Does it have to be an <embed/> element? Can you use an <iframe/>?
> 
> This was a bit tricky, but I figure out how to do it:
> 
> ```
> <div class="click-wrapper">
>      <iframe src="sample.pdf" width="640" height="480"></iframe>
> </div>
> <script>
>      let qs = (sel, ctx) => (ctx || document).querySelector(sel),
>          clickWrapper = qs('.click-wrapper'),
>          iframe = qs('iframe', clickWrapper)
>      iframe.style.pointerEvents = 'none'
>      clickWrapper.addEventListener('click', () => {
>          console.log('iframe clicked')
>          iframe.style.pointerEvents = 'auto'
>          iframe.focus()
>      })
>      document.addEventListener('click', (e) => {
>          if(![clickWrapper, iframe].includes(e.target)) {
>              console.log('iframe blurred')
>              iframe.style.pointerEvents = 'none'
>          }
>      })
> </script>
> ```
> 
> Basically you wrap the iframe with another element like Evertjan suggested and add the event listener to that element.
> 
> The iframe intercepts events though which is the problem you described, and they don't get propagated to the parent window including the wrapping element unless you happened to click on the border of the element. So Evertjan's solution is incomplete.
> 
> You can override this behavior with the css property `pointer-events: none`. This allows the wrapping element to receive the click event. onlick it will then re-enable click events and focus the iframe so the users can interact with the pdf normally.
> 
> By adding a global click listener to the document you can re-enable the original state and capture another click event.
> 
> This is imperfect, but hopefully closer to what you're looking for

I tested it and though you "lose" the first click on the PDF it looks 
pretty close to what I'm looking for. Thanks for the code and the 
explanation.

Andrew Poulos

[toc] | [prev] | [next] | [standalone]


#38430

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2020-05-21 17:15 +0200
Message-ID<4588804.31r3eYUQgx@PointedEars.de>
In reply to#38415
Andrew Poulos wrote:

> I have a HTML5 page which includes this
> 
> <embed id="pdf" src="sample.pdf" type="application/pdf" title="Sample">
> 
> CSS positions and sizes the element.
> 
> What I need to do is to know when a user has selected it eg clicked it
> with a mouse. While Dr Google suggests that embed elements support
> events it may just be media events because I can't get it to respond to
> a click event. How can the parent window know when an embed has been
> clicked?

Click events are handled by the application that displays the content, as it 
was before HTML5; in this case either the PDF viewer provided by the browser 
itself or probably the Adobe Reader plugin.  So you would have to learn and 
use Adobe JavaScript in order to handle those.

However, in 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like 
Gecko) Chrome/73.0.3683.75 Safari/537.36' which includes a PDF viewer, a 
FocusEvent is fired if an “embed” element like above, that has loaded a PDF 
document, is clicked.

You can find out which events are fired by an element by handling all 
possible events:


function getAllPropertyNames (obj)
{
  /* Object instead of Array to avoid duplicates automatically */
  let properties = {};

  do {
    Object.getOwnPropertyNames(obj)
      .forEach(name => {properties[name] = true});
  } while ((obj = Object.getPrototypeOf(obj)));

  return Object.keys(properties);
}

/* $0 in the Chrome Dev Console refers to the currently selected element 
node in the Tree Pane */
var el = $0;

getAllPropertyNames(el).filter(name => name.indexOf('on') === 0)
  .forEach(name => {
    el[name] = ((ev) => { console.log(ev); });
  });



-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#38431

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2020-05-21 08:55 -0700
Message-ID<510316de-79da-42b4-8502-ce21d07bacdc@googlegroups.com>
In reply to#38430
On Thursday, May 21, 2020 at 10:16:02 AM UTC-5, Thomas 'PointedEars' Lahn wrote:
> 
> function getAllPropertyNames (obj)
> {
>   /* Object instead of Array to avoid duplicates automatically */
>   let properties = {};
> 
>   do {
>     Object.getOwnPropertyNames(obj)
>       .forEach(name => {properties[name] = true});
>   } while ((obj = Object.getPrototypeOf(obj)));
> 
>   return Object.keys(properties);
> }
> 
> /* $0 in the Chrome Dev Console refers to the currently selected element 
> node in the Tree Pane */
> var el = $0;
> 
> getAllPropertyNames(el).filter(name => name.indexOf('on') === 0)
>   .forEach(name => {
>     el[name] = ((ev) => { console.log(ev); });
>   });

In case you were unaware, a Set[1] object is generally available now:

```
let featureNames = (obj: object): Set<PropertyKey> =>
  obj == null ? new Set() :
    new Set([
      ...Object.getOwnPropertyNames(obj),
      ...featureNames(Object.getPrototypeOf(obj))
    ])
```

[1] <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set>

[toc] | [prev] | [next] | [standalone]


#38432

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2020-05-21 08:57 -0700
Message-ID<12dbcf64-ebca-4c3d-adc7-26ad1246ca63@googlegroups.com>
In reply to#38431
On Thursday, May 21, 2020 at 10:55:14 AM UTC-5, Michael Haufe (TNO) wrote:

> ```
> let featureNames = (obj: object): Set<PropertyKey> =>
>   obj == null ? new Set() :
>     new Set([
>       ...Object.getOwnPropertyNames(obj),
>       ...featureNames(Object.getPrototypeOf(obj))
>     ])
> ```

oops, I forgot to mention that was in TypeScript. JavaScript:

```
let featureNames = (obj) =>
  obj == null ? new Set() :
    new Set([
      ...Object.getOwnPropertyNames(obj),
      ...featureNames(Object.getPrototypeOf(obj))
    ])
```

[toc] | [prev] | [next] | [standalone]


#38433

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2020-05-21 18:53 +0200
Message-ID<4261657.LvFx2qVVIh@PointedEars.de>
In reply to#38432
Michael Haufe (TNO) wrote:

> On Thursday, May 21, 2020 at 10:55:14 AM UTC-5, Michael Haufe (TNO) wrote:
>> ```
>> let featureNames = (obj: object): Set<PropertyKey> =>
>>   obj == null ? new Set() :
>>     new Set([
>>       ...Object.getOwnPropertyNames(obj),
>>       ...featureNames(Object.getPrototypeOf(obj))
>>     ])
>> ```
> 
> oops, I forgot to mention that was in TypeScript. JavaScript:
> 
> ```
> let featureNames = (obj) =>
>   obj == null ? new Set() :
>     new Set([
>       ...Object.getOwnPropertyNames(obj),
>       ...featureNames(Object.getPrototypeOf(obj))
>     ])
> ```

I forgot about Set.  I do not know what you mean by “featureNames”, or why 
you would pass a reference to a two-element Array.

The following would be equivalent to my original suggestion if one would 
write

  var properties = Object.create(null);

there instead:


function getAllPropertyNames (obj)
{
  /* Object instead of Array to avoid duplicates automatically */
  let properties = new Set();

  do {
    Object.getOwnPropertyNames(obj)
      .forEach(name => {set.add(name)});
  } while ((obj = Object.getPrototypeOf(obj)));

  return Array.from(properties.keys());
}

/* $0 in the Chrome Dev Console refers to the currently selected element 
node in the Tree Pane */
var el = $0;

getAllPropertyNames(el).filter(name => name.indexOf('on') === 0)
  .forEach(name => {
    el[name] = ((ev) => { console.log(ev); });
  });

ISTM that the advantage that Set provides in this case is too small.

-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#38434

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2020-05-21 11:00 -0700
Message-ID<61275749-9018-4baf-a633-6de74dceedd3@googlegroups.com>
In reply to#38433
On Thursday, May 21, 2020 at 11:53:31 AM UTC-5, Thomas 'PointedEars' Lahn wrote:
> 
> I forgot about Set.  I do not know what you mean by “featureNames”, 

Sorry, that was a copy/paste issue from other code I'm working on which focuses on classes instead of objects. A 'feature' in the context of a class is a property, a method, or an accessor. This terminology is seen in compiler work and in some literature such as: 

"Feature-Oriented Programming with Object Algebras"
<https://www.cs.utexas.edu/~wcook/Drafts/2012/FOPwOA.pdf>

> or why you would pass a reference to a two-element Array.

The constructor of Set accepts an iterable so you can do:

new Set([1,2,3])

Therefore in a single expression in declarative fashion we can define a set which contains all of the current property names, and all of the ancestor property names. To iterate is human, to recurse is divine.
 
> The following would be equivalent to my original suggestion if one would 
> write
> 
>   var properties = Object.create(null);
> 
> there instead:
> 
> 
> function getAllPropertyNames (obj)
> {
>   /* Object instead of Array to avoid duplicates automatically */
>   let properties = new Set();
> 
>   do {
>     Object.getOwnPropertyNames(obj)
>       .forEach(name => {set.add(name)});
>   } while ((obj = Object.getPrototypeOf(obj)));
> 
>   return Array.from(properties.keys());
> }
> 
> /* $0 in the Chrome Dev Console refers to the currently selected element 
> node in the Tree Pane */
> var el = $0;
> 
> getAllPropertyNames(el).filter(name => name.indexOf('on') === 0)
>   .forEach(name => {
>     el[name] = ((ev) => { console.log(ev); });
>   });
> 
> ISTM that the advantage that Set provides in this case is too small.


Using the Set approach:

```
let propertyNames = obj =>
  obj == null ? new Set() :
    new Set([
      ...Object.getOwnPropertyNames(obj),
      ...featureNames(Object.getPrototypeOf(obj))
    ])

var el = $0;

[...propertyNames(el)]
  .filter(name => name.startsWith('on'))
  .forEach(name => el[name] = ev => console.log(ev));
```

[toc] | [prev] | [next] | [standalone]


#38435

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2020-05-21 21:50 +0200
Message-ID<3049967.y3JZ3UGTbG@PointedEars.de>
In reply to#38434
Michael Haufe (TNO) wrote:

> On Thursday, May 21, 2020 at 11:53:31 AM UTC-5, Thomas 'PointedEars' Lahn
> wrote:
>> I forgot about Set.  I do not know what you mean by “featureNames”,
> 
> Sorry, that was a copy/paste issue from other code I'm working on which
> focuses on classes instead of objects. A 'feature' in the context of a
> class is a property, a method, or an accessor. This terminology is seen in
> compiler work and in some literature such as:
> 
> "Feature-Oriented Programming with Object Algebras"
> <https://www.cs.utexas.edu/~wcook/Drafts/2012/FOPwOA.pdf>

As I mentioned recently, I have been using the term “feature” in my code for 
ages[tm] :)
 
>> or why you would pass a reference to a two-element Array.

I see now that actually you are NOT doing that.  The new meaning of “...” in 
ECMAScript just has not entered my subconscious yet.

For the interested, unaware reader: “...” is not an omission (Perls are 
warned now), but works *like* an *operator* now (ECMAScript 2015+), such 
that

  [...['foo', 'bar'], ...['baz', 'bla']]

is now equivalent to

  ['foo', 'bar', 'baz', 'bla']

which is most useful if ['foo', 'bar'] and ['baz', 'bla'] are return values.  
Array.prototype.concat(), Array.prototype.push(), and simple uses of 
Function.prototype.call() and Function.prototype.apply() are thus rendered 
unnecessary.

  a.concat('foo', 'bar')       → [...a, ...['foo', 'bar']]
  a.push('foo', 'bar')         → a = [...a, ...['foo', 'bar']]
  o.f.call(o, 'foo', 'bar')    → o.f(...['foo', 'bar'])
  o.f.apply(o, ['foo', 'bar']) → o.f(...['foo', 'bar'])

Which means we can also finally write something like

  var input = '2020-05-21';
  new Date(...input.split('-').map((comp, i) => (i == 1 ? comp - 1 : comp)))

without a workaround.
 
> The constructor of Set accepts an iterable so you can do:
> 
> new Set([1,2,3])
> 
> Therefore in a single expression in declarative fashion we can define a
> set which contains all of the current property names, and all of the
> ancestor property names. To iterate is human, to recurse is divine.

I see.  Nice line :)

> Using the Set approach:
> 
> ```
> let propertyNames = obj =>
>   obj == null ? new Set() :
>     new Set([
>       ...Object.getOwnPropertyNames(obj),
>       ...featureNames(Object.getPrototypeOf(obj))

That would be ...propertyNames(…) here, I suppose.

>     ])
> 
> var el = $0;
> 
> [...propertyNames(el)]

IOW, now for simple cases .forEach(…) is rendered unnecessary, too? :-o

>   .filter(name => name.startsWith('on'))
                         ^^^^^^^^^^
Another "new" feature that had not entered my subconscious yet.

>   .forEach(name => el[name] = ev => console.log(ev));

For me, a readable code style requires at least braces around both function 
bodies here, as they are *statements*, not expressions.  (If they were more 
complex expressions, I would put them in parentheses instead; see above.)

-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail. 

[toc] | [prev] | [next] | [standalone]


#38436

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2020-05-21 22:03 +0200
Message-ID<2423838.kYtruNp0W4@PointedEars.de>
In reply to#38435
Thomas 'PointedEars' Lahn wrote:

> Michael Haufe (TNO) wrote:
>> [...propertyNames(el)]
> 
> IOW, now for simple cases .forEach(…) is rendered unnecessary, too? :-o

It is not, but simple cases of Array.from(…) appear to be, as 
propertyNames() is returning a reference to a Set.
 
>>   .filter(name => name.startsWith('on'))

-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#38437

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2020-05-21 15:25 -0700
Message-ID<11f17cae-beb1-46ff-8827-e0daa24487fa@googlegroups.com>
In reply to#38435
On Thursday, May 21, 2020 at 2:51:01 PM UTC-5, Thomas 'PointedEars' Lahn wrote:

> As I mentioned recently, I have been using the term “feature” in my code for 
> ages[tm] :)

Which is not necessarily incompatible:

<https://en.wikipedia.org/wiki/Feature-oriented_programming>

Part of my undergraduate research was in this area.
"Managing the Evolution of Software Product Lines"
<https://thenewobjective.com/publications>

> > To iterate is human, to recurse is divine.
> 
> I see.  Nice line :)

Credit to L. Peter Deutsch
<https://en.wikipedia.org/wiki/L._Peter_Deutsch>

> > [...propertyNames(el)]
> 
> IOW, now for simple cases .forEach(…) is rendered unnecessary, too? :-o

In simple cases where you don't need to filter you don't need an array. Set.prototype.forEach() exists

It's a shame that something like iterator expressions were never standardized:
<https://developer.mozilla.org/en-US/docs/Archive/Web/JavaScript/Array_comprehensions>

If they were then:

```
[...propertyNames(el)]
  .filter(name => name.startsWith('on'))
```

might become:

```
[...propertyNames(el); name => name.startsWith('on')]
```

But that's wishful thinking.

[toc] | [prev] | [next] | [standalone]


#38438

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2020-05-23 03:06 +0200
Message-ID<2769722.njXs8T4uTo@PointedEars.de>
In reply to#38437
Michael Haufe (TNO) wrote:

> On Thursday, May 21, 2020 at 2:51:01 PM UTC-5, Thomas 'PointedEars' Lahn
> wrote:
>> As I mentioned recently, I have been using the term “feature” in my code
>> for ages[tm] :)
> 
> Which is not necessarily incompatible:

You are missing the point.  I was pointing out that I have been using
the term “feature” precisely in that way, by jsx.object.getFeature().
 
>> > [...propertyNames(el)]
>> 
>> IOW, now for simple cases .forEach(…) is rendered unnecessary, too? :-o
> 
> In simple cases where you don't need to filter you don't need an array.
> Set.prototype.forEach() exists

That is beside the point.  See my correction.

-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.javascript


csiph-web