Code Monkey home page Code Monkey logo

basichtml's Introduction

basicHTML

Coverage Status Build Status License: ISC

📣 Announcement

Be aware there is a shiny new module called LinkeDOM which is completely different, but better than basicHTML, at pretty much everything.

All modules of mine are going to use linkedom instead, and basicHTML will be soon deprecated or put in maintainance mode.

Feel free to read the related post to know more about this decision.


A NodeJS based, standard oriented, HTML implementation.

viperHTML logo

Breaking V2 Changes

As the canvas module brought in ~100MB of dependency, and as it's not even a common use case, I've decided to move the canvas package into devDependencies, so that you need to explicitly include it when you use basicHTML.

npm i basichtml canvas

By default, no canvas module will be installed at all.

New in v1

Introduced optional node-canvas dependency behind the <canvas> and <img> scene 🦄

  • automatic fallback if the canvas module doesn't build
  • provide canvas 2d API, with the ability to create real images
  • provide the node-canvas Image ability to react on load and error events
const {Image, document} = require('basichtml').init({});

const canvas = document.createElement('canvas');
canvas.width = 320;
canvas.height = 200;

const ctx = canvas.getContext('2d');
ctx.moveTo(0, 0);
ctx.lineTo(320, 200);
ctx.stroke();

const img = new Image();
img.onload = () => {
  console.log(img.outerHTML);
};
img.src = canvas.toDataURL();

New in 0.23

Custom Elements built-in extends are finally supported 🎉

customElements.define('my-special-thing', MySpecialThing, {extends: 'div'});
document.createElement('div', {is: 'my-special-thing'});

New init(...) in 0.13

// easy way, introduced in 0.13
// pollutes by default the global with:
//  - window
//  - document
//  - customElements
//  - HTMLElement
// if a non global window is provided
// it will use it as defaultView
require('basichtml').init({
  // all properties are optional
  window: global,
  // in case you'd like to share a predefined
  // registry of Custom Elements
  customElements,
  // specify a different selector
  selector: {
    // use the module sizzle, it will be required
    // automatically
    name: 'sizzle',
    // or alternatively, use a module function
    module() {
      return require('sizzle');
    },
    // how to retrieve results => querySelectorAll
    $(Sizzle, element, css) {
      return Sizzle(css, element);
    }
  }
});
// returns the window itself

Good old way to init with basic selectors

const {Document} = require('basichtml');

const document = new Document();

// attributes
document.documentElement.setAttribute('lang', 'en');

// common accessors
document.documentElement.innerHTML = `
  <head></head>
  <body></body>
`;
document.body.textContent = 'Hello basicHTML';

// basic querySelector / querySelectorAll
document.querySelector('head').appendChild(
  document.createElement('title')
).textContent = 'HTML on NodeJS';

// toString() necessary to read, it's a Buffer
console.log(document.toString());

Above log will produce an output like the following one.

<!DOCTYPE html>
<html lang="en">
  <head><title>HTML on NodeJS</title></head>
  <body>Hello basicHTML</body>
</html>

Features

  • create any amount of documents
  • document fragments, comments, text nodes, and elements
  • elements have classList and dataset too
  • Event and CustomEvent through add/removeEventListener and dispatchEvent
  • DOM Level 0 compatible events
  • Attributes compatible with Custom Elements reactions
  • arbitrary Custom Elements creation
  • customizable selector engine

Current caveats / exceptions

  • since v0.2, the property nodeName is case-sensitive to make basicHTML compatible with XML projects too
  • el.querySelectorAll(css) works with tagName, #id, or .className. You can use more complex selectors including 3rd party libraries such Sizzle, as shown in this test example.
  • el.querySelector(css) is not optimized and will return just index 0 of the whole collection. However, selecting a lot is not the goal of this library.
  • el.getElementsByTagName as well as el.getElementsByClassName and el.getElementsById are all available. The latter is the fastest one of the trio.
  • all collections are basically just arrays. You should use official DOM methods to mutate them. As example, do not ever childNodes.push(new Node) 'cause that's not what you could do on the DOM. The whole point here is to provide a Web like env, not to write defensive code for NodeJS or other non strictly Web environments.
  • most historical properties and standards are most likely not implemented

