add new <:Document> meta-component

pull/1024/head
Rich Harris 7 years ago
parent 7c86487691
commit e57ddb0503

@ -727,6 +727,9 @@ export default class Generator {
} else if (node.name === ':Window') { // TODO do this in parse?
node.type = 'Window';
node.__proto__ = nodes.Window.prototype;
} else if (node.name === ':Document') { // TODO do this in parse?
node.type = 'Document';
node.__proto__ = nodes.Document.prototype;
} else if (node.type === 'Element' && node.name === 'slot' && !generator.customElement) {
node.type = 'Slot';
node.__proto__ = nodes.Slot.prototype;

@ -203,7 +203,7 @@ export default class Block {
this.builders.hydrate.addLine(`this.first = ${this.first};`);
}
if (this.builders.create.isEmpty()) {
if (this.builders.create.isEmpty() && this.builders.hydrate.isEmpty()) {
properties.addBlock(`c: @noop,`);
} else {
properties.addBlock(deindent`
@ -215,7 +215,7 @@ export default class Block {
}
if (this.generator.hydratable) {
if (this.builders.claim.isEmpty()) {
if (this.builders.claim.isEmpty() && this.builders.hydrate.isEmpty()) {
properties.addBlock(`l: @noop,`);
} else {
properties.addBlock(deindent`

@ -77,10 +77,7 @@ export default class Attribute {
? '@setXlinkAttribute'
: '@setAttribute';
const isDynamic =
(this.value !== true && this.value.length > 1) ||
(this.value.length === 1 && this.value[0].type !== 'Text');
const isDynamic = this.isDynamic();
const isLegacyInputType = this.generator.legacy && name === 'type' && this.parent.name === 'input';
const isDataSet = /^data-/.test(name) && !this.generator.legacy && !node.namespace;
@ -310,6 +307,12 @@ export default class Attribute {
);
});
}
isDynamic() {
if (this.value === true || this.value.length === 0) return false;
if (this.value.length > 1) return true;
return this.value[0].type !== 'Text';
}
}
// source: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes

@ -0,0 +1,34 @@
import deindent from '../../utils/deindent';
import { stringify } from '../../utils/stringify';
import Node from './shared/Node';
import Block from '../dom/Block';
import Attribute from './Attribute';
const readonly = new Set([
'innerWidth',
'innerHeight',
'outerWidth',
'outerHeight',
'online',
]);
export default class Document extends Node {
type: 'Document';
attributes: Attribute[];
build(
block: Block,
parentNode: string,
parentNodes: string
) {
const { generator } = this;
this.var = 'document';
this.attributes.forEach((attribute: Attribute) => {
if (attribute.name === 'title') {
attribute.render(block);
}
});
}
}

@ -5,6 +5,7 @@ import Binding from './Binding';
import CatchBlock from './CatchBlock';
import Comment from './Comment';
import Component from './Component';
import Document from './Document';
import EachBlock from './EachBlock';
import Element from './Element';
import ElseBlock from './ElseBlock';
@ -28,6 +29,7 @@ const nodes: Record<string, any> = {
CatchBlock,
Comment,
Component,
Document,
EachBlock,
Element,
ElseBlock,

@ -17,9 +17,10 @@ const validTagName = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/;
const SELF = ':Self';
const COMPONENT = ':Component';
const metaTags = {
':Window': true
};
const metaTags = new Set([
':Window',
':Document'
]);
const specials = new Map([
[
@ -86,7 +87,7 @@ export default function tag(parser: Parser) {
const name = readTagName(parser);
if (name in metaTags) {
if (metaTags.has(name)) {
if (name in parser.metaTags) {
if (isClosingTag && parser.current().children.length) {
parser.error(
@ -252,7 +253,7 @@ function readTagName(parser: Parser) {
const name = parser.readUntil(/(\s|\/|>)/);
if (name in metaTags) return name;
if (metaTags.has(name)) return name;
if (!validTagName.test(name)) {
parser.error(`Expected valid tag name`, start);

@ -1,12 +1,16 @@
import validateElement from './validateElement';
import validateWindow from './validateWindow';
import validateDocument from './validateDocument';
import a11y from './a11y';
import fuzzymatch from '../utils/fuzzymatch'
import flattenReference from '../../utils/flattenReference';
import { Validator } from '../index';
import { Node } from '../../interfaces';
const meta = new Map([[':Window', validateWindow]]);
const meta = new Map([
[':Window', validateWindow],
[':Document', validateDocument]
]);
export default function validateHtml(validator: Validator, html: Node) {
const refs = new Map();

@ -0,0 +1,42 @@
import flattenReference from '../../utils/flattenReference';
import fuzzymatch from '../utils/fuzzymatch';
import list from '../../utils/list';
import validateEventHandler from './validateEventHandler';
import { Validator } from '../index';
import { Node } from '../../interfaces';
const descriptions = {
Bindings: 'two-way bindings',
EventHandler: 'event handlers',
Transition: 'transitions',
Ref: 'refs'
};
export default function validateWindow(validator: Validator, node: Node, refs: Map<string, Node[]>, refCallees: Node[]) {
node.attributes.forEach((attribute: Node) => {
if (attribute.type === 'Attribute') {
if (attribute.name !== 'title') {
validator.error(
`<:Document> can only have a 'title' attribute`,
attribute.start
);
}
}
else {
const description = descriptions[attribute.type];
if (description) {
validator.error(
`<:Document> does not support ${description}`,
attribute.start
);
} else {
// future-proofing
validator.error(
`<:Document> can only have a 'title' attribute`,
attribute.start
);
}
}
});
}

@ -0,0 +1,12 @@
export default {
data: {
adjective: 'custom'
},
test(assert, component, target, window) {
assert.equal(window.document.title, 'a custom title');
component.set({ adjective: 'different' });
assert.equal(window.document.title, 'a different title');
}
};

@ -0,0 +1 @@
<:Document title='a {{adjective}} title'/>

@ -0,0 +1,5 @@
export default {
test(assert, component, target, window) {
assert.equal(window.document.title, 'changed');
}
};
Loading…
Cancel
Save