diff --git a/.travis.yml b/.travis.yml index 0383d47c81ec..de91162ece95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ node_js: env: global: - - BUILD_TIMEOUT=10000 + - BUILD_TIMEOUT=20000 addons: apt: diff --git a/CHANGELOG.md b/CHANGELOG.md index f9c18fafd1bd..5ccd6be70457 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Svelte changelog +## 2.13.1 + +* Coerce second argument to `toggleClass` ([#1685](https://github.com/sveltejs/svelte/issues/1685)) + +## 2.13.0 + +* Add `class` directive ([#890](https://github.com/sveltejs/svelte/issues/890)) +* Remove sourcemaps from npm package ([#1690](https://github.com/sveltejs/svelte/pull/1690)) + +## 2.12.1 + +* Allow actions to take any expression ([#1676](https://github.com/sveltejs/svelte/issues/1676)) +* Run transitions in component context ([#1675](https://github.com/sveltejs/svelte/issues/1675)) +* Correctly set select value on mount ([#1666](https://github.com/sveltejs/svelte/issues/1666)) +* Support `{@debug}` in SSR ([#1659](https://github.com/sveltejs/svelte/issues/1659)) +* Don't treat ` ` as empty whitespace ([#1658](https://github.com/sveltejs/svelte/issues/1658)) +* Fix outros for if blocks with no else ([#1688](https://github.com/sveltejs/svelte/pull/1688)) +* Set `style.cssText` in spread attributes ([#1684](https://github.com/sveltejs/svelte/pull/1684)) + + ## 2.12.0 * Initialise actions on mount rather than hydrate ([#1653](https://github.com/sveltejs/svelte/pull/1653)) diff --git a/package.json b/package.json index 8bd1fc7b08f9..b245b1f88ed4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "2.12.0", + "version": "2.13.1", "description": "The magical disappearing UI framework", "main": "compiler/svelte.js", "bin": { @@ -8,8 +8,8 @@ }, "files": [ "cli", - "compiler", - "ssr", + "compiler/*.js", + "ssr/*.js", "shared.js", "store.js", "store.umd.js", diff --git a/src/compile/nodes/Attribute.ts b/src/compile/nodes/Attribute.ts index 0165dc98fb81..b0c26c534d8f 100644 --- a/src/compile/nodes/Attribute.ts +++ b/src/compile/nodes/Attribute.ts @@ -210,7 +210,7 @@ export default class Attribute extends Node { } `; - block.builders.hydrate.addBlock(deindent` + block.builders.mount.addBlock(deindent` ${last} = ${value}; ${updater} `); diff --git a/src/compile/nodes/Class.ts b/src/compile/nodes/Class.ts new file mode 100644 index 000000000000..965cf7ea0d71 --- /dev/null +++ b/src/compile/nodes/Class.ts @@ -0,0 +1,18 @@ +import Node from './shared/Node'; +import Expression from './shared/Expression'; + +export default class Class extends Node { + type: 'Class'; + name: string; + expression: Expression; + + constructor(compiler, parent, scope, info) { + super(compiler, parent, scope, info); + + this.name = info.name; + + this.expression = info.expression + ? new Expression(compiler, this, scope, info.expression) + : null; + } +} \ No newline at end of file diff --git a/src/compile/nodes/DebugTag.ts b/src/compile/nodes/DebugTag.ts index e70d6a33a2fb..b73208961a15 100644 --- a/src/compile/nodes/DebugTag.ts +++ b/src/compile/nodes/DebugTag.ts @@ -4,6 +4,7 @@ import Block from '../dom/Block'; import Expression from './shared/Expression'; import deindent from '../../utils/deindent'; import addToSet from '../../utils/addToSet'; +import { stringify } from '../../utils/stringify'; export default class DebugTag extends Node { expressions: Expression[]; @@ -25,8 +26,8 @@ export default class DebugTag extends Node { const { code } = this.compiler; - // Debug all if (this.expressions.length === 0) { + // Debug all code.overwrite(this.start + 1, this.start + 7, 'debugger', { storeName: true }); @@ -67,4 +68,22 @@ export default class DebugTag extends Node { `); } } + + ssr() { + if (!this.compiler.options.dev) return; + + const filename = this.compiler.file || null; + const { line, column } = this.compiler.locate(this.start + 1); + + const obj = this.expressions.length === 0 + ? `ctx` + : `{ ${this.expressions + .map(e => e.node.name) + .map(name => `${name}: ctx.${name}`) + .join(', ')} }`; + + const str = '${@debug(' + `${filename && stringify(filename)}, ${line}, ${column}, ${obj})}`; + + this.compiler.target.append(str); + } } \ No newline at end of file diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts index 43e690bfd71c..bee1103dc09c 100644 --- a/src/compile/nodes/Element.ts +++ b/src/compile/nodes/Element.ts @@ -15,6 +15,7 @@ import EventHandler from './EventHandler'; import Transition from './Transition'; import Animation from './Animation'; import Action from './Action'; +import Class from './Class'; import Text from './Text'; import * as namespaces from '../../utils/namespaces'; import mapChildren from './shared/mapChildren'; @@ -68,6 +69,8 @@ export default class Element extends Node { attributes: Attribute[]; actions: Action[]; bindings: Binding[]; + classes: Class[]; + classDependencies: string[]; handlers: EventHandler[]; intro?: Transition; outro?: Transition; @@ -90,6 +93,8 @@ export default class Element extends Node { this.attributes = []; this.actions = []; this.bindings = []; + this.classes = []; + this.classDependencies = []; this.handlers = []; this.intro = null; @@ -144,6 +149,10 @@ export default class Element extends Node { this.bindings.push(new Binding(compiler, this, scope, node)); break; + case 'Class': + this.classes.push(new Class(compiler, this, scope, node)); + break; + case 'EventHandler': this.handlers.push(new EventHandler(compiler, this, scope, node)); break; @@ -228,6 +237,13 @@ export default class Element extends Node { block.addDependencies(binding.value.dependencies); }); + this.classes.forEach(classDir => { + this.parent.cannotUseInnerHTML(); + if (classDir.expression) { + block.addDependencies(classDir.expression.dependencies); + } + }); + this.handlers.forEach(handler => { this.parent.cannotUseInnerHTML(); block.addDependencies(handler.dependencies); @@ -403,6 +419,7 @@ export default class Element extends Node { this.addTransitions(block); this.addAnimation(block); this.addActions(block); + this.addClasses(block); if (this.initialUpdate) { block.builders.mount.addBlock(this.initialUpdate); @@ -584,6 +601,9 @@ export default class Element extends Node { } this.attributes.forEach((attribute: Attribute) => { + if (attribute.name === 'class' && attribute.isDynamic) { + this.classDependencies.push(...attribute.dependencies); + } attribute.render(block); }); } @@ -867,6 +887,26 @@ export default class Element extends Node { }); } + addClasses(block: Block) { + this.classes.forEach(classDir => { + const { expression: { snippet, dependencies}, name } = classDir; + const updater = `@toggleClass(${this.var}, "${name}", ${snippet});`; + + block.builders.hydrate.addLine(updater); + + if ((dependencies && dependencies.size > 0) || this.classDependencies.length) { + const allDeps = this.classDependencies.concat(...dependencies); + const deps = allDeps.map(dependency => `changed.${dependency}`).join(' || '); + const condition = allDeps.length > 1 ? `(${deps})` : deps; + + block.builders.update.addConditional( + condition, + updater + ); + } + }); + } + getStaticAttributeValue(name: string) { const attribute = this.attributes.find( (attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name @@ -937,6 +977,13 @@ export default class Element extends Node { appendTarget.slots[slotName] = ''; } + const classExpr = this.classes.map((classDir: Class) => { + const { expression: { snippet }, name } = classDir; + return `${snippet} ? "${name}" : ""`; + }).join(', '); + + let addClassAttribute = classExpr ? true : false; + if (this.attributes.find(attr => attr.isSpread)) { // TODO dry this out const args = []; @@ -977,12 +1024,19 @@ export default class Element extends Node { ) { // a boolean attribute with one non-Text chunk openingTag += '${' + attribute.chunks[0].snippet + ' ? " ' + attribute.name + '" : "" }'; + } else if (attribute.name === 'class' && classExpr) { + addClassAttribute = false; + openingTag += ` class="\${ [\`${attribute.stringifyForSsr()}\`, ${classExpr} ].join(' ') }"`; } else { openingTag += ` ${attribute.name}="${attribute.stringifyForSsr()}"`; } }); } + if (addClassAttribute) { + openingTag += ` class="\${ [${classExpr}].join(' ') }"`; + } + openingTag += '>'; compiler.target.append(openingTag); diff --git a/src/compile/nodes/IfBlock.ts b/src/compile/nodes/IfBlock.ts index 2a5a49af1689..eef654b90bbb 100644 --- a/src/compile/nodes/IfBlock.ts +++ b/src/compile/nodes/IfBlock.ts @@ -139,9 +139,10 @@ export default class IfBlock extends Node { this.buildCompoundWithOutros(block, parentNode, parentNodes, branches, dynamic, vars); if (this.compiler.options.nestedTransitions) { - block.builders.outro.addLine( - `${name}.o(#outrocallback);` - ); + block.builders.outro.addBlock(deindent` + if (${name}) ${name}.o(#outrocallback); + else #outrocallback(); + `); } } else { this.buildCompound(block, parentNode, parentNodes, branches, dynamic, vars); diff --git a/src/parse/read/directives.ts b/src/parse/read/directives.ts index 62a249a15874..813b1ce54a9c 100644 --- a/src/parse/read/directives.ts +++ b/src/parse/read/directives.ts @@ -77,10 +77,19 @@ const DIRECTIVES: Record { - fn(); - }); + program.group.callbacks.forEach(run); } } else { if (obj.css) transitionManager.deleteRule(node, program.name); diff --git a/src/shared/utils.js b/src/shared/utils.js index 1394f55a46d0..2077c25e010b 100644 --- a/src/shared/utils.js +++ b/src/shared/utils.js @@ -31,4 +31,8 @@ export function exclude(src, prop) { const tar = {}; for (const k in src) k === prop || (tar[k] = src[k]); return tar; +} + +export function run(fn) { + fn(); } \ No newline at end of file diff --git a/src/validate/html/index.ts b/src/validate/html/index.ts index ed4eaf4d382e..eabe9d88724f 100644 --- a/src/validate/html/index.ts +++ b/src/validate/html/index.ts @@ -14,7 +14,7 @@ function isEmptyBlock(node: Node) { if (!/Block$/.test(node.type) || !node.children) return false; if (node.children.length > 1) return false; const child = node.children[0]; - return !child || (child.type === 'Text' && !/\S/.test(child.data)); + return !child || (child.type === 'Text' && !/[^ \r\n\f\v\t]/.test(child.data)); } export default function validateHtml(validator: Validator, html: Node) { diff --git a/src/validate/html/validateComponent.ts b/src/validate/html/validateComponent.ts index 77d9cc275fd9..74bb6ebc6069 100644 --- a/src/validate/html/validateComponent.ts +++ b/src/validate/html/validateComponent.ts @@ -25,11 +25,11 @@ export default function validateComponent( if (attribute.type === 'Ref') { if (!isValidIdentifier(attribute.name)) { const suggestion = attribute.name.replace(/[^_$a-z0-9]/ig, '_').replace(/^\d/, '_$&'); - + validator.error(attribute, { code: `invalid-reference-name`, message: `Reference name '${attribute.name}' is invalid — must be a valid identifier such as ${suggestion}` - }); + }); } else { if (!refs.has(attribute.name)) refs.set(attribute.name, []); refs.get(attribute.name).push(node); @@ -49,6 +49,11 @@ export default function validateComponent( code: `invalid-action`, message: `Actions can only be applied to DOM elements, not components` }); + } else if (attribute.type === 'Class') { + validator.error(attribute, { + code: `invalid-class`, + message: `Classes can only be applied to DOM elements, not components` + }); } }); } diff --git a/test/js/samples/debug-ssr-foo/_config.js b/test/js/samples/debug-ssr-foo/_config.js new file mode 100644 index 000000000000..39bfbe7e6231 --- /dev/null +++ b/test/js/samples/debug-ssr-foo/_config.js @@ -0,0 +1,6 @@ +export default { + options: { + generate: 'ssr', + dev: true + } +}; \ No newline at end of file diff --git a/test/js/samples/debug-ssr-foo/expected-bundle.js b/test/js/samples/debug-ssr-foo/expected-bundle.js new file mode 100644 index 000000000000..dcfc5c6d02a9 --- /dev/null +++ b/test/js/samples/debug-ssr-foo/expected-bundle.js @@ -0,0 +1,46 @@ +var { debug, each, escape } = require("svelte/shared.js"); + +var SvelteComponent = {}; +SvelteComponent.data = function() { + return {}; +}; + +SvelteComponent.render = function(state, options = {}) { + var components = new Set(); + + function addComponent(component) { + components.add(component); + } + + var result = { head: '', addComponent }; + var html = SvelteComponent._render(result, state, options); + + var cssCode = Array.from(components).map(c => c.css && c.css.code).filter(Boolean).join('\n'); + + return { + html, + head: result.head, + css: { code: cssCode, map: null }, + toString() { + return html; + } + }; +}; + +SvelteComponent._render = function(__result, ctx, options) { + __result.addComponent(SvelteComponent); + + ctx = Object.assign({}, ctx); + + return `${ each(ctx.things, item => Object.assign({}, ctx, { thing: item }), ctx => `${escape(ctx.thing.name)} + ${debug(null, 2, 2, { foo: ctx.foo })}`)} + +

