add legacy option, use it for setInputType (#773)

pull/778/head
Rich Harris 7 years ago
parent cd1e8c12c1
commit f7b829820f

@ -20,6 +20,7 @@ export class DomGenerator extends Generator {
metaBindings: string[];
hydratable: boolean;
legacy: boolean;
hasIntroTransitions: boolean;
hasOutroTransitions: boolean;
@ -40,6 +41,7 @@ export class DomGenerator extends Generator {
this.readonly = new Set();
this.hydratable = options.hydratable;
this.legacy = options.legacy;
this.needsEncapsulateHelper = false;
// initial values for e.g. window.innerWidth, if there's a <:Window> meta tag

@ -44,6 +44,8 @@ export default function visitAttribute(
(attribute.value !== true && attribute.value.length > 1) ||
(attribute.value.length === 1 && attribute.value[0].type !== 'Text');
const isLegacyInputType = generator.legacy && name === 'type' && node.name === 'input';
if (isDynamic) {
let value;
@ -108,7 +110,12 @@ export default function visitAttribute(
let updater;
const init = shouldCache ? `${last} = ${value}` : value;
if (isSelectValueAttribute) {
if (isLegacyInputType) {
block.builders.hydrate.addLine(
`@setInputType( ${state.parentNode}, ${init} );`
);
updater = `@setInputType( ${state.parentNode}, ${shouldCache ? last : value} );`;
} else if (isSelectValueAttribute) {
// annoying special case
const isMultipleSelect =
node.name === 'select' &&
@ -178,9 +185,11 @@ export default function visitAttribute(
? `''`
: stringify(attribute.value[0].data);
const statement = propertyName
? `${state.parentNode}.${propertyName} = ${value};`
: `${method}( ${state.parentNode}, '${name}', ${value} );`;
const statement = (
isLegacyInputType ? `@setInputType( ${state.parentNode}, ${value} );` :
propertyName ? `${state.parentNode}.${propertyName} = ${value};` :
`${method}( ${state.parentNode}, '${name}', ${value} );`
);
block.builders.hydrate.addLine(statement);

@ -53,6 +53,7 @@ export interface CompileOptions {
shared?: boolean | string;
cascade?: boolean;
hydratable?: boolean;
legacy?: boolean;
onerror?: (error: Error) => void;
onwarn?: (warning: Warning) => void;

@ -96,4 +96,10 @@ export function claimText (nodes, data) {
}
return createText(data);
}
export function setInputType(input, type) {
try {
input.type = type;
} catch (e) {}
}

@ -2,7 +2,7 @@ import assert from "assert";
import * as fs from "fs";
import * as path from "path";
import { rollup } from "rollup";
import { svelte } from "../helpers.js";
import { loadConfig, svelte } from "../helpers.js";
describe("js", () => {
fs.readdirSync("test/js/samples").forEach(dir => {
@ -17,6 +17,8 @@ describe("js", () => {
(solo ? it.only : it)(dir, () => {
dir = path.resolve("test/js/samples", dir);
const config = loadConfig(`${dir}/_config.js`);
const input = fs
.readFileSync(`${dir}/input.html`, "utf-8")
.replace(/\s+$/, "");
@ -24,20 +26,17 @@ describe("js", () => {
let actual;
try {
actual = svelte.compile(input, {
const options = Object.assign(config.options || {}, {
shared: true
}).code;
});
actual = svelte.compile(input, options).code;
} catch (err) {
console.log(err.frame);
throw err;
}
fs.writeFileSync(`${dir}/_actual.js`, actual);
const expected = fs.readFileSync(`${dir}/expected.js`, "utf-8");
const expectedBundle = fs.readFileSync(
`${dir}/expected-bundle.js`,
"utf-8"
);
return rollup({
entry: `${dir}/_actual.js`,
@ -56,6 +55,12 @@ describe("js", () => {
}).then(({ code }) => {
fs.writeFileSync(`${dir}/_actual-bundle.js`, code);
const expected = fs.readFileSync(`${dir}/expected.js`, "utf-8");
const expectedBundle = fs.readFileSync(
`${dir}/expected-bundle.js`,
"utf-8"
);
assert.equal(
actual.trim().replace(/^\s+$/gm, ""),
expected.trim().replace(/^\s+$/gm, "")

@ -0,0 +1,5 @@
export default {
options: {
legacy: true
}
};

@ -0,0 +1,213 @@
function noop() {}
function assign(target) {
var k,
source,
i = 1,
len = arguments.length;
for (; i < len; i++) {
source = arguments[i];
for (k in source) target[k] = source[k];
}
return target;
}
function insertNode(node, target, anchor) {
target.insertBefore(node, anchor);
}
function detachNode(node) {
node.parentNode.removeChild(node);
}
function createElement(name) {
return document.createElement(name);
}
function setInputType(input, type) {
try {
input.type = type;
} catch (e) {}
}
function destroy(detach) {
this.destroy = this.set = this.get = noop;
this.fire('destroy');
if (detach !== false) this._fragment.unmount();
this._fragment.destroy();
this._fragment = this._state = null;
}
function differs(a, b) {
return a !== b || ((a && typeof a === 'object') || typeof a === 'function');
}
function dispatchObservers(component, group, changed, newState, oldState) {
for (var key in group) {
if (!changed[key]) continue;
var newValue = newState[key];
var oldValue = oldState[key];
var callbacks = group[key];
if (!callbacks) continue;
for (var i = 0; i < callbacks.length; i += 1) {
var callback = callbacks[i];
if (callback.__calling) continue;
callback.__calling = true;
callback.call(component, newValue, oldValue);
callback.__calling = false;
}
}
}
function get(key) {
return key ? this._state[key] : this._state;
}
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) {
handlers[i].call(this, data);
}
}
function observe(key, callback, options) {
var group = options && options.defer
? this._observers.post
: this._observers.pre;
(group[key] || (group[key] = [])).push(callback);
if (!options || options.init !== false) {
callback.__calling = true;
callback.call(this, this._state[key]);
callback.__calling = false;
}
return {
cancel: function() {
var index = group[key].indexOf(callback);
if (~index) group[key].splice(index, 1);
}
};
}
function on(eventName, handler) {
if (eventName === 'teardown') return this.on('destroy', 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;
this._root._lock = true;
callAll(this._root._beforecreate);
callAll(this._root._oncreate);
callAll(this._root._aftercreate);
this._root._lock = false;
}
function _set(newState) {
var oldState = this._state,
changed = {},
dirty = false;
for (var key in newState) {
if (differs(newState[key], oldState[key])) changed[key] = dirty = true;
}
if (!dirty) return;
this._state = assign({}, oldState, newState);
this._recompute(changed, this._state, oldState, false);
if (this._bind) this._bind(changed, this._state);
dispatchObservers(this, this._observers.pre, changed, this._state, oldState);
this._fragment.update(changed, this._state);
dispatchObservers(this, this._observers.post, changed, this._state, oldState);
}
function callAll(fns) {
while (fns && fns.length) fns.pop()();
}
var proto = {
destroy: destroy,
get: get,
fire: fire,
observe: observe,
on: on,
set: set,
teardown: destroy,
_recompute: noop,
_set: _set
};
function create_main_fragment ( state, component ) {
var input;
return {
create: function () {
input = createElement( 'input' );
this.hydrate();
},
hydrate: function ( nodes ) {
setInputType( input, "search" );
},
mount: function ( target, anchor ) {
insertNode( input, target, anchor );
},
update: noop,
unmount: function () {
detachNode( input );
},
destroy: noop
};
}
function SvelteComponent ( options ) {
options = options || {};
this._state = options.data || {};
this._observers = {
pre: Object.create( null ),
post: Object.create( null )
};
this._handlers = Object.create( null );
this._root = options._root || this;
this._yield = options._yield;
this._bind = options._bind;
this._fragment = create_main_fragment( this._state, this );
if ( options.target ) {
this._fragment.create();
this._fragment.mount( options.target, null );
}
}
assign( SvelteComponent.prototype, proto );
export default SvelteComponent;

@ -0,0 +1,55 @@
import { assign, createElement, detachNode, insertNode, noop, proto, setInputType } from "svelte/shared.js";
function create_main_fragment ( state, component ) {
var input;
return {
create: function () {
input = createElement( 'input' );
this.hydrate();
},
hydrate: function ( nodes ) {
setInputType( input, "search" );
},
mount: function ( target, anchor ) {
insertNode( input, target, anchor );
},
update: noop,
unmount: function () {
detachNode( input );
},
destroy: noop
};
}
function SvelteComponent ( options ) {
options = options || {};
this._state = options.data || {};
this._observers = {
pre: Object.create( null ),
post: Object.create( null )
};
this._handlers = Object.create( null );
this._root = options._root || this;
this._yield = options._yield;
this._bind = options._bind;
this._fragment = create_main_fragment( this._state, this );
if ( options.target ) {
this._fragment.create();
this._fragment.mount( options.target, null );
}
}
assign( SvelteComponent.prototype, proto );
export default SvelteComponent;
Loading…
Cancel
Save