def(incremental-dom) initial commit

This commit is contained in:
basarat
2015-07-11 16:53:27 +10:00
parent 286c198898
commit dac60b5c95
3 changed files with 261 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
/// <reference path="incremental-dom.d.ts" />
declare var describe:any
,it:any
,expect:any
,beforeEach:any
,afterEach:any;
/// <reference path="tests/functional/attributes-tests.ts" />
+81
View File
@@ -0,0 +1,81 @@
// Type definitions for Incremetal DOM
// Project: https://github.com/google/incremental-dom
// Definitions by: Basarat Ali Syed <https://github.com/basarat>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
declare module "incremental-dom" {
/**
* Patches the document starting at el with the provided function. This function
* may be called during an existing patch operation.
* @param {!Element} el the element to patch
* @param {!function} fn A function containing elementOpen/elementClose/etc.
* calls that describe the DOM.
*/
export var patch: (el: Node, fn: Function) => void;
/**
* Declares a virtual Element at the current location in the document. This
* corresponds to an opening tag and a elementClose tag is required.
* @param {string} tag The element's tag.
* @param {?string} key The key used to identify this element. This can be an
* empty string, but performance may be better if a unique value is used
* when iterating over an array of items.
* @param {?Array<*>} statics An array of attribute name/value pairs of the
* static attributes for the Element. These will only be set once when the
* Element is created.
* @param {...*} var_args Attribute name/value pairs of the dynamic attributes
* for the Element.
*/
export var elementOpen: (tag: string, key?: string, statics?: any[], ...var_args: any[]) => void;
/**
* Declares a virtual Element at the current location in the document. This
* corresponds to an opening tag and a elementClose tag is required. This is
* like elementOpen, but the attributes are defined using the attr function
* rather than being passed as arguments. Must be folllowed by 0 or more calls
* to attr, then a call to elementOpenEnd.
* @param {string} tag The element's tag.
* @param {?string} key The key used to identify this element. This can be an
* empty string, but performance may be better if a unique value is used
* when iterating over an array of items.
* @param {?Array<*>} statics An array of attribute name/value pairs of the
* static attributes for the Element. These will only be set once when the
* Element is created.
*/
export var elementOpenStart: (tag: string, key?: any, ...statics: any[]) => void;
/***
* Defines a virtual attribute at this point of the DOM. This is only valid
* when called between elementOpenStart and elementOpenEnd.
*
* @param {string} name
* @param {*} value
*/
export var attr: (name: string, value: any) => void;
/**
* Closes an open tag started with elementOpenStart.
*/
export var elementOpenEnd: () => void;
/**
* Closes an open virtual Element.
*/
export var elementClose: () => void;
/**
* Declares a virtual Element at the current location in the document that has
* no children.
* @param {string} tag The element's tag.
* @param {?string} key The key used to identify this element. This can be an
* empty string, but performance may be better if a unique value is used
* when iterating over an array of items.
* @param {?Array<*>} statics An array of attribute name/value pairs of the
* static attributes for the Element. These will only be set once when the
* Element is created.
* @param {...*} var_args Attribute name/value pairs of the dynamic attributes
* for the Element.
*/
export var elementVoid: (tag: string, key?: string, statics?: any, ...var_args: any[]) => void;
/**
* Declares a virtual Text at this point in the document.
*
* @param {string} value The text of the Text.
*/
export var text: (value: string) => void;
}
@@ -0,0 +1,171 @@
/// <reference path="../../all-tests.ts"/>
import id = require('incremental-dom');
var patch = id.patch;
var elementVoid = id.elementVoid;
describe('attribute updates', () => {
var container:any;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
document.body.removeChild(container);
});
describe('for conditional attributes', () => {
function render(obj:any) {
elementVoid('div', '', [],
'data-expanded', obj.key);
}
it('should be present when they have a value', () => {
patch(container, () => render({
key: 'hello'
}));
var el = container.childNodes[0];
expect(el.getAttribute('data-expanded')).to.equal('hello');
});
it('should be present when falsy', () => {
patch(container, () => render({
key: false
}));
var el = container.childNodes[0];
expect(el.getAttribute('data-expanded')).to.equal('false');
});
it('should be not present when undefined', () => {
patch(container, () => render({
key: undefined
}));
var el = container.childNodes[0];
expect(el.getAttribute('data-expanded')).to.equal(null);
});
it('should update the DOM when they change', () => {
patch(container, () => render({
key: 'foo'
}));
patch(container, () => render({
key: 'bar'
}));
var el = container.childNodes[0];
expect(el.getAttribute('data-expanded')).to.equal('bar');
});
});
describe('for function attributes', () => {
it('should not be set as attributes', () => {
var fn = () =>{};
patch(container, () => {
elementVoid('div', '', null,
'fn', fn);
});
var el = container.childNodes[0];
expect(el.hasAttribute('fn')).to.be.false;
});
it('should be set on the node', () => {
var fn = () =>{};
patch(container, () => {
elementVoid('div', '', null,
'fn', fn);
});
var el = container.childNodes[0];
expect(el.fn).to.equal(fn);
});
});
describe('for object attributes', () => {
it('should not be set as attributes', () => {
var obj = {};
patch(container, () => {
elementVoid('div', '', null,
'obj', obj);
});
var el = container.childNodes[0];
expect(el.hasAttribute('obj')).to.be.false;
});
it('should be set on the node', () => {
var obj = {};
patch(container, () => {
elementVoid('div', '', null,
'obj', obj);
});
var el = container.childNodes[0];
expect(el.obj).to.equal(obj);
});
});
describe('for style', () => {
function render(style:any) {
elementVoid('div', '', [],
'style', style);
}
it('should render with the correct style properties for objects', () => {
patch(container, () => render({
color: 'white',
backgroundColor: 'red'
}));
var el = container.childNodes[0];
expect(el.style.color).to.equal('white');
expect(el.style.backgroundColor).to.equal('red');
});
it('should update the correct style properties', () => {
patch(container, () => render({
color: 'white'
}));
patch(container, () => render({
color: 'red'
}));
var el = container.childNodes[0];
expect(el.style.color).to.equal('red');
});
it('should remove properties not present in the new object', () => {
patch(container, () => render({
color: 'white'
}));
patch(container, () => render({
backgroundColor: 'red'
}));
var el = container.childNodes[0];
expect(el.style.color).to.equal('');
expect(el.style.backgroundColor).to.equal('red');
});
it('should render with the correct style properties for strings', () => {
patch(container, () => render('color: white; background-color: red;'));
var el = container.childNodes[0];
expect(el.style.color).to.equal('white');
expect(el.style.backgroundColor).to.equal('red');
});
it('should render with the correct style properties for String instances', () => {
patch(container, () => render(new String('color: white; background-color: red;')));
var el = container.childNodes[0];
expect(el.style.color).to.equal('white');
expect(el.style.backgroundColor).to.equal('red');
});
});
});