foo: ${escape(ctx.foo)}

`; +}; + +SvelteComponent.css = { + code: '', + map: null +}; + +module.exports = SvelteComponent; diff --git a/test/js/samples/debug-ssr-foo/expected.js b/test/js/samples/debug-ssr-foo/expected.js new file mode 100644 index 000000000000..43f1be1db646 --- /dev/null +++ b/test/js/samples/debug-ssr-foo/expected.js @@ -0,0 +1,51 @@ +"use strict"; + +var { debug, each, escape } = require("svelte/shared.js"); + +var SvelteComponent = {};; + +SvelteComponent.data = function() { + return {}; +}; + +SvelteComponent.render = function(state, options = {}) { + var components = new Set(); + + function addComponent(component) { + components.add(component); + } + + var result = { head: '', addComponent }; + var html = SvelteComponent._render(result, state, options); + + var cssCode = Array.from(components).map(c => c.css && c.css.code).filter(Boolean).join('\n'); + + return { + html, + head: result.head, + css: { code: cssCode, map: null }, + toString() { + return html; + } + }; +} + +SvelteComponent._render = function(__result, ctx, options) { + __result.addComponent(SvelteComponent); + + ctx = Object.assign({}, ctx); + + return `${ each(ctx.things, item => Object.assign({}, ctx, { thing: item }), ctx => `${escape(ctx.thing.name)} + ${debug(null, 2, 2, { foo: ctx.foo })}`)} + +

