diff --git a/specs/html/spec.js b/specs/html/spec.js
index d01141e4..4e7fcaca 100644
--- a/specs/html/spec.js
+++ b/specs/html/spec.js
@@ -47,7 +47,7 @@ test('HTML Interfaces Available', function(){
ok(HTMLParamElement, 'HTMLParamElement defined');
ok(HTMLScriptElement, 'HTMLScriptElement defined');
ok(HTMLSelectElement, 'HTMLSelectElement defined');
- ok(HTMLSpanElement, 'HTMLSpanElement defined');
+ ok(HTMLSpanElement, 'HTMLSpanElement defined');
ok(HTMLStyleElement, 'HTMLStyleElement defined');
ok(HTMLTableElement, 'HTMLTableElement defined');
ok(HTMLTableSectionElement, 'HTMLTableSectionElement defined');
@@ -299,6 +299,9 @@ test('HTMLAreaElement', function(){
equals(element.parentNode, null, '.parentNode');
equals(element.prefix, null, '.prefix');
equals(xmlserializer.serializeToString(element), '', 'xmlserializer');
+ equals(element.alt, '', 'alt');
+ element.alt = 'foo';
+ equals(element.alt, 'foo', 'set alt');
equals(element.toString(), '', 'toString returns href');
element.href = 'http://envjs.com/';
@@ -332,6 +335,7 @@ test('HTMLDocument.createElement(frame)', function(){
equals(element.scrolling, "", '.scrolling');
equals(element.src, "", '.src');
equals(element.tagName, 'FRAME', '.name');
+ equals(element.toString(), '[object HTMLFrameElement]', 'toString');
equals(xmlserializer.serializeToString(element), '', 'xmlserializer');
});
@@ -391,6 +395,20 @@ test('HTMLBRElement', function() {
equals(a.toString(), '[object HTMLBRElement]');
});
+test('HTMLButtonElement', function() {
+ var e;
+ e = document.createElement('button');
+ ok(e, 'element created');
+ equals(e.toString(), '[object HTMLButtonElement]', 'toString');
+
+ equals(e.type, 'submit', 'type');
+ equals(e.value, '', 'empty button value');
+ equals(typeof e.value, 'string', 'empty button value is string');
+
+ e.value = 'foo';
+ equals(e.value, 'foo', 'set value');
+});
+
test('HTMLDivElement', function() {
var a = document.createElement('div');
ok(a, 'element created');
@@ -428,12 +446,37 @@ test('HTMLInputElement', function() {
equals(a.alt, '', 'empty alt is string');
a.alt = 'foo';
equals(a.alt, 'foo', 'set alt');
-
+ equals(a.type, 'text', 'type');
equals(a.src, '', 'empty src is string');
a.src = 'http://envjs.com/';
equals(a.src, 'http://envjs.com/', 'set src');
// TODO, src should make absolute any relative links
+ /**
+ * 'value' is a virtual state, NOT an attribute
+ *
+ */
+ // relationship between defaultValue and Value
+ equals(a.value, '', 'default value');
+ equals(a.defaultValue, '', 'default defaultValue');
+
+ a.defaultValue = 'bar';
+ equals(a.defaultValue, 'bar', 'set defaultValue');
+ equals(a.value, 'bar', 'value is initially set by defaultValue');
+
+ a.value = 'foo';
+ equals(a.value, 'foo', 'set value');
+ equals(a.defaultValue, 'bar', 'defaultValue is unchanged');
+
+ a.defaultValue = 'dingbat';
+ equals(a.defaultValue, 'dingbat', 'set defaultValue');
+ equals(a.value, 'foo', 'value is unchanged');
+
+ // test with DOMAPI
+ a.setAttribute('value', 'foobar');
+ equals(a.defaultValue, 'foobar', 'set defaultValue via DOMAPI');
+ equals(a.value, 'foo', 'value is unchanged');
+
/**
* Checked is a virtual state, NOT an attribute
*
@@ -463,6 +506,7 @@ test('HTMLInputElement', function() {
equals(a.useMap, '', 'useMap is false');
equals(typeof a.useMap, 'string', 'default useMap value is boolean');
+
/**
* Numeric-like things
*/
@@ -542,6 +586,22 @@ test('HTMLMetaElement', function() {
equals(element.getAttribute('content'), 'foo', 'get content via attribute');
});
+test('HTMLModElement', function() {
+ var a = document.createElement('del');
+ ok(a, 'element created');
+ //equals(a.toString(), '[object HTMLModElement]');
+
+ a = document.createElement('ins');
+ ok(a, 'element created');
+ //equals(a.toString(), '[object HTMLModElement]');
+});
+
+test('HTMLObjectElement', function() {
+ var a = document.createElement('object');
+ ok(a, 'element created');
+ equals(a.toString(), '[object HTMLObjectElement]');
+});
+
test('HTMLOListElement', function() {
var a = document.createElement('ol');
ok(a, 'element created');
@@ -578,6 +638,26 @@ test('HTMLQuoteElement', function() {
// See http://dev.w3.org/html5/spec/Overview.html#dom-quote-cite
});
+test('HTMLSelectElement', function() {
+ var a = document.createElement('select');
+ ok(a, 'element created');
+ equals(a.toString(), '[object HTMLSelectElement]');
+
+ equals(a.value, '', 'value');
+ equals(a.length, 0, 'length');
+ equals(a.selectedIndex, -1, 'selectedIndex');
+ equals(a.type, 'select-one', 'type');
+
+ equals(a.multiple, false, 'multiple');
+ a.multiple = true;
+ equals(a.multiple, true, 'set multiple');
+ equals(a.hasAttribute('multiple'), true, 'set multiple has attribute');
+ equals(a.getAttribute('multiple'), '', 'set multiple set attribute');
+ a.multiple = false;
+ equals(a.hasAttribute('multiple'), false,
+ 'set multiple removes attribute');
+});
+
test('HTMLSpanElement', function() {
var a = document.createElement('span');
ok(a, 'element created');
@@ -604,8 +684,8 @@ test('HTMLTableDataCellElement', function() {
ok(element, 'element created');
if (runningUnderEnvjs())
equals(element.toString(), '[object HTMLTableDataCellElement]',
- 'toString');
- // don't run in-browser, FF uses HTMLTableCellElement
+ 'toString');
+ // don't run in-browser, FF uses HTMLTableCellElement
});
test('HTMLTableHeaderCellElement', function() {
@@ -614,8 +694,8 @@ test('HTMLTableHeaderCellElement', function() {
ok(element, 'element created');
if (runningUnderEnvjs())
equals(element.toString(), '[object HTMLTableHeaderCellElement]',
- 'toString');
- // don't run in-browser, FF uses HTMLTableCellElement
+ 'toString');
+ // don't run in-browser, FF uses HTMLTableCellElement
});
test('HTMLTableRowElement', function() {
@@ -638,6 +718,7 @@ test('HTMLTextArea', function() {
ok(e, 'element created');
equals(e.toString(), '[object HTMLTextAreaElement]', 'toString');
+ equals(e.type, 'textarea', 'type');
equals(e.cols, -1, 'default cols is -1');
e.cols = '10';
equals(e.cols, 10, 'set cols');
@@ -648,6 +729,41 @@ test('HTMLTextArea', function() {
equals(e.rows, 11, 'set row');
equals(typeof e.rows, 'number', 'rows is a number');
+ // relationship between defaultValue and Value
+ equals(e.value, '', 'default value');
+ equals(e.defaultValue, '', 'default defaultValue');
+
+ e.defaultValue = 'bar';
+ equals(e.defaultValue, 'bar', 'set defaultValue');
+ equals(e.value, 'bar', 'value is initially set by defaultValue');
+
+ e.value = 'foo';
+ equals(e.value, 'foo', 'set value');
+ equals(e.defaultValue, 'bar', 'defaultValue is unchanged');
+
+ e.defaultValue = 'dingbat';
+ equals(e.defaultValue, 'dingbat', 'set defaultValue');
+ equals(e.value, 'foo', 'value is unchanged');
+
+ // change 'value' via DOMAPI setAttribute
+ e.value = 'foo';
+ e.defaultValue = 'bar';
+
+ // "setAttribute(value)" does nothing since the value of textarea is
+ // really in it's textContent child
+ e.setAttribute('value', 'dingbat');
+ equals(e.value, 'foo', 'value is NOT set via DOMAPI');
+ equals(e.defaultValue, 'bar', 'defaultValue is NOT set via setattr');
+ equals(e.textContent, 'bar', 'textContent is NOT set via setattr');
+
+ e.textContent = 'dingbat';
+ equals(e.textContent, 'dingbat', 'set textContent');
+ equals(e.value, 'foo', 'value is NOT set via textContent');
+ equals(e.defaultValue, 'dingbat', 'defaultValue is set via textContent');
+
+
+ // TODO: normalization of rawvalue
+
});
test('HTMLTitleElement', function() {
@@ -710,6 +826,7 @@ test("Option", function() {
equals(x.tagName, 'OPTION', 'constructor sets tagName');
equals(x.form, null, 'get form is null');
equals(x.selected, false, 'selected is false');
+ equals(typeof x.type, 'undefined', 'type is undefined');
x = new Option('text');
equals(x.text, 'text', 'text content');
@@ -719,11 +836,19 @@ test("Option", function() {
x = new Option('text', 'value');
equals(x.text, 'text', 'text content');
equals(x.value, 'value', 'value attribute');
+ equals(x.index, -1, 'index');
+ equals(x.form, null, 'form');
+
equals(x.selected, false, 'selected is false');
+ x.selected = true;
+ equals(x.selected, true, 'set selected');
- // TODO: defaultSelect, and selected arguments
- // Missing since logic to compute 'selectedness' is busted.
- x = new Option('text', 'value', true);
- x = new Option('text', 'value', true, true);
+ equals(x.defaultSelected, false, 'defaultselected');
+ x.defaultSelected = true;
+ equals(x.defaultSelected, true, 'set defaultselected');
+ x.defaultSelected = false;
+ equals(x.defaultSelected, false, 'set defaultselected');
+ x = new Option('text1', 'value1');
+ x = new Option('text2', 'value2', true, true);
});
diff --git a/specs/parser/boot.js b/specs/parser/boot.js
index e2259808..7a7a0fc1 100644
--- a/specs/parser/boot.js
+++ b/specs/parser/boot.js
@@ -5,6 +5,7 @@
load('specs/qunit.js');
load('specs/env.qunit.js');
+load('specs/helpers.js');
QUnit.init();
load('dist/platform/core.js');
diff --git a/specs/parser/spec.js b/specs/parser/spec.js
index 11497678..e678d1df 100644
--- a/specs/parser/spec.js
+++ b/specs/parser/spec.js
@@ -1,5 +1,12 @@
QUnit.module('parser');
+var isenvjs;
+try {
+ isenvjs = runningUnderEnvjs();
+} catch (e) {
+ isenvjs= false;
+}
+
test('Parser Interfaces Available', function(){
expect(1);
@@ -390,7 +397,7 @@ test('Form Named Element Lookup', function(){
// let's change the name
var node = form.input1;
node.name = 'input2';
- ok(elements.input1 instanceof HTMLInputElement, 'is HTMLInputElement');
+ ok(form.input2 instanceof HTMLInputElement, 'is HTMLInputElement');
ok(form.input1 instanceof HTMLInputElement, 'is HTMLInputElement');
/*
@@ -407,3 +414,247 @@ test('Form Named Element Lookup', function(){
doc.close();
stop();
});
+
+
+function testForm(doc, isenvjs) {
+ var form = doc.foo;
+ var elements = form.elements;
+ ok(elements instanceof HTMLCollection,
+ "form.elements is an HTMLCollection");
+ equals(elements.length, 6, "form.elements.length");
+ equals(form.length, 6, "form.length");
+
+
+ // not yet supported by FF 3.6
+ //equals(form.namedItem('e1').value, 'v1', 'form.namedItem(e1).value');
+ //equals(form.item(0).value, 'v1', 'form.item(0).value');
+
+ equals(form.e1.value, 'v1', 'form.e1.value');
+ equals(form.e2.value, 'v2', 'form.e2.value');
+ equals(form.e3.value, 'v3', 'form.e3.value');
+ equals(form.e4.value, 'v4', 'form.e4.value');
+ equals(form.e5.value, 'v5', 'form.e5.value');
+ equals(form.e6.value, 'v6', 'form.e6.value');
+
+ // quick tests of HTMLCollection
+ equals(form.elements.toString(), '[object HTMLCollection]',
+ 'form.elements.toString()');
+ equals(form.elements[1234], null, 'form.elements[12340]');
+ equals(form.elements.item(1234), null, 'form.elements.item(12340)');
+ equals(form.elements.namedItem('foo'), null, 'form.elements.namedItem(foo)');
+
+ equals(form.elements.e1.value, 'v1', 'form.elements.e1.value');
+ equals(form.elements.e2.value, 'v2', 'form.elements.e2.value');
+ equals(form.elements.e3.value, 'v3', 'form.elements.e3.value');
+ equals(form.elements.e4.value, 'v4', 'form.elements.e4.value');
+ equals(form.elements.e5.value, 'v5', 'form.elements.e5.value');
+ equals(form.elements.e6.value, 'v6', 'form.elements.e6.value');
+
+ // direct array lookup
+ equals(form.elements[0].value, 'v1', 'form.elements[0].value');
+ equals(form.elements[1].value, 'v2', 'form.elements[1].value');
+ equals(form.elements[2].value, 'v3', 'form.elements[2].value');
+ equals(form.elements[3].value, 'v4', 'form.elements[3].value');
+ equals(form.elements[4].value, 'v5', 'form.elements[4].value');
+ equals(form.elements[5].value, 'v6', 'form.elements[5].value');
+
+ // namedItems
+ equals(form.elements.namedItem('e1').value, 'v1',
+ 'form.elements.namedItem(e1).value');
+ equals(form.elements.namedItem('e2').value, 'v2',
+ 'form.elements.namedItem(e2).value');
+ equals(form.elements.namedItem('e3').value, 'v3',
+ 'form.elements.namedItem(e3).value');
+ equals(form.elements.namedItem('e4').value, 'v4',
+ 'form.elements.namedItem(e4).value');
+ equals(form.elements.namedItem('e5').value, 'v5',
+ 'form.elements.namedItem(e5).value');
+ equals(form.elements.namedItem('e6').value, 'v6',
+ 'form.elements.namedItem(e6).value');
+
+
+ // items
+ equals(form.elements.item(0).value, 'v1',
+ 'form.elements.item(e1).value');
+ equals(form.elements.item(1).value, 'v2',
+ 'form.elements.item(e2).value');
+ equals(form.elements.item(2).value, 'v3',
+ 'form.elements.item(e3).value');
+ equals(form.elements.item(3).value, 'v4',
+ 'form.elements.item(e4).value');
+ equals(form.elements.item(4).value, 'v5',
+ 'form.elements.item(e5).value');
+ equals(form.elements.item(5).value, 'v6',
+ 'form.elements.item(e6).value');
+
+ // Options
+ equals(form.e5[0].value, 'v5', 'form.e5[0]');
+ equals(form.e5[1].value, 'opt2', 'form.e5[1]');
+
+
+ equals(form.e5.item(0).value, 'v5', 'form.e5.item(0)');
+ equals(form.e5.item(1).value, 'opt2', 'form.e5.item(1)');
+
+
+ equals(form.e5.options.length, 2, 'form.e5.options.length');
+ equals(form.e5.options[0].value, 'v5', 'form.e5.options[0].value');
+ equals(form.e5.options[1].value, 'opt2', 'form.e5.options[1].value');
+ equals(form.e5.options.item(0).value, 'v5', 'form.e5.options[0].value');
+ equals(form.e5.options.item(1).value, 'opt2', 'form.e5.options[1].value');
+
+ // firefox bugs or incomplete behavior
+ // some of these run under the doc and innerHTML tests, but
+ // don't work under the DOMAPI test
+ if (isenvjs) {
+ equals(form.e5.options.namedItem('o1').value, 'v5', 'form.e5.options[0].value');
+ equals(form.e5.options.namedItem('o2').value, 'opt2', 'form.e5.options[1].value');
+ equals(form.e5['o1'].value, 'v5', 'form.e5[0]');
+ equals(form.e5['o2'].value, 'opt2', 'form.e5[1]');
+
+ equals(form.e5.namedItem('o1').value, 'v5', 'form.e5.namedItem(o1)');
+ equals(form.e5.namedItem('o2').value, 'opt2', 'form.e5.namedItem(o2)');
+ }
+
+
+}
+
+
+
+test('Form Named Elements via parser', function() {
+ if ((typeof Envjs == 'undefined') || !Envjs) {
+ Envjs = {};
+ }
+
+ // need to do this at top level since under FF,
+ // frames have different scope and this function isn't defined.
+ var iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+
+ iframe.addEventListener('load', function() {
+ var doc = iframe.contentDocument;
+ ok(true, 'frame loaded');
+ testForm(doc, isenvjs);
+ document.body.removeChild(iframe);
+ start();
+ }, false);
+
+ var doc = iframe.contentDocument;
+ doc.write('
');
+ doc.close();
+ stop();
+});
+
+test('Form Named Elements via innerHTML', function() {
+ if ((typeof Envjs == 'undefined') || !Envjs) {
+ Envjs = {};
+ }
+ var iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+
+ iframe.addEventListener('load', function() {
+ var doc = iframe.contentDocument;
+ ok(true, 'frame loaded');
+ var div = doc.getElementById('container');
+ div.innerHTML = '' +
+ '';
+ testForm(doc, isenvjs);
+ document.body.removeChild(iframe);
+ start();
+ }, false);
+
+ var doc = iframe.contentDocument;
+ doc.write('' +
+ '
');
+ doc.close();
+ stop();
+});
+
+test('Form Named Elements via DOMAPI', function() {
+ if ((typeof Envjs == 'undefined') || !Envjs) {
+ Envjs = {};
+ }
+ var iframe = document.createElement("iframe");
+ document.body.appendChild(iframe);
+
+ iframe.addEventListener('load', function() {
+ var doc = iframe.contentDocument;
+ ok(true, 'frame loaded');
+ var div = doc.getElementById('container');
+ var form = doc.createElement('form');
+ var n;
+ form.name = 'foo';
+ div.appendChild(form);
+
+ n = doc.createElement('input');
+ n.name = 'e1';
+ n.value = 'v1';
+ form.appendChild(n);
+
+ n = doc.createElement('input');
+ n.id = 'e2';
+ n.value = 'v2';
+ form.appendChild(n);
+
+ n = doc.createElement('textarea');
+ n.name = 'e3';
+ n.value = 'v3';
+ form.appendChild(n);
+
+ n = doc.createElement('textarea');
+ n.id = 'e4';
+ n.value = 'v4';
+ form.appendChild(n);
+ lastn = n;
+
+ var select = doc.createElement('select');
+ select.name = 'e5';
+ form.appendChild(select);
+
+ var opt = new Option('v5', 'v5', true, true);
+ opt.name ='o1';
+ select.add(opt, null);
+ // select.appendChild(opt);
+
+ opt = new Option('opt2', 'opt2');
+ opt.id = 'o2';
+ select.add(opt, null);
+ //select.appendChild(opt);
+
+ n = doc.createElement('button');
+ n.name = 'e6';
+ n.value = 'v6';
+ form.appendChild(n);
+
+ testForm(doc, isenvjs);
+ document.body.removeChild(iframe);
+ start();
+ }, false);
+
+ var doc = iframe.contentDocument;
+ doc.write('' +
+ '
');
+ doc.close();
+ stop();
+});
diff --git a/src/html/area.js b/src/html/area.js
index 230fa693..37a014cb 100644
--- a/src/html/area.js
+++ b/src/html/area.js
@@ -17,7 +17,7 @@ __extend__(HTMLAreaElement.prototype, {
this.setAttribute('accesskey',value);
},
get alt(){
- return this.getAttribute('alt');
+ return this.getAttribute('alt') || '';
},
set alt(value){
this.setAttribute('alt',value);
diff --git a/src/html/button.js b/src/html/button.js
index 5237ae14..13af0fab 100644
--- a/src/html/button.js
+++ b/src/html/button.js
@@ -17,8 +17,14 @@ __extend__(HTMLButtonElement.prototype, {
set dataFormatAs(value){
this.setAttribute('dataFormatAs',value);
},
+ get type() {
+ return this.getAttribute('type') || 'submit';
+ },
+ set type(value) {
+ this.setAttribute('type', value);
+ },
get value() {
- this.getAttribute('value') || '';
+ return this.getAttribute('value') || '';
},
set value(value) {
this.setAttribute('value', value);
diff --git a/src/html/collection.js b/src/html/collection.js
index 534bd973..eec88cf0 100644
--- a/src/html/collection.js
+++ b/src/html/collection.js
@@ -1,23 +1,23 @@
-
-/* HTML "Collections"
- * http://dev.w3.org/html5/spec/Overview.html#collections
- */
-
/*
- * HTMLCollection - DOM Level 2
- * Implementation Provided by Steven Wood
+ * HTMLCollection
*
* HTML5 -- 2.7.2.1 HTMLCollection
* http://dev.w3.org/html5/spec/Overview.html#htmlcollection
+ * http://dev.w3.org/html5/spec/Overview.html#collections
*/
HTMLCollection = function(nodelist, type) {
__setArray__(this, []);
-
+ var n;
for (var i=0; i= 0) && (idx < this.length)) {
- ret = this[idx];
- }
- return ret;
+ return ((idx >= 0) && (idx < this.length)) ? this[idx] : null;
},
namedItem: function (name) {
- if (name in this) {
- return this[name];
- }
- return null;
+ return this[name] || null;
+ },
+
+ toString: function() {
+ return '[object HTMLCollection]';
}
};
diff --git a/src/html/document.js b/src/html/document.js
index a4f383e6..a56970f6 100644
--- a/src/html/document.js
+++ b/src/html/document.js
@@ -514,16 +514,20 @@ Aspect.around({
__loadLink__(node, node.href);
}
break;
-/*
- case 'img':
- if (node.src && node.src.length > 0){
- // don't actually load anything, so we're "done" immediately:
- event = doc.createEvent('HTMLEvents');
- event.initEvent("load", false, false);
- node.dispatchEvent( event, false );
- }
- break;
+ /*
+ case 'img':
+ if (node.src && node.src.length > 0){
+ // don't actually load anything, so we're "done" immediately:
+ event = doc.createEvent('HTMLEvents');
+ event.initEvent("load", false, false);
+ node.dispatchEvent( event, false );
+ }
+ break;
*/
+ case 'option':
+ console.log("ADD CHILD");
+ node._updateoptions();
+ break;
default:
if(node.getAttribute('onload')){
console.log('calling attribute onload %s | %s', node.onload, node.tagName);
diff --git a/src/html/form.js b/src/html/form.js
index a521cb43..55144a76 100644
--- a/src/html/form.js
+++ b/src/html/form.js
@@ -64,7 +64,7 @@ __extend__(HTMLFormElement.prototype,{
get elements() {
var nodes = this.getElementsByTagName('*');
var alist = [];
- var i;
+ var i, tmp;
for (i = 0; i < nodes.length; ++i) {
nodename = nodes[i].nodeName;
// would like to replace switch with something else
@@ -80,8 +80,13 @@ __extend__(HTMLFormElement.prototype,{
case 'TEXTAREA':
alist.push(nodes[i]);
this[i] = nodes[i];
- if ('name' in nodes[i]) {
- this[nodes[i].name] = nodes[i];
+ tmp = nodes[i].name;
+ if (tmp) {
+ this[tmp] = nodes[i];
+ }
+ tmp = nodes[i].id;
+ if (tmp) {
+ this[tmp] = nodes[i];
}
}
}
@@ -97,7 +102,7 @@ __extend__(HTMLFormElement.prototype,{
return this.elements[idx];
},
namedItem: function(aname) {
- return this.elements[aname];
+ return this.elements.namedItem(aname);
},
toString: function() {
return '[object HTMLFormElement]';
diff --git a/src/html/input-elements.js b/src/html/input-elements.js
index b22e39b8..08302a4b 100644
--- a/src/html/input-elements.js
+++ b/src/html/input-elements.js
@@ -222,24 +222,12 @@ __extend__(HTMLTypeValueInputs.prototype, inputElements_size);
__extend__(HTMLTypeValueInputs.prototype, inputElements_status);
__extend__(HTMLTypeValueInputs.prototype, inputElements_dataProperties);
__extend__(HTMLTypeValueInputs.prototype, {
- get defaultValue(){
- return this.getAttribute('defaultValue');
- },
- set defaultValue(value){
- this.setAttribute('defaultValue', value);
- },
get name(){
return this.getAttribute('name')||'';
},
set name(value){
this.setAttribute('name',value);
},
- get type(){
- return this.getAttribute('type');
- },
- set type(type){
- return this.setAttribute('type', type);
- },
});
diff --git a/src/html/input.js b/src/html/input.js
index fca718be..1a6bb1f0 100644
--- a/src/html/input.js
+++ b/src/html/input.js
@@ -6,7 +6,9 @@
*/
HTMLInputElement = function(ownerDocument) {
HTMLInputAreaCommon.apply(this, arguments);
+ this._dirty = false;
this._checked = null;
+ this._value = null;
};
HTMLInputElement.prototype = new HTMLInputAreaCommon();
__extend__(HTMLInputElement.prototype, {
@@ -47,7 +49,19 @@ __extend__(HTMLInputElement.prototype, {
}
}
},
-
+ get defaultValue() {
+ return this.getAttribute('value') || '';
+ },
+ set defaultValue(value) {
+ this._dirty = true;
+ this.setAttribute('value', value);
+ },
+ get value() {
+ return (this._value === null) ? this.defaultValue : this._value;
+ },
+ set value(newvalue) {
+ this._value = newvalue;
+ },
/**
* Height is a string
*/
@@ -80,6 +94,13 @@ __extend__(HTMLInputElement.prototype, {
this.setAttribute('src', value);
},
+ get type() {
+ return this.getAttribute('type') || 'text';
+ },
+ set type(value) {
+ this.setAttribute('type', value);
+ },
+
get useMap(){
return this.getAttribute('map') || '';
},
@@ -101,17 +122,25 @@ __extend__(HTMLInputElement.prototype, {
}
});
-
//http://dev.w3.org/html5/spec/Overview.html#dom-input-value
-// TODO: needs work, not even clear this is needed and can be moved
-// up into the object
+// if someone directly modifies the value attribute, then the input's value
+// also directly changes.
HTMLElement.registerSetAttribute('INPUT', 'value', function(node, value) {
- //console.log('setting defaultValue (NS)');
- if(!node.defaultValue){
- node.defaultValue = value;
+ if (!node._dirty) {
+ node._value = value;
+ node._dirty = true;
}
});
+/*
+ *The checked content attribute is a boolean attribute that gives the
+ *default checkedness of the input element. When the checked content
+ *attribute is added, if the control does not have dirty checkedness,
+ *the user agent must set the checkedness of the element to true; when
+ *the checked content attribute is removed, if the control does not
+ *have dirty checkedness, the user agent must set the checkedness of
+ *the element to false.
+ */
// Named Element Support
HTMLElement.registerSetAttribute('INPUT', 'name',
__updateFormForNamedElement__);
diff --git a/src/html/option.js b/src/html/option.js
index 33941387..bc31928f 100644
--- a/src/html/option.js
+++ b/src/html/option.js
@@ -6,20 +6,26 @@
*/
HTMLOptionElement = function(ownerDocument) {
HTMLInputCommon.apply(this, arguments);
- this._selected = false;
+ this._selected = null;
};
HTMLOptionElement.prototype = new HTMLInputCommon();
__extend__(HTMLOptionElement.prototype, {
/**
- * defaultSelected actually reflects the 'selected' attribute
- * leaving for now as is.
+ * defaultSelected actually reflects the presence of the
+ * 'selected' attribute.
*/
get defaultSelected() {
- return this.getAttribute('defaultSelected');
+ return this.hasAttribute('selected');
},
set defaultSelected(value) {
- this.setAttribute('defaultSelected',value);
+ if (value) {
+ this.setAttribute('selected','');
+ } else {
+ if (this.hasAttribute('selected')) {
+ this.removeAttribute('selected');
+ }
+ }
},
/*
@@ -31,37 +37,46 @@ __extend__(HTMLOptionElement.prototype, {
* value as the form IDL attribute on that select
* element. Otherwise, it must return null.
*/
- get form() {
+ _selectparent: function() {
var parent = this.parentNode;
if (!parent) {
return null;
}
+
if (parent.tagName === 'SELECT') {
- return parent.form;
+ return parent;
}
if (parent.tagName === 'COLGROUP') {
parent = parent.parentNode;
if (parent && parent.tagName === 'SELECT') {
- return parent.form;
+ return parent;
}
}
- return null;
+ },
+ _updateoptions: function() {
+ var parent = this._selectparent();
+ if (parent) {
+ // has side effects and updates owner select's options
+ parent.options;
+ }
+ },
+ get form() {
+ var parent = this._selectparent();
+ return parent ? parent.form : null;
},
get index() {
- var options = this.parentNode.childNodes,
- index = 0,
- i, opt;
+ var options, i;
- for (i=0; i < options.length; i++) {
- opt = options[i];
- if (opt.nodeType === Node.ELEMENT_NODE && opt.tagName === "OPTION") {
- index++;
- }
- if (this == opt) {
- return index;
+ if (! this.parentNode) {
+ return -1;
+ }
+ options = this.parentNode.options;
+ for (i=0; i < options.length; ++i) {
+ if (this === options[i]) {
+ return i;
}
}
- return -1;
+ return 0;
},
get label() {
return this.getAttribute('label');
@@ -70,48 +85,48 @@ __extend__(HTMLOptionElement.prototype, {
this.setAttribute('label', value);
},
+ /*
+ * This is not in the spec, but safari and firefox both
+ * use this
+ */
+ get name() {
+ return this.getAttribute('name');
+ },
+ set name(value) {
+ this.setAttribute('name', value);
+ },
+
/**
- * TODO: the getters/setters for 'selected' aren't quite right.
- * lots of special cases.
*
- * selected returns an internal state, partially based on the 'selected' attribute
- * but not entirely.
*/
get selected() {
- // if disabled, return false
+ // if disabled, return false, no matter what
+ if (this.disabled) {
+ return false;
+ }
+ if (this._selected === null) {
+ return this.defaultSelected;
+ }
- return (this.getAttribute('selected') === 'selected');
+ return this._selected;
},
set selected(value) {
- // if disabled, ignore? or error?
-
- //console.log('option set selected %s', value);
- if(this.defaultSelected===null && this.selected!==null) {
- this.defaultSelected = this.selected+'';
- }
- var selectedValue = (value ? 'selected' : '');
- if (this.getAttribute('selected') == selectedValue) {
- // prevent inifinite loops (option's selected modifies
- // select's value which modifies option's selected)
- return;
- }
- //console.log('option setAttribute selected %s', selectedValue);
- this.setAttribute('selected', selectedValue);
+ this._selected = (value) ? true : false;
},
get text() {
- return ((this.nodeValue === null) || (this.nodeValue ===undefined)) ?
+ var val = this.nodeValue;
+ return (val === null || this.value === undefined) ?
this.innerHTML :
- this.nodeValue;
+ val;
},
get value() {
- //console.log('getting value on option %s %s', this.text, this.getAttribute('value'));
- return ((this.getAttribute('value') === undefined) || (this.getAttribute('value') === null)) ?
- this.text :
- this.getAttribute('value');
+ var val = this.getAttribute('value');
+ return (val === null || val === undefined) ?
+ this.textContent :
+ val;
},
set value(value) {
- //console.log('setting value on option');
this.setAttribute('value', value);
},
toString: function() {
@@ -141,8 +156,16 @@ Option = function(text, value, defaultSelected, selected) {
}
}
if (arguments.length >= 4) {
- this._selected = (selected) ? true : false;
+ this.selected = (selected) ? true : false;
}
};
Option.prototype = new HTMLOptionElement();
+
+// Named Element Support
+
+function updater(node, value) {
+ node._updateoptions();
+}
+HTMLElement.registerSetAttribute('OPTION', 'name', updater);
+HTMLElement.registerSetAttribute('OPTION', 'id', updater);
diff --git a/src/html/select.js b/src/html/select.js
index 836669fd..b5680cdc 100644
--- a/src/html/select.js
+++ b/src/html/select.js
@@ -1,13 +1,13 @@
/**
- * HTMLSelectElement - DOM Level 2
+ * HTMLSelectElement
* HTML5: http://dev.w3.org/html5/spec/Overview.html#the-select-element
*/
HTMLSelectElement = function(ownerDocument) {
HTMLTypeValueInputs.apply(this, arguments);
-
this._oldIndex = -1;
};
+
HTMLSelectElement.prototype = new HTMLTypeValueInputs();
__extend__(HTMLSelectElement.prototype, inputElements_dataProperties);
__extend__(HTMLButtonElement.prototype, inputElements_size);
@@ -15,63 +15,67 @@ __extend__(HTMLSelectElement.prototype, inputElements_onchange);
__extend__(HTMLSelectElement.prototype, inputElements_focusEvents);
__extend__(HTMLSelectElement.prototype, {
- // over-ride the value setter in HTMLTypeValueInputs
+ get value() {
+ var index = this.selectedIndex;
+ return (index === -1) ? '' : this.options[index].value;
+ },
set value(newValue) {
- //console.log('select set value %s', newValue);
- var options = this.options,
- i, index;
- //console.log('select options length %s', options.length);
- for (i=0; i -1) {
- value = this.options[index].value;
- console.log('select value %s', value);
- return value;
- } else {
- //console.log('select value ""');
- return '';
+ // Returns HTMLOptionsCollection
+ get options() {
+ var nodes = this.getElementsByTagName('option');
+ var alist = [];
+ var i, tmp;
+ for (i = 0; i < nodes.length; ++i) {
+ alist.push(nodes[i]);
+ this[i] = nodes[i];
+ tmp = nodes[i].name;
+ if (tmp) {
+ this[tmp] = nodes[i];
+ }
+ tmp = nodes[i].id;
+ if (tmp) {
+ this[tmp] = nodes[i];
}
- } else {
- return value;
}
+ return new HTMLCollection(alist);
},
get length() {
return this.options.length;
},
- get multiple() {
- return this.getAttribute('multiple');
- },
- set multiple(value) {
- this.setAttribute('multiple',value);
+ item: function(idx) {
+ return this.options[idx];
},
- // Returns HTMLOptionsCollection
- get options() {
- return this.getElementsByTagName('option');
+ namedItem: function(aname) {
+ return this.options[aname];
},
+
get selectedIndex() {
- //console.log('select get selectedIndex ');
var options = this.options;
- for(var i=0;i