License

ISC License

Copyright (c) 2017, Andrea Giammarchi, @WebReflection

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

What is this about?

This is an essential implementation of most common HTML operations without the necessary bloat brought in by the entire HTML specification.

The ideal scenario is together with hyperHTML to be able to create DOM trees and objects capable of being updated, refreshed, related to any native component.

The perfect scenario would be to drive NativeScript components using a CustomElementRegistry like you would do on the Web for Custom Elements.

Please bear in mind this project is not aiming to become a fully standard compliant implementation of the whole WebIDL based specifications, there are other projects for that.

basichtml's People

Contributors

bigopon avatar coreyfarrell avatar greenkeeper[bot] avatar kal-aster avatar richardkazuomiller avatar sheepfromheaven avatar webreflection avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

basichtml's Issues

Support insertAdjacentElement

It seems like basicHTML doesn't support insertAdjacentElement at the moment, as it returns document.body.insertAdjacentElement is not a function.

Add support for replaceWith()

This is the doc from MDN:

The ChildNode.replaceWith() method replaces this ChildNode in the children list of its parent with a set of Node or DOMString objects. DOMString objects are inserted as equivalent Text nodes.

There is a polyfill in MDN page.

In the meantime, it should be possible to use replaceChild() on the parent node.

Enable external selectors library

Usable selectors are very few in core and more than once users asked for more complex selectors.

The use case is using basicHTML for testing and code-covering purposes, where complex selectors might be actually useful.

Find a way to pass along querySelector and querySelectorAll engine through the ParentNode interface.

shadowDOM

Since basicHTML supports a customElements registry it might make sense for it to implement Shadow DOM as well.

Simply implementing HTMLElement.attachShadow wouldn't be too tough for a first pass but making it fully spec compliant might be a more work.

What are your thoughts on this?

Implementing attachShadow

Hi, do you think that is possible to implement the attachShadow method to support the ShadowDOM functionality?
I would like to help with that, but i'm not quite sure of how to do it.
Do you think it is a good contribution? And if so have any ideia about how it could be done?

Thanks
Hugo

style.cloneNode() fails

without a value, every attempt to access cssText on a cloned style would fail.

TODO

  • expose ownerElement so it can be modified at distance for cloned styles
  • ensure styles always have a value that is a style declaration

An in-range update of hyperhtml is breaking the build 🚨

Version 2.0.4 of hyperhtml was just published.

Branch Build failing 🚨
Dependency hyperhtml
Current Version 2.0.3
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

hyperhtml is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push The Travis CI build could not complete due to an error Details

Commits

The new version differs by 2 commits.

  • 81ef4da 2.0.4
  • bfd78c4 Resetting fastPath when mixed content is passed as value.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

disconnectedCallback is not invoked

I found that disconnectedCallback() doesn't get invoked when removing a custom element from the DOM.

To be honest, I don't really know what behaviour should I expect here:

  • diffing document.innerHTML when it changes, calling disconnectedCallbacks of those elements which were removed
  • having a functionality to reset/destroy a document, which resets document.innerHTML and calls the disconnectedCallbacks of each rendered elements

Does basichtml have any support for this? (instead of doing document.body.innerHTML = '';)

const { init, HTMLElement } = require('basichtml');
const { customElements, document } = init();

customElements.define('test-component', class TestComponent extends HTMLElement {
    connectedCallback() {
        console.log('connected');
        this.interval = setInterval(() => console.log('tick'), 1000);
    }

    disconnectedCallback() {
        console.log('disconnected');
        clearInterval(this.interval);
    }
});

document.body.innerHTML = '<body><test-component /></body>';
console.log(document.toString());
document.body.innerHTML = '';