foo: ${escape(ctx.foo)}

`; +}; + +SvelteComponent.css = { + code: '', + map: null +}; + +var warned = false; + +module.exports = SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/debug-ssr-foo/input.html b/test/js/samples/debug-ssr-foo/input.html new file mode 100644 index 000000000000..6e926a4015f6 --- /dev/null +++ b/test/js/samples/debug-ssr-foo/input.html @@ -0,0 +1,6 @@ +{#each things as thing} + {thing.name} + {@debug foo} +{/each} + +

foo: {foo}

\ No newline at end of file diff --git a/test/js/samples/select-dynamic-value/expected-bundle.js b/test/js/samples/select-dynamic-value/expected-bundle.js new file mode 100644 index 000000000000..1230856164f4 --- /dev/null +++ b/test/js/samples/select-dynamic-value/expected-bundle.js @@ -0,0 +1,224 @@ +function noop() {} + +function assign(tar, src) { + for (var k in src) tar[k] = src[k]; + return tar; +} + +function append(target, node) { + target.appendChild(node); +} + +function insert(target, node, anchor) { + target.insertBefore(node, anchor); +} + +function detachNode(node) { + node.parentNode.removeChild(node); +} + +function createElement(name) { + return document.createElement(name); +} + +function createText(data) { + return document.createTextNode(data); +} + +function blankObject() { + return Object.create(null); +} + +function destroy(detach) { + this.destroy = noop; + this.fire('destroy'); + this.set = noop; + + this._fragment.d(detach !== false); + this._fragment = null; + this._state = {}; +} + +function _differs(a, b) { + return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function'); +} + +function fire(eventName, data) { + var handlers = + eventName in this._handlers && this._handlers[eventName].slice(); + if (!handlers) return; + + for (var i = 0; i < handlers.length; i += 1) { + var handler = handlers[i]; + + if (!handler.__calling) { + try { + handler.__calling = true; + handler.call(this, data); + } finally { + handler.__calling = false; + } + } + } +} + +function flush(component) { + component._lock = true; + callAll(component._beforecreate); + callAll(component._oncreate); + callAll(component._aftercreate); + component._lock = false; +} + +function get() { + return this._state; +} + +function init(component, options) { + component._handlers = blankObject(); + component._slots = blankObject(); + component._bind = options._bind; + + component.options = options; + component.root = options.root || component; + component.store = options.store || component.root.store; + + if (!options.root) { + component._beforecreate = []; + component._oncreate = []; + component._aftercreate = []; + } +} + +function on(eventName, handler) { + var handlers = this._handlers[eventName] || (this._handlers[eventName] = []); + handlers.push(handler); + + return { + cancel: function() { + var index = handlers.indexOf(handler); + if (~index) handlers.splice(index, 1); + } + }; +} + +function set(newState) { + this._set(assign({}, newState)); + if (this.root._lock) return; + flush(this.root); +} + +function _set(newState) { + var oldState = this._state, + changed = {}, + dirty = false; + + for (var key in newState) { + if (this._differs(newState[key], oldState[key])) changed[key] = dirty = true; + } + if (!dirty) return; + + this._state = assign(assign({}, oldState), newState); + this._recompute(changed, this._state); + if (this._bind) this._bind(changed, this._state); + + if (this._fragment) { + this.fire("state", { changed: changed, current: this._state, previous: oldState }); + this._fragment.p(changed, this._state); + this.fire("update", { changed: changed, current: this._state, previous: oldState }); + } +} + +function callAll(fns) { + while (fns && fns.length) fns.shift()(); +} + +function _mount(target, anchor) { + this._fragment[this._fragment.i ? 'i' : 'm'](target, anchor || null); +} + +var proto = { + destroy, + get, + fire, + on, + set, + _recompute: noop, + _set, + _mount, + _differs +}; + +/* generated by Svelte vX.Y.Z */ + +function create_main_fragment(component, ctx) { + var select, option, text, option_1, text_1, select_value_value; + + return { + c() { + select = createElement("select"); + option = createElement("option"); + text = createText("1"); + option_1 = createElement("option"); + text_1 = createText("2"); + option.__value = "1"; + option.value = option.__value; + option_1.__value = "2"; + option_1.value = option_1.__value; + }, + + m(target, anchor) { + insert(target, select, anchor); + append(select, option); + append(option, text); + append(select, option_1); + append(option_1, text_1); + + select_value_value = ctx.current; + for (var i = 0; i < select.options.length; i += 1) { + var option_2 = select.options[i]; + + if (option_2.__value === select_value_value) { + option_2.selected = true; + break; + } + } + }, + + p(changed, ctx) { + if ((changed.current) && select_value_value !== (select_value_value = ctx.current)) { + for (var i = 0; i < select.options.length; i += 1) { + var option_2 = select.options[i]; + + if (option_2.__value === select_value_value) { + option_2.selected = true; + break; + } + } + } + }, + + d(detach) { + if (detach) { + detachNode(select); + } + } + }; +} + +function SvelteComponent(options) { + init(this, options); + this._state = assign({}, options.data); + this._intro = true; + + this._fragment = create_main_fragment(this, this._state); + + if (options.target) { + this._fragment.c(); + this._mount(options.target, options.anchor); + } +} + +assign(SvelteComponent.prototype, proto); + +export default SvelteComponent; diff --git a/test/js/samples/select-dynamic-value/expected.js b/test/js/samples/select-dynamic-value/expected.js new file mode 100644 index 000000000000..9bf99b528da0 --- /dev/null +++ b/test/js/samples/select-dynamic-value/expected.js @@ -0,0 +1,73 @@ +/* generated by Svelte vX.Y.Z */ +import { append, assign, createElement, createText, detachNode, init, insert, proto } from "svelte/shared.js"; + +function create_main_fragment(component, ctx) { + var select, option, text, option_1, text_1, select_value_value; + + return { + c() { + select = createElement("select"); + option = createElement("option"); + text = createText("1"); + option_1 = createElement("option"); + text_1 = createText("2"); + option.__value = "1"; + option.value = option.__value; + option_1.__value = "2"; + option_1.value = option_1.__value; + }, + + m(target, anchor) { + insert(target, select, anchor); + append(select, option); + append(option, text); + append(select, option_1); + append(option_1, text_1); + + select_value_value = ctx.current; + for (var i = 0; i < select.options.length; i += 1) { + var option_2 = select.options[i]; + + if (option_2.__value === select_value_value) { + option_2.selected = true; + break; + } + } + }, + + p(changed, ctx) { + if ((changed.current) && select_value_value !== (select_value_value = ctx.current)) { + for (var i = 0; i < select.options.length; i += 1) { + var option_2 = select.options[i]; + + if (option_2.__value === select_value_value) { + option_2.selected = true; + break; + } + } + } + }, + + d(detach) { + if (detach) { + detachNode(select); + } + } + }; +} + +function SvelteComponent(options) { + init(this, options); + this._state = assign({}, options.data); + this._intro = true; + + this._fragment = create_main_fragment(this, this._state); + + if (options.target) { + this._fragment.c(); + this._mount(options.target, options.anchor); + } +} + +assign(SvelteComponent.prototype, proto); +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/select-dynamic-value/input.html b/test/js/samples/select-dynamic-value/input.html new file mode 100644 index 000000000000..2c7d174d9246 --- /dev/null +++ b/test/js/samples/select-dynamic-value/input.html @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/test/runtime/samples/action-ternary-template/_config.js b/test/runtime/samples/action-ternary-template/_config.js new file mode 100644 index 000000000000..7e9196d5953c --- /dev/null +++ b/test/runtime/samples/action-ternary-template/_config.js @@ -0,0 +1,20 @@ +export default { + data: { + target: 'World!', + display: true, + }, + + html: ` +

