universal_html 1.2.1 copy "universal_html: ^1.2.1" to clipboard
universal_html: ^1.2.1 copied to clipboard

outdated

A 'dart:html' that works in all platforms, including Flutter and servers. Eases cross-platform development, web scraping, and other HTML / XML handling.

Pub Package Github Actions CI Build Status

Introduction #

Cross-platform dart:html that works in all platforms (browser, Dart VM, and Flutter).

The test suite is designed to verify that universal_html behaves identically to dart:html running in Chrome.

The project is licensed under the Apache License 2.0. Some of the source code was adopted from the original dart:html, which is documented in the relevant files.

Example use cases #

  • HTML or XML parsing and scraping
    • Parse and inspect HTML/XML.
    • Find HTML/XML elements with CSS queries (querySelectorAll).
    • Submit forms.
  • Generating HTML content
    • For example, web frameworks can generate HTML in the browser, command-line, and server-side.
  • EventSource

Similar projects #

Getting started #

1. Add dependency #

In pubspec.yaml:

dependencies:
  universal_html: ^1.2.1

Now you can replace usage of "dart:html" with "package:universal_html/html.dart".

2. Choose library #

import 'package:universal_html/html.dart';

This library exports dart:html by default. You can also use import 'package:universal_html/prefer_sdk/html.dart';.

If you use this library, Dart tools may mistakenly think that your package is not compatible with VM/Flutter.

Option 2 #

import 'package:universal_html/prefer_universal/html.dart';

This library exports our implementation by default. The main advantage of this library is easier debugging. If you click "Go to declaration" in your IDE, you will see the implementation.

Getting warnings? In some cases, when you mix universal_io classes with dart:html classes, your IDE produces type warnings ("universal_html Element is not dart:html Element"). Your application should still compile (in browser, universal_html classes will be dart:html classes).

Proposed future method #

Dart SDK feature request #37232 proposes that developers could supply missing dart:html in VM/Flutter in pubspec.yaml.

3. That's it! #

import "package:universal_html/html.dart";

void main() {
  // Create a DOM tree
  final divElement = new DivElement();
  divElement.append(new Element.tag("h1")
    ..classes.add("greeting")
    ..appendText("Hello world!"));

  // Print outer HTML
  print(divElement.outerHtml);
  // --> <div><h1>Hello world</h1></div>

  // Do a CSS query
  print(divElement.querySelector("div > .greeting").text);
  // --> Hello world
}

Manual #

Parsing HTML / XML #

We recommend that you use package:universal_html/parsing.dart (instead of DomParser):

import 'package:universal_html/parsing.dart';

void main() {
  // HTML
  final htmlDocument = parseHtmlDocument('<html>...</html>');

  // XML
  final xmlDocument = parseXmlDocument('<xml>...</xml>');
}

Server-side rendering #

The package comes with ServerSideRenderer, which is a web server for rendering your web application in the server-side.

import 'package:universal_html/driver.dart';
import 'package:universal_html/html.dart';

void main() {
  final renderer = new ServerSideRenderer(webAppMain);
  renderer.bind("localhost", 12345);
}

void webAppMain() {
  document.body.appendText("Hello world!");
}

Creating and using browser simulators #

import 'package:universal_html/driver.dart';
import 'package:universal_html/html.dart';

Future main() async {
  // Construct a driver
  final driver = new HtmlDriver(userAgent:"My Hacker News bot");
  
  // Load a document.
  await driver.setDocumentFromUri(Uri.parse("https://news.ycombinator.com/"));
  
  // Select top story
  final topStoryTitle = driver.document.querySelectorAll(".athing > .title").first.text;
  print("Top Hacker News story is: ${topStoryTitle}");
}

Implemented APIs #

List of differences #

DIFFERENCES.md contains an automatically generated list of dart:html APIs that are not yet declared by this package yet.

HTML #

  • Document nodes
    • All core classes (Node, Element, etc.)
    • All HtmlElement subclasses (AnchorElement, ResetButtonElement, etc.)
    • Most class members. For example, anchorElement.href returns the resolved URI. Only a few class members are still missing (see DIFFERENCES.md).
  • DOM parsing
    • You can parse HTML/XML with innerHtml/outerHtml setters and DomParser
    • HTML parsing uses package:html
    • CSS parsing uses package:csslib
    • XML parsing uses our own parser.
  • DOM printing
    • element.innerHtml, element.outerHtml
  • DOM events
    • For example, element.onClick.listen(...) receives invocation of element.click().

CSS #

  • Much of the CSS classes (CssStyleDeclaration, etc.)
  • CSS queries
    • Methods element.querySelector(..), element.querySelectorAll(..), element.matchesSelector(..)
    • Element name (table)
    • Element ID (#id)
    • Element class (.classA.classB)
    • Combinators:
      • element.class#id
      • s0 s1 s2
      • s0 s1 s2
      • s0 > s1 > s2
      • s0 ~ s1 ~ s2
      • s0 + s1 + s2
    • Pseudoselectors:
      • :disabled
      • :first-child
      • :last-child
      • :not(x)
      • :nth-child(5)
      • :nth-child(even)
      • :nth-child(3n+1)
      • :only-child
      • :root
    • Attribute selectors:
      • [name]
      • [name=value]
      • [name~=value]
      • [name|=value]
      • [name^=value]
      • [name$=value]
      • [name*=value]

Layout #

Currently, the library does not attempt to calculate layout for the elements.

Every DOM element has a private field RenderData, which you can get with BrowserImplementationUtils.getRenderData(...)). When a property such as element.offset is called, the RenderData instance is responsible for evaluating the answer. The default implementation generally returns 0. If you want to implement layout engine, you can override BrowserImplementation.newRenderData(element).

Networking #

  • Form submitting
    • Implemented and tested, but doesn't support all encodings yet.
    • Ways to use:
      • formElement.submit()
      • submitButtonElement.click()
  • HttpRequest (XMLHttpRequest)
    • Implemented and tested.
  • EventSource ("application/event-stream" client)
    • Implemented and tested.

Currently, networking classes don't implement same-origin policies, CORS, and other security specifications. We hope to fix this in future.

  • locale
  • All APIs are declared

Window #

  • console
  • history
    • back(...), pushState(...), etc.
  • location
    • origin, href, etc.
  • localStorage / sessionStorage
    • Implemented and tested.
    • Stores values in the heap.
  • All APIs are declared.

Other SDK libraries #

We wrote mock implementation of the following SDK libraries:

  • dart:indexed_db
  • dart:js
  • dart:js_util
  • dart:svg
  • dart:web_gl

Any attempt to use these APIs will throw UnimplementedException. The libraries are available in:

  • package:universal_html/(libraryName).dart
  • package:universal_html/prefer_sdk/(libraryName).dart
  • package:universal_html/prefer_universal/(libraryName).dart
431
likes
0
pub points
99%
popularity

Publisher

verified publisherdint.dev

A 'dart:html' that works in all platforms, including Flutter and servers. Eases cross-platform development, web scraping, and other HTML / XML handling.

Repository (GitHub)
View/report issues

License

unknown (LICENSE)

Dependencies

async, charcode, collection, csslib, html, meta, typed_data, universal_io, zone_local

More

Packages that depend on universal_html