// keeping the process alive
process.stdin.on('data', () => {});

As a result of not calling disconnectedCallback, the setInterval() created in connectedCallback keeps ticking in every second.

Console output:

connected
<!DOCTYPE html><html><body><body><test-component></test-component></body></body></html>
tick
tick
tick

(Please forgive me opening issues, there are rather questions than actual issues. I'm just getting familiar with basichtml, which looks awesome as your other projects (e.g. heresy <3))

Version 10 of node.js has been released

Version 10 of Node.js (code name Dubnium) has been released! 🎊

To see what happens to your code in Node.js 10, Greenkeeper has created a branch with the following changes:

  • Added the new Node.js version to your .travis.yml

If you’re interested in upgrading this repo to Node.js 10, you can open a PR with these changes. Please note that this issue is just intended as a friendly reminder and the PR as a possible starting point for getting your code running on Node.js 10.

More information on this issue

Greenkeeper has checked the engines key in any package.json file, the .nvmrc file, and the .travis.yml file, if present.

  • engines was only updated if it defined a single version, not a range.
  • .nvmrc was updated to Node.js 10
  • .travis.yml was only changed if there was a root-level node_js that didn’t already include Node.js 10, such as node or lts/*. In this case, the new version was appended to the list. We didn’t touch job or matrix configurations because these tend to be quite specific and complex, and it’s difficult to infer what the intentions were.

For many simpler .travis.yml configurations, this PR should suffice as-is, but depending on what you’re doing it may require additional work or may not be applicable at all. We’re also aware that you may have good reasons to not update to Node.js 10, which is why this was sent as an issue and not a pull request. Feel free to delete it without comment, I’m a humble robot and won’t feel rejected 🤖


FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Problems with nodeName

While testing with basichtml i found that nodeName of the elements are reported with lower-case while the browsers (as far as i know) reports them as uppercase, is that something you can fix?

If there are some browsers that reports them as lower case i may have to update my code then :D

Text and Comment classes should implement `ChildNode` interface?

I found this while using basichtml for some testing. Minimal failing test case:

const assert = require('assert');
const {body} = require('basichtml').init().document;

body.innerHTML = 'Text<!--comment-->';
[...body.childNodes].forEach(node => node.remove());
assert.strictEqual(body.innerHTML, '');

This throws TypeError: node.remove is not a function where I expected the test to silently succeed. I realize the whatwg standard doesn't show Text or Comment implementing ChildNode but https://developer.mozilla.org/en-US/docs/Web/API/CharacterData#Browser_compatibility shows that CharacterData implements ChildNode in most browsers.

Issue with not self-closing <void-element> tag

If I run this script in the test/ folder:

const { Document } = require("../basichtml.js");
const document = new Document();
document.documentElement.innerHTML =
  "start <img> ghost1 <img/> ghost2 <img/> end";
console.log(document.toString());

I get this result:

<!DOCTYPE html><html>start <img /><img /> ghost2 <img /> end</html>

ghost1 disappeared.

It looks like it's because the first is not self-closing.

window.addEventListener is not a function

basicHTML does not define addEventListener or removeEventListener for the window object.
What I tried to do:

window.addEventListener("some-custom-event", console.log.bind(console));

Expected Behavior:

  • Register an event handler that logs "some-custom-event" events to console.

Actual:
TypeError: window.addEventListener is not a function

Broken inline CSS custom properties

Hi, when I take the example "Good old way to init with basic selectors" from the README and add an inline custom property to the body element (with style="--foo: bar"), it is transformed in the output, with the two dashes transformed into one only.

Script:

const { Document } = require("basichtml");

const document = new Document();

// attributes
document.documentElement.setAttribute("lang", "en");

// common accessors
document.documentElement.innerHTML = `
  <head></head>
  <body style="--foo: bar"></body>
`;
document.body.textContent = "Hello basicHTML";

// basic querySelector / querySelectorAll
document
  .querySelector("head")
  .appendChild(document.createElement("title")).textContent = "HTML on NodeJS";

// toString() necessary to read, it's a Buffer
console.log(document.toString());

Output:

<!DOCTYPE html><html lang="en">
  <head><title>HTML on NodeJS</title></head>
  <body style="-foo:bar;">Hello basicHTML</body>
</html>

style="--foo: bar" is transformed into style="-foo:bar;".

Implement NamedNodeMap?

Would you consider a PR implementing NamedNodeMap interface in the Element class? Or at least exposing the item method?

Currently, the project I'm working in makes a call to element.attributes.item and fails when the element is created using basicHTML 😢

dispatchEvent does not return a boolean for cancelable events

with basicHTML EventTarget.dispatchEvent does not return a boolean for cancelable events.

What I tried to do:

const div = document.createElement("div");
if( !div.dispatchEvent(new CustomEvent("some-event", {cancelable: true})) )
  console.log("Event was canceled!");

Expected Behavior:

  • no console output since the event wasn't canceled

Actual:

  • "Event was canceled!" in console

Use Case:
I am unit testing a webcomponent library with multiple decorators, one of them being the property decorator @Event. This decorator populates the property on first access with a bound event emitter. This emitter provides a method emit. This method takes a detail object as an argument and returns the result of dispatchEvent. To properly unit test this functionality, dispatchEvent has to return a boolean if a cancelable event has been canceled.

Workaround:
My current workaround is to create the event, emit it and check if it returned a boolean, if it did not, it will check the defaultPrevented property afterwards.

Refactor `querySelectorAll` per `document`

Currently, the init with a selector method causes a global side effect on every selector, playing not particularly nice when Document class is extracted, and initialized, a part.

Consider providing a Document.prototype.useSelector(...) method to simplify, and confine, different selectors engine, per document.

few differences from actual browser API

once again thanks for the awesome work!

More and more I use basicHTML, I really like it, especially it enabled me to write and run tests for customElements, for which I use to struggle a lot with JSDOM earlier.

Since basichtml goal is not necessarily to be 100% same as browser DOM api, not sure if this needs to be considered as enhancement or bug, you can close this, if you think it's a overkill, I'm just logging my findings.

To make tests run and return same results in actual browser, noted below differences:

  1. Element.tagName should always return upperCase() to match with browser API, ex: img > IMG.

I'm overriding for now with below.

Object.defineProperties(Element.prototype, {
    tagName: {
        get() {
            return this.nodeName.toUpperCase();
        }
    }
});
  1. may be it's HTML parser used in basichtml doing this, but void elements are being converted into XHTML instead of HTML5, ex: <img src="image.png" alt="alt text" /> where as actual browser returns <img src="image.png" alt="alt text">
  2. TIOLI, native attributes that are converted into properties on the element are not available ex: 'src', 'href' etc. I can extend by adding get/set onElement.prototype but getAttribute works for now without needing to do this.

Custom element properties are not accessible

I'm experimenting with basicHTML to render custom elements with SSR and I'm facing with an issue. Probably I'm doing something wrong, so I made this simplified code for demonstration:

const { init, HTMLElement } = require('basichtml');
const { customElements, document } = init();

customElements.define('test-component', class TestComponent extends HTMLElement {
    connectedCallback() {
        this.innerHTML = `Hello ${this.getAttribute('greet')}!`;
    }
});

document.body.innerHTML = '<body><test-component greet="David"></test-component></body>';

console.log(document.toString());

The output is:

<!DOCTYPE html><html><body><test-component greet="David">Hello null!</test-component></body></html>

While I'm expecting this (running in a browser the output matches this):

<!DOCTYPE html><html><body><test-component greet="David">Hello David!</test-component></body></html>

Can somebody please tell me what am I doing wrong?

requestAnimationFrame not found

I am trying to use the library to set up a fake DOM into node but I would need requestAnimationFrame. Would that be possible to integrate?

An in-range update of coveralls is breaking the build 🚨


☝️ Important announcement: Greenkeeper will be saying goodbye 👋 and passing the torch to Snyk on June 3rd, 2020! Find out how to migrate to Snyk and more at greenkeeper.io


The devDependency coveralls was updated from 3.0.11 to 3.0.12.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

coveralls is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push: The Travis CI build failed (Details).

Commits

The new version differs by 3 commits.

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Implement cloneNode

Latest hyperHTML refactoring uses cloneNode to duplicate templateObjects fragment once.

Consider supporting at least fragments cloneNode, but proper any node implementation would be good too.

Improvement suggestion: make sizzle default selector engine?

@WebReflection: Thanks for the update 0.13.1 with init()
at least now I don't need to patch window, document and CustomElements.
however, it's still not great user experience in my opinion and below are few suggestions, may TIOLI.

  • I'm sure most devs use webpack, where dynamic import/require is not allowed so can't use the option you have provided. Not sure if rollup compiler allows dynamic require though.
  • since we know query selector from basicHTML doesn't cover most of the CSS selectors, why not make sizzle as default engine and also allow users to override if needed.
  • It would be useful to add HTMLElement also to the global by default, since major focus of basicHTML is to support custom elements, what you think?

this is what I still need to do with current implementation.

const { init, HTMLElement, Element }  = require('basichtml');

init();
global.HTMLElement = HTMLElement;

// override selector with sizzle engine
const Sizzle = require('sizzle');
Element.prototype.querySelectorAll = function (css) {
  return Sizzle(css, this);
};

I have forked and made a change here is the commit, let me know your thoughts, I can create pull request if you're ok with this change. I know you want this to be extensible with any selector engine but making this simplified to use will be a big win.

Regression in v2.3.0: duplicate <html><html>…</html></html>

I'm loading full HTML documents in BasicHTML, with DOCTYPE and <html>, and it used to work properly up to v2.2.9

Now, in v2.3.0, document.toString() gives me a duplicate <html><html>…</html></html>.

Sample script:

const basicHTML = require('basichtml');
const { document } = basicHTML.init();

const html = "<!DOCTYPE html><html><body><p>Hello</p></body></html>";
document.documentElement.innerHTML = html;
console.dir(document.toString());

Outputs this in v2.2.9:
<!DOCTYPE html><html><body><p>Hello</p></body></html>

Outputs this in v2.3.0:
<!DOCTYPE html><html><html><body><p>Hello</p></body></html></html>

canvas.getContext() not working when canvas created with basicHTML.

I was trying to implement this:

var canvas;
    if (options.inBrowser) {
      canvas = document.querySelector(selector);
    }
    else {
      const { Document } = require('basichtml');
      const document = new Document();
      // common accessors
      document.documentElement.innerHTML = `
        <canvas id='image-sequencer-canvas'></canvas>
      `;
      canvas = document.querySelector('#image-sequencer-canvas');
    }

and then

var gl;
gl = canvas.getContext(names[i], { preserveDrawingBuffer: true });

but gl always turns out to be undefined.
Please help.
@WebReflection

An in-range update of hyperhtml is breaking the build 🚨

Version 2.10.1 of hyperhtml was just published.

Branch Build failing 🚨
Dependency hyperhtml
Current Version 2.10.0
Type devDependency

This version is covered by your current version range and after updating it in your project the build failed.

hyperhtml is a devDependency of this project. It might not break your production code or affect downstream projects, but probably breaks your build or test tools, which may prevent deploying or publishing.

Status Details
  • continuous-integration/travis-ci/push The Travis CI build could not complete due to an error Details

Commits

The new version differs by 4 commits.

  • 242dadf 2.10.1
  • eb09e76 fixed #230 and umd.js file
  • 78aeb3f Merge pull request #226 from WebReflection/greenkeeper/uglify-js-3.3.22
  • a799032 chore(package): update uglify-js to version 3.3.22

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.