+ `, + + test ( assert, component, target, window ) { + const header = target.querySelector( 'h1' ); + const eventClick = new window.MouseEvent( 'click' ); + + header.dispatchEvent( eventClick ); + assert.htmlEqual( target.innerHTML, ` +

Hello World!

+ ` ); + } +}; diff --git a/test/runtime/samples/action-ternary-template/main.html b/test/runtime/samples/action-ternary-template/main.html new file mode 100644 index 000000000000..58e19e28f475 --- /dev/null +++ b/test/runtime/samples/action-ternary-template/main.html @@ -0,0 +1,21 @@ +

+ + \ No newline at end of file diff --git a/test/runtime/samples/class-boolean/_config.js b/test/runtime/samples/class-boolean/_config.js new file mode 100644 index 000000000000..a5003566cca1 --- /dev/null +++ b/test/runtime/samples/class-boolean/_config.js @@ -0,0 +1,3 @@ +export default { + html: `
` +}; diff --git a/test/runtime/samples/class-boolean/main.html b/test/runtime/samples/class-boolean/main.html new file mode 100644 index 000000000000..2595907a6e4b --- /dev/null +++ b/test/runtime/samples/class-boolean/main.html @@ -0,0 +1 @@ +
diff --git a/test/runtime/samples/class-helper/_config.js b/test/runtime/samples/class-helper/_config.js new file mode 100644 index 000000000000..38aed667be50 --- /dev/null +++ b/test/runtime/samples/class-helper/_config.js @@ -0,0 +1,14 @@ +export default { + data: { + user: { active: true } + }, + html: `
`, + + test ( assert, component, target, window ) { + component.set({ user: { active: false }}); + + assert.htmlEqual( target.innerHTML, ` +
+ ` ); + } +}; diff --git a/test/runtime/samples/class-helper/main.html b/test/runtime/samples/class-helper/main.html new file mode 100644 index 000000000000..8e77da1282bf --- /dev/null +++ b/test/runtime/samples/class-helper/main.html @@ -0,0 +1,11 @@ +
+ + diff --git a/test/runtime/samples/class-with-attribute/_config.js b/test/runtime/samples/class-with-attribute/_config.js new file mode 100644 index 000000000000..719e6bd473fb --- /dev/null +++ b/test/runtime/samples/class-with-attribute/_config.js @@ -0,0 +1,3 @@ +export default { + html: `
` +}; diff --git a/test/runtime/samples/class-with-attribute/main.html b/test/runtime/samples/class-with-attribute/main.html new file mode 100644 index 000000000000..c8d9e98f76f1 --- /dev/null +++ b/test/runtime/samples/class-with-attribute/main.html @@ -0,0 +1 @@ +
diff --git a/test/runtime/samples/class-with-dynamic-attribute/_config.js b/test/runtime/samples/class-with-dynamic-attribute/_config.js new file mode 100644 index 000000000000..9b65c1955958 --- /dev/null +++ b/test/runtime/samples/class-with-dynamic-attribute/_config.js @@ -0,0 +1,14 @@ +export default { + data: { + myClass: 'one two' + }, + html: `
`, + + test ( assert, component, target, window ) { + component.set({ myClass: 'one' }); + + assert.htmlEqual( target.innerHTML, ` +
+ ` ); + } +}; diff --git a/test/runtime/samples/class-with-dynamic-attribute/main.html b/test/runtime/samples/class-with-dynamic-attribute/main.html new file mode 100644 index 000000000000..b329f1544d1a --- /dev/null +++ b/test/runtime/samples/class-with-dynamic-attribute/main.html @@ -0,0 +1 @@ +
diff --git a/test/runtime/samples/if-block-outro-nested-else/Component.html b/test/runtime/samples/if-block-outro-nested-else/Component.html new file mode 100644 index 000000000000..281c6866c375 --- /dev/null +++ b/test/runtime/samples/if-block-outro-nested-else/Component.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/test/runtime/samples/if-block-outro-nested-else/_config.js b/test/runtime/samples/if-block-outro-nested-else/_config.js new file mode 100644 index 000000000000..4fe5eaa92677 --- /dev/null +++ b/test/runtime/samples/if-block-outro-nested-else/_config.js @@ -0,0 +1,8 @@ +export default { + nestedTransitions: true, + + test ( assert, component, target ) { + // Would cause "TypeError: Cannot read property 'o' of undefined" + component.set({ foo: false }); + } +}; diff --git a/test/runtime/samples/if-block-outro-nested-else/main.html b/test/runtime/samples/if-block-outro-nested-else/main.html new file mode 100644 index 000000000000..02e000b3c346 --- /dev/null +++ b/test/runtime/samples/if-block-outro-nested-else/main.html @@ -0,0 +1,16 @@ +{#if foo} + {#if false} + + {:elseif false} + + {/if} +{/if} + + diff --git a/test/runtime/samples/transition-js-context/_config.js b/test/runtime/samples/transition-js-context/_config.js new file mode 100644 index 000000000000..c5b3f1460a40 --- /dev/null +++ b/test/runtime/samples/transition-js-context/_config.js @@ -0,0 +1,9 @@ +export default { + test(assert, component, target, window, raf) { + const div = target.querySelector('div'); + assert.equal(div.foo, 42); + + raf.tick(50); + assert.equal(div.foo, 42); + } +}; diff --git a/test/runtime/samples/transition-js-context/main.html b/test/runtime/samples/transition-js-context/main.html new file mode 100644 index 000000000000..18f5f50ec900 --- /dev/null +++ b/test/runtime/samples/transition-js-context/main.html @@ -0,0 +1,20 @@ +
+ + \ No newline at end of file diff --git a/test/validator/samples/non-empty-block-dev/_config.js b/test/validator/samples/non-empty-block-dev/_config.js new file mode 100644 index 000000000000..e26996239d88 --- /dev/null +++ b/test/validator/samples/non-empty-block-dev/_config.js @@ -0,0 +1,3 @@ +export default { + dev: true +}; \ No newline at end of file diff --git a/test/validator/samples/non-empty-block-dev/input.html b/test/validator/samples/non-empty-block-dev/input.html new file mode 100644 index 000000000000..ed4b9e627416 --- /dev/null +++ b/test/validator/samples/non-empty-block-dev/input.html @@ -0,0 +1,3 @@ +{#if x} +   +{/if} \ No newline at end of file diff --git a/test/validator/samples/non-empty-block-dev/warnings.json b/test/validator/samples/non-empty-block-dev/warnings.json new file mode 100644 index 000000000000..0637a088a01e --- /dev/null +++ b/test/validator/samples/non-empty-block-dev/warnings.json @@ -0,0 +1 @@ +[] \ No newline at end of file