简体   繁体   中英

Custom HTML Element Extending the <script> Element?

The customary <script type="text/template"> tag for client-side processing isn't sufficient for my purposes because it isn't nestable . So I'm trying to extend it to work around this limitation.

Basically I have some raw html with embedded images that I want to parse the content client-side using javascript. I like the script tag because images inside it are not loaded by the browser. But when the html contains script tags, they break my application. Here's how I'm trying to extend the tag:

    <script>
        var scriptData = document.registerElement('script-data', {
            prototype: HTMLScriptElement.prototype
        });
        captureStart();
    </script>

When executed, chrome throws the following error:

Uncaught NotSupportedError: Failed to execute 'registerElement' on 'Document': Registration failed for type 'script-data'. The prototype is already in-use as an interface prototype object. 

Update:

Disputing my intentions or suggesting alternative methods is fine, however I still want an answer to my initial question: how does one extend the script tag?

How I'm using this is actually more complicated. I'm basically using this to "capture" the whole body of my HTML document, so that I can manipulate things before they are displayed. It's unconventional, I know. But I'm exploring it as a type of academic study.

The benefits to this approach include:

  • The html validates
  • The code is light-weight, and I hope better supported than solutions like mobify.js
  • I am able to modify content before the browser loads image resources

The challenges to this approach include:

  • The body of the document can have 3rd party modules/widgets with script tags or html comments.
  • I can't escape inline script tags. They need to remain in-tact because browsers with javascript disabled will display the document normally.

My proposed solution to these problems:

  • Extending the prototype of the script tag would allow me to use a custom tag that I know will never appear in other components.

Here's a larger sample of the code:

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Script Test</title>
        <style>
            html, body {
                margin: 0;
                padding: 0;
            }
        </style>
        <script>document.write("<script type='text/html' id='text-html'>");</script>
    </head>
    <body>
        <img src="http://placehold.it/600x400" alt="" width="600" height="400"/>
    </body>
</html>
<!--</script>
<script>
    var content = document.getElementById("text-html");
    document.write(content.innerHTML);
    content.parentNode.removeChild(content);
</script>-->

Short answer: Use Object.create() for the prototype object. The following code allows you to extend the script element, and represents the way document.registerElement() is meant to be used.

var scriptData = document.registerElement('script-data', {
    prototype: Object.create(HTMLScriptElement.prototype);
});

Long answer

Consider this variation on your original code:

var scriptDataProto = HTMLScriptElement.prototype;
// The next statement throws a DOMException of type "NotSupportedError".
var scriptData = document.registerElement('script-data', {
    prototype: scriptDataProto
});

The source of the exception is illustrated here:

scriptDataProto === HTMLScriptElement.prototype; // true

You're providing a reference to HTMLScriptElement.prototype , meaning that you want to use the exact same prototype for the custom script element you're creating. It's not very well documented yet, but the prototype you provide can't be a reference to any of the built-in HTML[*]Element prototypes; you have to provide a new prototype object.

If you want to inherit from the <script> tag's prototype, then you have to create a new prototype object that inherits from HTMLScriptElement.prototype by using Object.create() .

var scriptDataProto = Object.create(HTMLScriptElement.prototype);
scriptDataProto === HTMLScriptElement.prototype; // false

If you'd like, you can then add new members to this prototype without affecting the base HTMLScriptElement.prototype .

scriptDataProto.foo = function() {
    alert('Hello world!');
};
var scriptData = document.registerElement('script-data', {
    prototype: scriptDataProto
});
var element = new scriptData();
element.foo(); // alerts "Hello world!"
document.body.appendChild(element);
element.onclick = element.foo;

For further reading, HTML5 Rocks has a well-written article that really helped me understand how custom elements work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM