Bug 1507895 - Part II, Remove the datetimebox binding r=smaug

This patch removes the datetimebox binding and always use
UA Widget for the job.

Depends on D17571

Differential Revision: https://phabricator.services.mozilla.com/D17572

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Timothy Guan-tin Chien 2019-01-28 18:32:39 +00:00
Родитель d59f80985c
Коммит ccf133638c
51 изменённых файлов: 61 добавлений и 11485 удалений

Просмотреть файл

@ -52,7 +52,6 @@
#include "nsError.h" #include "nsError.h"
#include "nsIEditor.h" #include "nsIEditor.h"
#include "nsAttrValueOrString.h" #include "nsAttrValueOrString.h"
#include "nsDateTimeControlFrame.h"
#include "mozilla/PresState.h" #include "mozilla/PresState.h"
#include "nsLinebreakConverter.h" //to strip out carriage returns #include "nsLinebreakConverter.h" //to strip out carriage returns
@ -2057,28 +2056,22 @@ void HTMLInputElement::GetDateTimeInputBoxValue(DateTimeValue& aValue) {
aValue = *mDateTimeInputBoxValue; aValue = *mDateTimeInputBoxValue;
} }
Element* HTMLInputElement::GetDateTimeBoxElementInUAWidget() { Element* HTMLInputElement::GetDateTimeBoxElement() {
if (GetShadowRoot()) { if (!GetShadowRoot()) {
// The datetimebox <div> is the only child of the UA Widget Shadow Root return nullptr;
// if it is present. }
MOZ_ASSERT(GetShadowRoot()->IsUAWidget());
MOZ_ASSERT(1 >= GetShadowRoot()->GetChildCount()); // The datetimebox <div> is the only child of the UA Widget Shadow Root
if (nsIContent* inputAreaContent = GetShadowRoot()->GetFirstChild()) { // if it is present.
return inputAreaContent->AsElement(); MOZ_ASSERT(GetShadowRoot()->IsUAWidget());
} MOZ_ASSERT(1 >= GetShadowRoot()->GetChildCount());
if (nsIContent* inputAreaContent = GetShadowRoot()->GetFirstChild()) {
return inputAreaContent->AsElement();
} }
return nullptr; return nullptr;
} }
Element* HTMLInputElement::GetDateTimeBoxElement() {
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame && frame->GetInputAreaContent()) {
return frame->GetInputAreaContent()->AsElement();
}
return GetDateTimeBoxElementInUAWidget();
}
void HTMLInputElement::OpenDateTimePicker(const DateTimeValue& aInitialValue) { void HTMLInputElement::OpenDateTimePicker(const DateTimeValue& aInitialValue) {
if (NS_WARN_IF(!IsDateTimeInputType(mType))) { if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
return; return;
@ -2634,17 +2627,12 @@ nsresult HTMLInputElement::SetValueInternal(const nsAString& aValue,
mType == NS_FORM_INPUT_DATE) && mType == NS_FORM_INPUT_DATE) &&
!IsExperimentalMobileType(mType) && !IsExperimentalMobileType(mType) &&
!(aFlags & nsTextEditorState::eSetValue_BySetUserInput)) { !(aFlags & nsTextEditorState::eSetValue_BySetUserInput)) {
if (Element* dateTimeBoxElement = GetDateTimeBoxElementInUAWidget()) { if (Element* dateTimeBoxElement = GetDateTimeBoxElement()) {
AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher( AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
dateTimeBoxElement, dateTimeBoxElement,
NS_LITERAL_STRING("MozDateTimeValueChanged"), CanBubble::eNo, NS_LITERAL_STRING("MozDateTimeValueChanged"), CanBubble::eNo,
ChromeOnlyDispatch::eNo); ChromeOnlyDispatch::eNo);
dispatcher->RunDOMEventWhenSafe(); dispatcher->RunDOMEventWhenSafe();
} else {
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->OnValueChanged();
}
} }
} }
if (mDoneCreating) { if (mDoneCreating) {
@ -2931,18 +2919,12 @@ void HTMLInputElement::Blur(ErrorResult& aError) {
if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) && if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
!IsExperimentalMobileType(mType)) { !IsExperimentalMobileType(mType)) {
if (Element* dateTimeBoxElement = GetDateTimeBoxElementInUAWidget()) { if (Element* dateTimeBoxElement = GetDateTimeBoxElement()) {
AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher( AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
dateTimeBoxElement, NS_LITERAL_STRING("MozBlurInnerTextBox"), dateTimeBoxElement, NS_LITERAL_STRING("MozBlurInnerTextBox"),
CanBubble::eNo, ChromeOnlyDispatch::eNo); CanBubble::eNo, ChromeOnlyDispatch::eNo);
dispatcher->RunDOMEventWhenSafe(); dispatcher->RunDOMEventWhenSafe();
return; return;
} else {
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->HandleBlurEvent();
return;
}
} }
} }
@ -2965,18 +2947,12 @@ void HTMLInputElement::Focus(ErrorResult& aError) {
if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) && if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
!IsExperimentalMobileType(mType)) { !IsExperimentalMobileType(mType)) {
if (Element* dateTimeBoxElement = GetDateTimeBoxElementInUAWidget()) { if (Element* dateTimeBoxElement = GetDateTimeBoxElement()) {
AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher( AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
dateTimeBoxElement, NS_LITERAL_STRING("MozFocusInnerTextBox"), dateTimeBoxElement, NS_LITERAL_STRING("MozFocusInnerTextBox"),
CanBubble::eNo, ChromeOnlyDispatch::eNo); CanBubble::eNo, ChromeOnlyDispatch::eNo);
dispatcher->RunDOMEventWhenSafe(); dispatcher->RunDOMEventWhenSafe();
return; return;
} else {
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->HandleFocusEvent();
return;
}
} }
} }
@ -3285,16 +3261,11 @@ void HTMLInputElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
aVisitor.mEvent->mOriginalTarget == this) { aVisitor.mEvent->mOriginalTarget == this) {
// If original target is this and not the inner text control, we should // If original target is this and not the inner text control, we should
// pass the focus to the inner text control. // pass the focus to the inner text control.
if (Element* dateTimeBoxElement = GetDateTimeBoxElementInUAWidget()) { if (Element* dateTimeBoxElement = GetDateTimeBoxElement()) {
AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher( AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
dateTimeBoxElement, NS_LITERAL_STRING("MozFocusInnerTextBox"), dateTimeBoxElement, NS_LITERAL_STRING("MozFocusInnerTextBox"),
CanBubble::eNo, ChromeOnlyDispatch::eNo); CanBubble::eNo, ChromeOnlyDispatch::eNo);
dispatcher->RunDOMEventWhenSafe(); dispatcher->RunDOMEventWhenSafe();
} else {
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->HandleFocusEvent();
}
} }
} }
@ -4370,7 +4341,7 @@ nsresult HTMLInputElement::BindToTree(Document* aDocument, nsIContent* aParent,
UpdateState(false); UpdateState(false);
if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) && if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
nsContentUtils::IsUAWidgetEnabled() && IsInComposedDoc()) { IsInComposedDoc()) {
// Construct Shadow Root so web content can be hidden in the DOM. // Construct Shadow Root so web content can be hidden in the DOM.
AttachAndSetUAShadowRoot(); AttachAndSetUAShadowRoot();
NotifyUAWidgetSetupOrChange(); NotifyUAWidgetSetupOrChange();
@ -4403,7 +4374,7 @@ void HTMLInputElement::UnbindFromTree(bool aDeep, bool aNullParent) {
} }
if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) && if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
nsContentUtils::IsUAWidgetEnabled() && IsInComposedDoc()) { IsInComposedDoc()) {
NotifyUAWidgetTeardown(); NotifyUAWidgetTeardown();
} }
@ -4582,7 +4553,7 @@ void HTMLInputElement::HandleTypeChange(uint8_t aNewType, bool aNotify) {
dispatcher->PostDOMEvent(); dispatcher->PostDOMEvent();
} }
if (nsContentUtils::IsUAWidgetEnabled() && IsInComposedDoc()) { if (IsInComposedDoc()) {
if (oldType == NS_FORM_INPUT_TIME || oldType == NS_FORM_INPUT_DATE) { if (oldType == NS_FORM_INPUT_TIME || oldType == NS_FORM_INPUT_DATE) {
if (mType != NS_FORM_INPUT_TIME && mType != NS_FORM_INPUT_DATE) { if (mType != NS_FORM_INPUT_TIME && mType != NS_FORM_INPUT_DATE) {
// Switch away from date/time type. // Switch away from date/time type.

Просмотреть файл

@ -747,18 +747,9 @@ class HTMLInputElement final : public nsGenericHTMLFormElementWithState,
*/ */
void GetDateTimeInputBoxValue(DateTimeValue& aValue); void GetDateTimeInputBoxValue(DateTimeValue& aValue);
/*
* This locates the inner datetimebox UA Widget element and only the
* UA Widget
* element. This should fold into GetDateTimeBoxElement() when the XBL binding
* is removed.
*/
Element* GetDateTimeBoxElementInUAWidget();
/* /*
* This allows chrome JavaScript to dispatch event to the inner datetimebox * This allows chrome JavaScript to dispatch event to the inner datetimebox
* anonymous or UA Widget element and access nsIDateTimeInputArea * anonymous or UA Widget element.
* implementation.
*/ */
Element* GetDateTimeBoxElement(); Element* GetDateTimeBoxElement();

Просмотреть файл

@ -9,7 +9,6 @@
#include "js/Date.h" #include "js/Date.h"
#include "mozilla/AsyncEventDispatcher.h" #include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/HTMLInputElement.h" #include "mozilla/dom/HTMLInputElement.h"
#include "nsDateTimeControlFrame.h"
#include "nsDOMTokenList.h" #include "nsDOMTokenList.h"
const double DateTimeInputTypeBase::kMinimumYear = 1; const double DateTimeInputTypeBase::kMinimumYear = 1;
@ -100,19 +99,13 @@ bool DateTimeInputTypeBase::HasStepMismatch(bool aUseZeroIfValueNaN) const {
} }
bool DateTimeInputTypeBase::HasBadInput() const { bool DateTimeInputTypeBase::HasBadInput() const {
Element* editWrapperElement = nullptr; if (!mInputElement->GetShadowRoot()) {
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame()); return false;
if (frame && frame->GetInputAreaContent()) {
// edit-wrapper is inside an XBL binding
editWrapperElement =
mInputElement->GetComposedDoc()->GetAnonymousElementByAttribute(
frame->GetInputAreaContent(), nsGkAtoms::anonid,
NS_LITERAL_STRING("edit-wrapper"));
} else if (mInputElement->GetShadowRoot()) {
// edit-wrapper is inside an UA Widget Shadow DOM
editWrapperElement = mInputElement->GetShadowRoot()->GetElementById(
NS_LITERAL_STRING("edit-wrapper"));
} }
Element* editWrapperElement = mInputElement->GetShadowRoot()->GetElementById(
NS_LITERAL_STRING("edit-wrapper"));
if (!editWrapperElement) { if (!editWrapperElement) {
return false; return false;
} }
@ -159,17 +152,11 @@ nsresult DateTimeInputTypeBase::GetRangeUnderflowMessage(nsAString& aMessage) {
} }
nsresult DateTimeInputTypeBase::MinMaxStepAttrChanged() { nsresult DateTimeInputTypeBase::MinMaxStepAttrChanged() {
if (Element* dateTimeBoxElement = if (Element* dateTimeBoxElement = mInputElement->GetDateTimeBoxElement()) {
mInputElement->GetDateTimeBoxElementInUAWidget()) {
AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher( AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
dateTimeBoxElement, NS_LITERAL_STRING("MozNotifyMinMaxStepAttrChanged"), dateTimeBoxElement, NS_LITERAL_STRING("MozNotifyMinMaxStepAttrChanged"),
CanBubble::eNo, ChromeOnlyDispatch::eNo); CanBubble::eNo, ChromeOnlyDispatch::eNo);
dispatcher->RunDOMEventWhenSafe(); dispatcher->RunDOMEventWhenSafe();
} else {
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
if (frame) {
frame->OnMinMaxStepAttrChanged();
}
} }
return NS_OK; return NS_OK;

Просмотреть файл

@ -11,20 +11,17 @@ DIRS += ['input']
MOCHITEST_MANIFESTS += [ MOCHITEST_MANIFESTS += [
'test/forms/mochitest.ini', 'test/forms/mochitest.ini',
'test/forms/xbl/mochitest.ini',
'test/mochitest.ini', 'test/mochitest.ini',
] ]
MOCHITEST_CHROME_MANIFESTS += [ MOCHITEST_CHROME_MANIFESTS += [
'test/chrome.ini', 'test/chrome.ini',
'test/forms/chrome.ini', 'test/forms/chrome.ini',
'test/forms/xbl/chrome.ini',
] ]
BROWSER_CHROME_MANIFESTS += ['test/browser.ini'] BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
XPIDL_SOURCES += [ XPIDL_SOURCES += [
'nsIDateTimeInputArea.idl',
'nsIFormSubmitObserver.idl', 'nsIFormSubmitObserver.idl',
'nsIImageDocument.idl', 'nsIImageDocument.idl',
'nsIMenuBuilder.idl', 'nsIMenuBuilder.idl',

Просмотреть файл

@ -1,49 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
[scriptable, uuid(465c0cc3-24cb-48ce-af1a-b18402326b05)]
interface nsIDateTimeInputArea : nsISupports
{
/**
* Called from DOM/Layout when input element value has changed.
*/
void notifyInputElementValueChanged();
/**
* Called from DOM/Layout when input element min, max or step attribute has
* changed.
*/
void notifyMinMaxStepAttrChanged();
/**
* Called when date/time picker value has changed.
*/
void setValueFromPicker(in jsval value);
/**
* Called from DOM/Layout to set focus on inner text box.
*/
void focusInnerTextBox();
/**
* Called from DOM/Layout to blur inner text box.
*/
void blurInnerTextBox();
/**
* Set the current state of the picker, true if it's opened, false otherwise.
*/
void setPickerState(in boolean isOpen);
/**
* Update the attribute of the inner text boxes by copying the attribute value
* from the input. Only values set to "tabindex", "readonly",
* and "disabled" attributes are copied.
*/
void updateEditAttributes();
};

Просмотреть файл

@ -1,4 +0,0 @@
[DEFAULT]
prefs = dom.ua_widget.enabled=false
[test_autocompleteinfo.html]

Просмотреть файл

@ -1,40 +0,0 @@
[DEFAULT]
prefs =
dom.ua_widget.enabled=false
support-files =
!/dom/html/test/reflect.js
../FAIL.html
../PASS.html
[test_input_attributes_reflection.html]
[test_input_date_bad_input.html]
[test_input_date_key_events.html]
[test_input_datetime_input_change_events.html]
[test_input_datetime_focus_blur.html]
[test_input_datetime_focus_blur_events.html]
[test_input_datetime_focus_state.html]
[test_input_datetime_tabindex.html]
[test_input_defaultValue.html]
[test_input_sanitization.html]
skip-if = os == 'android' && debug # Extremely slow on debug android
[test_input_textarea_set_value_no_scroll.html]
[test_input_time_key_events.html]
[test_input_time_sec_millisec_field.html]
[test_input_types_pref.html]
[test_input_typing_sanitization.html]
skip-if = os == "android" && debug # bug 1397615
[test_label_input_controls.html]
[test_max_attribute.html]
[test_min_attribute.html]
[test_mozistextfield.html]
[test_novalidate_attribute.html]
[test_pattern_attribute.html]
[test_required_attribute.html]
[test_step_attribute.html]
[test_stepup_stepdown.html]
[test_textarea_attributes_reflection.html]
[test_validation.html]
[test_valueAsDate_pref.html]
[test_valueasdate_attribute.html]
[test_valueasnumber_attribute.html]
[test_validation_not_in_doc.html]

Просмотреть файл

@ -1,171 +0,0 @@
<!DOCTYPE html>
<html>
<!--
Test getAutocompleteInfo() on <input> and <select>
-->
<head>
<title>Test for getAutocompleteInfo()</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/AddTask.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
<form>
<input id="input"/>
<select id="select" />
</form>
</div>
<pre id="test">
<script>
"use strict";
var values = [
// Missing or empty attribute
[undefined, {}, ""],
["", {}, ""],
// One token
["on", {fieldName: "on" }, "on"],
["On", {fieldName: "on" }, "on"],
["off", {fieldName: "off" }, "off" ],
["name", {fieldName: "name" }, "name"],
[" name ", {fieldName: "name" }, "name"],
["username", {fieldName: "username"}, ""],
[" username ", {fieldName: "username"}, ""],
["cc-csc", {fieldName: "cc-csc"}, ""],
["language", {fieldName: "language"}, ""],
["tel-extension", {fieldName: "tel-extension"}, ""],
["foobar", {}, ""],
["section-blue", {}, ""],
// Two tokens
["on off", {}, ""],
["off on", {}, ""],
["username tel", {}, ""],
["tel username ", {}, ""],
[" username tel ", {}, ""],
["tel mobile", {}, ""],
["tel shipping", {}, ""],
["shipping tel", {addressType: "shipping", fieldName: "tel"}, "shipping tel"],
["shipPING tel", {addressType: "shipping", fieldName: "tel"}, "shipping tel"],
["mobile tel", {contactType: "mobile", fieldName: "tel"}, "mobile tel"],
[" MoBiLe TeL ", {contactType: "mobile", fieldName: "tel"}, "mobile tel"],
["pager impp", {contactType: "pager", fieldName: "impp"}, ""],
["fax tel-extension", {contactType: "fax", fieldName: "tel-extension"}, ""],
["XXX tel", {}, ""],
["XXX username", {}, ""],
["name section-blue", {}, ""],
["scetion-blue cc-name", {}, ""],
["pager language", {}, ""],
["fax url", {}, ""],
["section-blue name", {section: "section-blue", fieldName: "name"}, "section-blue name"],
["section-blue tel", {section: "section-blue", fieldName: "tel"}, "section-blue tel"],
// Three tokens
["billing invalid tel", {}, ""],
["___ mobile tel", {}, ""],
["mobile foo tel", {}, ""],
["mobile tel foo", {}, ""],
["tel mobile billing", {}, ""],
["billing mobile tel", {addressType: "billing", contactType: "mobile", fieldName: "tel"}, "billing mobile tel"],
[" BILLing MoBiLE tEl ", {addressType: "billing", contactType: "mobile", fieldName: "tel"}, "billing mobile tel"],
["billing home tel", {addressType: "billing", contactType: "home", fieldName: "tel"}, "billing home tel"],
["home section-blue tel", {}, ""],
["setion-blue work email", {}, ""],
["section-blue home address-level2", {}, ""],
["section-blue shipping name", {section: "section-blue", addressType: "shipping", fieldName: "name"}, "section-blue shipping name"],
["section-blue mobile tel", {section: "section-blue", contactType: "mobile", fieldName: "tel"}, "section-blue mobile tel"],
// Four tokens
["billing billing mobile tel", {}, ""],
["name section-blue shipping home", {}, ""],
["secti shipping work address-line1", {}, ""],
["section-blue shipping home name", {}, ""],
["section-blue shipping mobile tel", {section: "section-blue", addressType: "shipping", contactType: "mobile", fieldName: "tel"}, "section-blue shipping mobile tel"],
// Five tokens (invalid)
["billing billing billing mobile tel", {}, ""],
["section-blue section-blue billing mobile tel", {}, ""],
];
var autocompleteInfoFieldIds = ["input", "select"];
var autocompleteEnabledTypes = ["hidden", "text", "search", "url", "tel",
"email", "password", "date", "time", "number",
"range", "color"];
var autocompleteDisabledTypes = ["reset", "submit", "image", "button", "radio",
"checkbox", "file"];
function testInputTypes() {
let field = document.getElementById("input");
for (var type of autocompleteEnabledTypes) {
testAutocomplete(field, type, true);
}
for (var type of autocompleteDisabledTypes) {
testAutocomplete(field, type, false);
}
// Clear input type attribute.
field.removeAttribute("type");
}
function testAutocompleteInfoValue(aEnabled) {
for (var fieldId of autocompleteInfoFieldIds) {
let field = document.getElementById(fieldId);
for (var test of values) {
if (typeof(test[0]) === "undefined")
field.removeAttribute("autocomplete");
else
field.setAttribute("autocomplete", test[0]);
var info = field.getAutocompleteInfo();
if (aEnabled) {
// We need to consider if getAutocompleteInfo() is valid,
// but @autocomplete is invalid case, because @autocomplete
// has smaller set of values.
is(field.autocomplete, test[2], "Checking @autocomplete of: " + test[0]);
}
is(info.section, "section" in test[1] ? test[1].section : "",
"Checking autocompleteInfo.section for " + field + ": " + test[0]);
is(info.addressType, "addressType" in test[1] ? test[1].addressType : "",
"Checking autocompleteInfo.addressType for " + field + ": " + test[0]);
is(info.contactType, "contactType" in test[1] ? test[1].contactType : "",
"Checking autocompleteInfo.contactType for " + field + ": " + test[0]);
is(info.fieldName, "fieldName" in test[1] ? test[1].fieldName : "",
"Checking autocompleteInfo.fieldName for " + field + ": " + test[0]);
}
}
}
function testAutocomplete(aField, aType, aEnabled) {
aField.type = aType;
if (aEnabled) {
ok(aField.getAutocompleteInfo() !== null, "getAutocompleteInfo shouldn't return null");
} else {
is(aField.getAutocompleteInfo(), null, "getAutocompleteInfo should return null");
}
}
// getAutocompleteInfo() should be able to parse all tokens as defined
// in the spec regardless of whether dom.forms.autocomplete.formautofill pref
// is on or off.
add_task(async function testAutocompletePreferenceEnabled() {
await SpecialPowers.pushPrefEnv({"set": [["dom.forms.autocomplete.formautofill", true]]}, testInputTypes);
testAutocompleteInfoValue(true);
});
add_task(async function testAutocompletePreferenceDisabled() {
await SpecialPowers.pushPrefEnv({"set": [["dom.forms.autocomplete.formautofill", false]]}, testInputTypes);
testAutocompleteInfoValue(false);
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,279 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for HTMLInputElement attributes reflection</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="../../reflect.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for HTMLInputElement attributes reflection **/
// TODO: maybe make those reflections be tested against all input types.
function testWidthHeight(attr) {
var element = document.createElement('input');
is(element[attr], 0, attr + ' always returns 0 if not type=image');
element.setAttribute(attr, '42');
is(element[attr], 0, attr + ' always returns 0 if not type=image');
is(element.getAttribute(attr), '42');
element[attr] = 0;
is(element.getAttribute(attr), '0', 'setting ' + attr + ' changes the content attribute');
element[attr] = 12;
is(element.getAttribute(attr), '12', 'setting ' + attr + ' changes the content attribute');
element.removeAttribute(attr);
is(element.getAttribute(attr), null);
element = document.createElement('input');
element.type = 'image';
document.getElementById('content').appendChild(element);
isnot(element[attr], 0, attr + ' represents the dimension of the element if type=image');
element.setAttribute(attr, '42');
isnot(element[attr], 0, attr + ' represents the dimension of the element if type=image');
isnot(element[attr], 42, attr + ' represents the dimension of the element if type=image');
is(element.getAttribute(attr), '42');
element[attr] = 0;
is(element.getAttribute(attr), '0', 'setting ' + attr + ' changes the content attribute');
element[attr] = 12;
is(element.getAttribute(attr), '12', 'setting ' + attr + ' changes the content attribute');
element.removeAttribute(attr);
is(element.getAttribute(attr), null);
}
// .accept
reflectString({
element: document.createElement("input"),
attribute: "accept",
otherValues: [ "audio/*", "video/*", "image/*", "image/png",
"application/msword", "appplication/pdf" ],
});
// .alt
reflectString({
element: document.createElement("input"),
attribute: "alt",
});
// .autocomplete
reflectLimitedEnumerated({
element: document.createElement("input"),
attribute: "autocomplete",
validValues: [ "on", "off" ],
invalidValues: [ "", "default", "foo", "tulip" ],
});
// .autofocus
reflectBoolean({
element: document.createElement("input"),
attribute: "autofocus",
});
// .defaultChecked
reflectBoolean({
element: document.createElement("input"),
attribute: { idl: "defaultChecked", content: "checked" },
});
// .checked doesn't reflect a content attribute.
// .dirName
todo("dirName" in document.createElement("input"),
"dirName isn't implemented yet");
// .disabled
reflectBoolean({
element: document.createElement("input"),
attribute: "disabled",
});
// TODO: form (HTMLFormElement)
// TODO: files (FileList)
// .formAction
reflectURL({
element: document.createElement("button"),
attribute: "formAction",
});
// .formEnctype
reflectLimitedEnumerated({
element: document.createElement("input"),
attribute: "formEnctype",
validValues: [ "application/x-www-form-urlencoded", "multipart/form-data",
"text/plain" ],
invalidValues: [ "", "foo", "tulip", "multipart/foo" ],
defaultValue: { invalid: "application/x-www-form-urlencoded", missing: "" }
});
// .formMethod
reflectLimitedEnumerated({
element: document.createElement("input"),
attribute: "formMethod",
validValues: [ "get", "post" ],
invalidValues: [ "", "foo", "tulip" ],
defaultValue: { invalid: "get", missing: "" }
});
// .formNoValidate
reflectBoolean({
element: document.createElement("input"),
attribute: "formNoValidate",
});
// .formTarget
reflectString({
element: document.createElement("input"),
attribute: "formTarget",
otherValues: [ "_blank", "_self", "_parent", "_top" ],
});
// .height
testWidthHeight('height');
// .indeterminate doesn't reflect a content attribute.
// .inputmode
if (SpecialPowers.getBoolPref("dom.forms.inputmode")) {
reflectLimitedEnumerated({
element: document.createElement("input"),
attribute: "inputMode",
validValues: [ "numeric", "digit", "uppercase", "lowercase", "titlecase", "autocapitalized", "auto" ],
invalidValues: [ "", "foo", "tulip" ],
defaultValue: "auto"
});
}
// TODO: list (HTMLElement)
// .max
reflectString({
element: document.createElement('input'),
attribute: 'max',
});
// .maxLength
reflectInt({
element: document.createElement("input"),
attribute: "maxLength",
nonNegative: true,
});
// .min
reflectString({
element: document.createElement('input'),
attribute: 'min',
});
// .multiple
reflectBoolean({
element: document.createElement("input"),
attribute: "multiple",
});
// .name
reflectString({
element: document.createElement("input"),
attribute: "name",
otherValues: [ "isindex", "_charset_" ],
});
// .pattern
reflectString({
element: document.createElement("input"),
attribute: "pattern",
otherValues: [ "[0-9][A-Z]{3}" ],
});
// .placeholder
reflectString({
element: document.createElement("input"),
attribute: "placeholder",
otherValues: [ "foo\nbar", "foo\rbar", "foo\r\nbar" ],
});
// .readOnly
reflectBoolean({
element: document.createElement("input"),
attribute: "readOnly",
});
// .required
reflectBoolean({
element: document.createElement("input"),
attribute: "required",
});
// .size
reflectUnsignedInt({
element: document.createElement("input"),
attribute: "size",
nonZero: true,
defaultValue: 20,
});
// .src (URL)
reflectURL({
element: document.createElement('input'),
attribute: 'src',
});
// .step
reflectString({
element: document.createElement('input'),
attribute: 'step',
});
// .type
reflectLimitedEnumerated({
element: document.createElement("input"),
attribute: "type",
validValues: [ "hidden", "text", "search", "tel", "url", "email", "password",
"checkbox", "radio", "file", "submit", "image", "reset",
"button", "date", "time", "number", "range", "color", "month",
"week", "datetime-local" ],
invalidValues: [ "this-is-probably-a-wrong-type", "", "tulip" ],
defaultValue: "text"
});
// .defaultValue
reflectString({
element: document.createElement("input"),
attribute: { idl: "defaultValue", content: "value" },
otherValues: [ "foo\nbar", "foo\rbar", "foo\r\nbar" ],
});
// .value doesn't reflect a content attribute.
// .valueAsDate
is("valueAsDate" in document.createElement("input"), true,
"valueAsDate should be available");
// Deeper check will be done with bug 763305.
is('valueAsNumber' in document.createElement("input"), true,
"valueAsNumber should be available");
// .selectedOption
todo("selectedOption" in document.createElement("input"),
"selectedOption isn't implemented yet");
// .width
testWidthHeight('width');
// .willValidate doesn't reflect a content attribute.
// .validity doesn't reflect a content attribute.
// .validationMessage doesn't reflect a content attribute.
// .labels doesn't reflect a content attribute.
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,108 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1372369
-->
<head>
<title>Test for &lt;input type='date'&gt; bad input validity state</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
input { background-color: rgb(0,0,0) !important; }
:valid { background-color: rgb(0,255,0) !important; }
:invalid { background-color: rgb(255,0,0) !important; }
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1372369">Mozilla Bug 1372369</a>
<p id="display"></p>
<div id="content">
<form>
<input type="date" id="input">
<form>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for <input type='date'> bad input validity state **/
SimpleTest.waitForExplicitFinish();
// Turn off Spatial Navigation because it hijacks arrow keydown events:
SimpleTest.waitForFocus(function() {
SpecialPowers.pushPrefEnv({"set":[["snav.enabled", false]]}, function() {
test();
SimpleTest.finish();
});
});
const DATE_BAD_INPUT_MSG = "Please enter a valid date.";
const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
function checkValidity(aElement, aIsBadInput) {
is(aElement.validity.valid, aIsBadInput ? false : true,
"validity.valid should be " + (aIsBadInput ? "false" : "true"));
is(aElement.validity.badInput, aIsBadInput ? true : false,
"validity.badInput should be " + (aIsBadInput ? "true" : "false"));
is(aElement.validationMessage, aIsBadInput ? DATE_BAD_INPUT_MSG : "",
"validationMessage should be: " + (aIsBadInput ? DATE_BAD_INPUT_MSG : ""));
is(window.getComputedStyle(aElement).getPropertyValue('background-color'),
aIsBadInput ? "rgb(255, 0, 0)" : "rgb(0, 255, 0)",
(aIsBadInput ? ":invalid" : "valid") + " pseudo-classs should apply");
}
function sendKeys(aKey) {
if (aKey.startsWith("KEY_")) {
synthesizeKey(aKey);
} else {
sendString(aKey);
}
}
function test() {
var elem = document.getElementById("input");
var inputRect = input.getBoundingClientRect();
// Points over the input's reset button
var resetButton_X = inputRect.width - 15;
var resetButton_Y = inputRect.height / 2;
elem.focus();
sendKeys("02312017");
elem.blur();
checkValidity(elem, true);
elem.focus();
sendKeys("02292016");
elem.blur();
checkValidity(elem, false);
elem.focus();
sendKeys("06312000");
elem.blur();
checkValidity(elem, true);
// Removing any of the fields makes the input valid again.
elem.focus();
sendKeys("KEY_Backspace");
elem.blur();
checkValidity(elem, false);
elem.focus();
sendKeys("02292017");
elem.blur();
checkValidity(elem, true);
// Reset button is desktop only.
if (isDesktop) {
// Clearing all fields should clear bad input validity state as well.
synthesizeMouse(input, resetButton_X, resetButton_Y, {});
checkValidity(elem, false);
}
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,243 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1286182
-->
<head>
<title>Test key events for time control</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta charset="UTF-8">
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1286182">Mozilla Bug 1286182</a>
<p id="display"></p>
<div id="content">
<input id="input" type="date">
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
// Turn off Spatial Navigation because it hijacks arrow keydown events:
SimpleTest.waitForFocus(function() {
SpecialPowers.pushPrefEnv({"set":[["snav.enabled", false]]}, function() {
test();
SimpleTest.finish();
});
});
var testData = [
/**
* keys: keys to send to the input element.
* initialVal: initial value set to the input element.
* expectedVal: expected value of the input element after sending the keys.
*/
{
// Type 11222016, default order is month, day, year.
keys: ["11222016"],
initialVal: "",
expectedVal: "2016-11-22"
},
{
// Type 3 in the month field will automatically advance to the day field,
// then type 5 in the day field will automatically advance to the year
// field.
keys: ["352016"],
initialVal: "",
expectedVal: "2016-03-05"
},
{
// Type 13 in the month field will set it to the maximum month, which is
// 12.
keys: ["13012016"],
initialVal: "",
expectedVal: "2016-12-01"
},
{
// Type 00 in the month field will set it to the minimum month, which is 1.
keys: ["00012016"],
initialVal: "",
expectedVal: "2016-01-01"
},
{
// Type 33 in the day field will set it to the maximum day, which is 31.
keys: ["12332016"],
initialVal: "",
expectedVal: "2016-12-31"
},
{
// Type 00 in the day field will set it to the minimum day, which is 1.
keys: ["12002016"],
initialVal: "",
expectedVal: "2016-12-01"
},
{
// Type 275769 in the year field will set it to the maximum year, which is
// 275760.
keys: ["0101275769"],
initialVal: "",
expectedVal: "275760-01-01"
},
{
// Type 000000 in the year field will set it to the minimum year, which is
// 0001.
keys: ["0101000000"],
initialVal: "",
expectedVal: "0001-01-01"
},
{
// Advance to year field and decrement.
keys: ["KEY_Tab", "KEY_Tab", "KEY_ArrowDown"],
initialVal: "2016-11-25",
expectedVal: "2015-11-25"
},
{
// Right key should do the same thing as TAB key.
keys: ["KEY_ArrowRight", "KEY_ArrowRight", "KEY_ArrowDown"],
initialVal: "2016-11-25",
expectedVal: "2015-11-25"
},
{
// Advance to day field then back to month field and decrement.
keys: ["KEY_ArrowRight", "KEY_ArrowLeft", "KEY_ArrowDown"],
initialVal: "2000-05-01",
expectedVal: "2000-04-01"
},
{
// Focus starts on the first field, month in this case, and increment.
keys: ["KEY_ArrowUp"],
initialVal: "2000-03-01",
expectedVal: "2000-04-01"
},
{
// Advance to day field and decrement.
keys: ["KEY_Tab", "KEY_ArrowDown"],
initialVal: "1234-01-01",
expectedVal: "1234-01-31"
},
{
// Advance to day field and increment.
keys: ["KEY_Tab", "KEY_ArrowUp"],
initialVal: "1234-01-01",
expectedVal: "1234-01-02"
},
{
// PageUp on month field increments month by 3.
keys: ["KEY_PageUp"],
initialVal: "1999-01-01",
expectedVal: "1999-04-01"
},
{
// PageDown on month field decrements month by 3.
keys: ["KEY_PageDown"],
initialVal: "1999-01-01",
expectedVal: "1999-10-01"
},
{
// PageUp on day field increments day by 7.
keys: ["KEY_Tab", "KEY_PageUp"],
initialVal: "1999-01-01",
expectedVal: "1999-01-08"
},
{
// PageDown on day field decrements day by 7.
keys: ["KEY_Tab", "KEY_PageDown"],
initialVal: "1999-01-01",
expectedVal: "1999-01-25"
},
{
// PageUp on year field increments year by 10.
keys: ["KEY_Tab", "KEY_Tab", "KEY_PageUp"],
initialVal: "1999-01-01",
expectedVal: "2009-01-01"
},
{
// PageDown on year field decrements year by 10.
keys: ["KEY_Tab", "KEY_Tab", "KEY_PageDown"],
initialVal: "1999-01-01",
expectedVal: "1989-01-01"
},
{
// Home key on month field sets it to the minimum month, which is 01.
keys: ["KEY_Home"],
initialVal: "2016-06-01",
expectedVal: "2016-01-01"
},
{
// End key on month field sets it to the maximum month, which is 12.
keys: ["KEY_End"],
initialVal: "2016-06-01",
expectedVal: "2016-12-01"
},
{
// Home key on day field sets it to the minimum day, which is 01.
keys: ["KEY_Tab", "KEY_Home"],
initialVal: "2016-01-10",
expectedVal: "2016-01-01"
},
{
// End key on day field sets it to the maximum day, which is 31.
keys: ["KEY_Tab", "KEY_End"],
initialVal: "2016-01-10",
expectedVal: "2016-01-31"
},
{
// Home key should have no effect on year field.
keys: ["KEY_Tab", "KEY_Tab", "KEY_Home"],
initialVal: "2016-01-01",
expectedVal: "2016-01-01"
},
{
// End key should have no effect on year field.
keys: ["KEY_Tab", "KEY_Tab", "KEY_End"],
initialVal: "2016-01-01",
expectedVal: "2016-01-01"
},
{
// Incomplete value maps to empty .value.
keys: ["1111"],
initialVal: "",
expectedVal: ""
},
];
function sendKeys(aKeys) {
for (let i = 0; i < aKeys.length; i++) {
let key = aKeys[i];
if (key.startsWith("KEY_")) {
synthesizeKey(key);
} else {
sendString(key);
}
}
}
function test() {
var elem = document.getElementById("input");
for (let { keys, initialVal, expectedVal } of testData) {
elem.focus();
elem.value = initialVal;
sendKeys(keys);
is(elem.value, expectedVal,
"Test with " + keys + ", result should be " + expectedVal);
elem.value = "";
elem.blur();
}
function chromeListener(e) {
ok(false, "Picker should not be opened when dispatching untrusted click.");
}
SpecialPowers.addChromeEventListener("MozOpenDateTimePicker",
chromeListener);
input.click();
SpecialPowers.removeChromeEventListener("MozOpenDateTimePicker",
chromeListener);
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,65 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
-->
<head>
<title>Test focus/blur behaviour for date/time input types</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1288591">Mozilla Bug 1288591</a>
<p id="display"></p>
<div id="content">
<input id="input_time" type="time">
<input id="input_date" type="date">
</div>
<pre id="test">
<script type="application/javascript">
/**
* Test for Bug 1288591.
* This test checks whether date/time input types' .focus()/.blur() works
* correctly. This test also checks when focusing on an date/time input element,
* the focus is redirected to the anonymous text control, but the
* document.activeElement still returns date/time input element.
**/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
test();
SimpleTest.finish();
});
function testFocusBlur(type) {
let input = document.getElementById("input_" + type);
input.focus();
// The active element returns the date/time input element.
let activeElement = document.activeElement;
is(activeElement, input, "activeElement should be the date/time input element");
is(activeElement.localName, "input", "activeElement should be an input element");
is(activeElement.type, type, "activeElement should be of type " + type);
// Use FocusManager to check that the actual focus is on the anonymous
// text control.
let fm = SpecialPowers.Cc["@mozilla.org/focus-manager;1"]
.getService(SpecialPowers.Ci.nsIFocusManager);
let focusedElement = fm.focusedElement;
is(focusedElement.localName, "span", "focusedElement should be an span element");
input.blur();
isnot(document.activeElement, input, "activeElement should no longer be the datetime input element");
}
function test() {
let inputTypes = ["time", "date"];
for (let i = 0; i < inputTypes.length; i++) {
testFocusBlur(inputTypes[i]);
}
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,90 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1301306
-->
<head>
<title>Test for Bug 1301306</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1301306">Mozilla Bug 722599</a>
<p id="display"></p>
<div id="content">
<input type="time" id="input_time" onfocus="++focusEvents[0]"
onblur="++blurEvents[0]" onfocusin="++focusInEvents[0]"
onfocusout="++focusOutEvents[0]">
<input type="date" id="input_date" onfocus="++focusEvents[1]"
onblur="++blurEvents[1]" onfocusin="++focusInEvents[1]"
onfocusout="++focusOutEvents[1]">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/**
* Test for Bug 1301306.
* This test checks that when moving inside the time input element, e.g. jumping
* through the inner text boxes, does not fire extra focus/blur events.
**/
var inputTypes = ["time", "date"];
var focusEvents = [0, 0];
var focusInEvents = [0, 0];
var focusOutEvents = [0, 0];
var blurEvents = [0, 0];
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
test();
SimpleTest.finish();
});
function test() {
for (var i = 0; i < inputTypes.length; i++) {
var input = document.getElementById("input_" + inputTypes[i]);
input.focus();
is(focusEvents[i], 1, inputTypes[i] + " input element should have dispatched focus event.");
is(focusInEvents[i], 1, inputTypes[i] + " input element should have dispatched focusin event.");
is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
// Move around inside the input element's input box.
synthesizeKey("KEY_Tab");
is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
is(blurEvents[i], 0, inputTypes[i] + " time input element should not have dispatched blur event.");
synthesizeKey("KEY_ArrowRight");
is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
synthesizeKey("KEY_ArrowLeft");
is(focusEvents[i], 1,inputTypes[i] + " input element should not have dispatched focus event.");
is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
synthesizeKey("KEY_ArrowRight");
is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event.");
is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event.");
input.blur();
is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event.");
is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event.");
is(focusOutEvents[i], 1, inputTypes[i] + " input element should have dispatched focusout event.");
is(blurEvents[i], 1, inputTypes[i] + " input element should have dispatched blur event.");
}
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,79 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1346085
-->
<head>
<title>Test moving focus in onfocus/onblur handler</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1346085">Mozilla Bug 1346085</a>
<p id="display"></p>
<div id="content">
<input id="input_time" type="time">
<input id="input_date" type="date">
<input id="input_dummy" type="text">
</div>
<pre id="test">
<script type="application/javascript">
/**
* Test for Bug 1346085.
* This test checks whether date/time input types' focus state are set
* correctly, event when moving focus in onfocus/onblur handler.
**/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
test();
SimpleTest.finish();
});
function testFocusState(type) {
let input = document.getElementById("input_" + type);
input.focus();
let focus = document.querySelector(":focus");
let focusRing = document.querySelector(":-moz-focusring");
is(focus, input, "input should have :focus state after focus");
is(focusRing, input, "input should have :-moz-focusring state after focus");
input.blur();
focus = document.querySelector(":focus");
focusRing = document.querySelector(":-moz-focusring");
isnot(focus, input, "input should not have :focus state after blur");
isnot(focusRing, input, "input should not have :-moz-focusring state after blur");
input.addEventListener("focus", function() {
document.getElementById("input_dummy").focus();
}, { once: true });
input.focus();
focus = document.querySelector(":focus");
focusRing = document.querySelector(":-moz-focusring");
isnot(focus, input, "input should not have :focus state when moving focus in onfocus handler");
isnot(focusRing, input, "input should not have :-moz-focusring state when moving focus in onfocus handler");
input.addEventListener("blur", function() {
document.getElementById("input_dummy").focus();
}, { once: true });
input.blur();
focus = document.querySelector(":focus");
focusRing = document.querySelector(":-moz-focusring");
isnot(focus, input, "input should not have :focus state when moving focus in onblur handler");
isnot(focusRing, input, "input should not have :-moz-focusring state when moving focus in onblur handler");
}
function test() {
let inputTypes = ["time", "date"];
for (let i = 0; i < inputTypes.length; i++) {
testFocusState(inputTypes[i]);
}
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,93 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1370858
-->
<head>
<title>Test for Bug 1370858</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1370858">Mozilla Bug 722599</a>
<p id="display"></p>
<div id="content">
<input type="time" id="input_time" onchange="++changeEvents[0]"
oninput="++inputEvents[0]">
<input type="date" id="input_date" onchange="++changeEvents[1]"
oninput="++inputEvents[1]">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/**
* Test for Bug 1370858.
* Test that change and input events are (not) fired for date/time inputs.
**/
const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
var inputTypes = ["time", "date"];
var changeEvents = [0, 0];
var inputEvents = [0, 0];
var values = ["10:30", "2017-06-08"];
var expectedValues = [["09:30", "01:30"], ["2017-05-08", "2017-01-08"]];
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
test();
SimpleTest.finish();
});
function test() {
for (var i = 0; i < inputTypes.length; i++) {
var input = document.getElementById("input_" + inputTypes[i]);
var inputRect = input.getBoundingClientRect();
// Points over the input's reset button
var resetButton_X = inputRect.width - 15;
var resetButton_Y = inputRect.height / 2;
is(changeEvents[i], 0, "Number of change events should be 0 at start.");
is(inputEvents[i], 0, "Number of input events should be 0 at start.");
// Test that change and input events are not dispatched setting .value by
// script.
input.value = values[i];
is(input.value, values[i], "Check that value was set correctly (0).");
is(changeEvents[i], 0, "Change event should not have dispatched (0).");
is(inputEvents[i], 0, "Input event should not have dispatched (0).");
// Test that change and input events are fired when changing the value using
// up/down keys.
input.focus();
synthesizeKey("KEY_ArrowDown");
is(input.value, expectedValues[i][0], "Check that value was set correctly (1).");
is(changeEvents[i], 1, "Change event should be dispatched (1).");
is(inputEvents[i], 1, "Input event should ne dispatched (1).");
// Test that change and input events are fired when changing the value with
// the keyboard.
sendString("01");
// We get event per character.
is(input.value, expectedValues[i][1], "Check that value was set correctly (2).");
is(changeEvents[i], 3, "Change event should be dispatched (2).");
is(inputEvents[i], 3, "Input event should be dispatched (2).");
// Reset button is desktop only.
if (isDesktop) {
// Test that change and input events are fired when clearing the value using
// the reset button.
synthesizeMouse(input, resetButton_X, resetButton_Y, {});
is(input.value, "", "Check that value was set correctly (3).");
is(changeEvents[i], 4, "Change event should be dispatched (3).");
is(inputEvents[i], 4, "Input event should be dispatched (3).");
}
}
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,83 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
-->
<head>
<title>Test tabindex attribute for date/time input types</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1288591">Mozilla Bug 1288591</a>
<p id="display"></p>
<div id="content">
<input id="time1" type="time" tabindex="0">
<input id="time2" type="time" tabindex="-1">
<input id="time3" type="time" tabindex="0">
<input id="date1" type="date" tabindex="0">
<input id="date2" type="date" tabindex="-1">
<input id="date3" type="date" tabindex="0">
</div>
<pre id="test">
<script type="application/javascript">
/**
* Test for Bug 1288591.
* This test checks whether date/time input types tabindex attribute works
* correctly.
**/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
test();
SimpleTest.finish();
});
function testTabindex(type) {
let input1 = document.getElementById(type + "1");
let input2 = document.getElementById(type + "2");
let input3 = document.getElementById(type + "3");
input1.focus();
is(document.activeElement, input1,
"input element with tabindex=0 is focusable");
// Advance to next inner field
synthesizeKey("KEY_Tab");
is(document.activeElement, input1,
"input element with tabindex=0 is tabbable");
// Advance to next inner field
synthesizeKey("KEY_Tab");
is(document.activeElement, input1,
"input element with tabindex=0 is tabbable");
// Advance to next element
synthesizeKey("KEY_Tab");
is(document.activeElement, input3,
"input element with tabindex=-1 is not tabbable");
input2.focus();
is(document.activeElement, input2,
"input element with tabindex=-1 is still focusable");
// Changing the tabindex attribute dynamically.
input3.setAttribute("tabindex", "-1");
synthesizeKey("KEY_Tab"); // need only one TAB since input2 is not tabbable
isnot(document.activeElement, input3,
"element with tabindex changed to -1 should not be tabbable");
}
function test() {
let inputTypes = ["time", "date"];
for (let i = 0; i < inputTypes.length; i++) {
testTabindex(inputTypes[i]);
}
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,81 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=977029
-->
<head>
<title>Test for Bug 977029</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<div id="content">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=977029">Bug 977029</a>
<p>
Goal of this test is to check that modifying defaultValue and value attribute
of input types is working as expected.
</p>
<form>
<input id='a' type="color" value="#00ff00">
<input id='b' type="text" value="foo">
<input id='c' type="email" value="foo">
<input id='d' type="date" value="2010-09-20">
<input id='e' type="search" value="foo">
<input id='f' type="tel" value="foo">
<input id='g' type="url" value="foo">
<input id='h' type="number" value="42">
<input id='i' type="range" value="42" min="0" max="100">
<input id='j' type="time" value="17:00:25.54">
</form>
</div>
<script type="application/javascript">
// [ element id | original defaultValue | another value | another default value]
// Preferably use only valid values: the goal of this test isn't to test the
// value sanitization algorithm (for input types which have one) as this is
// already part of another test)
var testData = [["a", "#00ff00", "#00aaaa", "#00ccaa"],
["b", "foo", "bar", "tulip"],
["c", "foo", "foo@bar.org", "tulip"],
["d", "2010-09-20", "2012-09-21", ""],
["e", "foo", "bar", "tulip"],
["f", "foo", "bar", "tulip"],
["g", "foo", "bar", "tulip"],
["h", "42", "1337", "3"],
["i", "42", "17", "3"],
["j", "17:00:25.54", "07:00:25", "03:00:03"],
];
for (var data of testData) {
id = data[0];
input = document.getElementById(id);
originalDefaultValue = data[1];
is(originalDefaultValue, input.defaultValue,
"Default value isn't the expected one");
is(originalDefaultValue, input.value,
"input.value original value is different from defaultValue");
input.defaultValue = data[2]
is(input.defaultValue, input.value,
"Changing default value before value was changed should change value too");
input.value = data[3];
input.defaultValue = originalDefaultValue;
is(input.value, data[3],
"Changing default value after value was changed should not change value");
input.value = data[2];
is(originalDefaultValue, input.defaultValue,
"defaultValue shouldn't change when changing value");
input.defaultValue = data[3];
is(input.defaultValue, data[3],
"defaultValue should have changed");
// Change the value...
input.value = data[2];
is(input.value, data[2],
"value should have changed");
// ...then reset the form
input.form.reset();
is(input.defaultValue, input.value,
"reset form should bring back the default value");
}
</script>
</body>
</html>

Просмотреть файл

@ -1,585 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=549475
-->
<head>
<title>Test for Bug 549475</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=549475">Mozilla Bug 549475</a>
<p id="display"></p>
<pre id="test">
<div id='content'>
<form>
</form>
</div>
<script type="application/javascript">
SimpleTest.requestLongerTimeout(2);
/**
* This files tests the 'value sanitization algorithm' for the various input
* types. Note that an input's value is affected by more than just its type's
* value sanitization algorithm; e.g. some type=range has actions that the user
* agent must perform to change the element's value to avoid underflow/overflow
* and step mismatch (when possible). We specifically avoid triggering these
* other actions here so that this test only tests the value sanitization
* algorithm for the various input types.
*
* XXXjwatt splitting out testing of the value sanitization algorithm and
* "other things" that affect .value makes it harder to know what we're testing
* and what we've missed, because what's included in the value sanitization
* algorithm and what's not is different from input type to input type. It
* seems to me it would be better to have a test (maybe one per type) focused
* on testing .value for permutations of all other inputs that can affect it.
* The value sanitization algorithm is just an internal spec concept after all.
*/
// We buffer up the results of sets of sub-tests, and avoid outputting log
// entries for them all if they all pass. Otherwise, we have an enormous amount
// of test output.
var delayedTests = [];
var anyFailedDelayedTests = false;
function delayed_is(actual, expected, description)
{
var result = actual == expected;
delayedTests.push({ actual: actual, expected: expected, description: description });
if (!result) {
anyFailedDelayedTests = true;
}
}
function flushDelayedTests(description)
{
if (anyFailedDelayedTests) {
info("Outputting individual results for \"" + description + "\" due to failures in subtests");
for (var test of delayedTests) {
is(test.actual, test.expected, test.description);
}
} else {
ok(true, description + " (" + delayedTests.length + " subtests)");
}
delayedTests = [];
anyFailedDelayedTests = false;
}
// We are excluding "file" because it's too different from the other types.
// And it has no sanitizing algorithm.
var inputTypes =
[
"text", "password", "search", "tel", "hidden", "checkbox", "radio",
"submit", "image", "reset", "button", "email", "url", "number", "date",
"time", "range", "color", "month", "week", "datetime-local"
];
var valueModeValue =
[
"text", "search", "url", "tel", "email", "password", "date", "datetime",
"month", "week", "time", "datetime-local", "number", "range", "color",
];
function sanitizeDate(aValue)
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-date-string
function getNumbersOfDaysInMonth(aMonth, aYear) {
if (aMonth === 2) {
return (aYear % 400 === 0 || (aYear % 100 != 0 && aYear % 4 === 0)) ? 29 : 28;
}
return (aMonth === 1 || aMonth === 3 || aMonth === 5 || aMonth === 7 ||
aMonth === 8 || aMonth === 10 || aMonth === 12) ? 31 : 30;
}
var match = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})$/.exec(aValue);
if (!match) {
return "";
}
var year = Number(match[1]);
if (year === 0) {
return "";
}
var month = Number(match[2]);
if (month > 12 || month < 1) {
return "";
}
var day = Number(match[3]);
return 1 <= day && day <= getNumbersOfDaysInMonth(month, year) ? aValue : "";
}
function sanitizeTime(aValue)
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-time-string
var match = /^([0-9]{2}):([0-9]{2})(.*)$/.exec(aValue);
if (!match) {
return "";
}
var hours = match[1];
if (hours < 0 || hours > 23) {
return "";
}
var minutes = match[2];
if (minutes < 0 || minutes > 59) {
return "";
}
var other = match[3];
if (other == "") {
return aValue;
}
match = /^:([0-9]{2})(.*)$/.exec(other);
if (!match) {
return "";
}
var seconds = match[1];
if (seconds < 0 || seconds > 59) {
return "";
}
var other = match[2];
if (other == "") {
return aValue;
}
match = /^.([0-9]{1,3})$/.exec(other);
if (!match) {
return "";
}
return aValue;
}
function sanitizeDateTimeLocal(aValue)
{
// https://html.spec.whatwg.org/multipage/infrastructure.html#valid-local-date-and-time-string
if (aValue.length < 16) {
return "";
}
var sepIndex = aValue.indexOf("T");
if (sepIndex == -1) {
sepIndex = aValue.indexOf(" ");
if (sepIndex == -1) {
return "";
}
}
var [date, time] = aValue.split(aValue[sepIndex]);
if (!sanitizeDate(date)) {
return "";
}
if (!sanitizeTime(time)) {
return "";
}
// Normalize datetime-local string.
// https://html.spec.whatwg.org/multipage/infrastructure.html#valid-normalised-local-date-and-time-string
if (aValue[sepIndex] == " ") {
aValue = date + "T" + time;
}
if ((aValue.length - sepIndex) == 6) {
return aValue;
}
if ((aValue.length - sepIndex) > 9) {
var milliseconds = aValue.substring(sepIndex + 10);
if (Number(milliseconds) != 0) {
return aValue;
}
aValue = aValue.slice(0, sepIndex + 9);
}
var seconds = aValue.substring(sepIndex + 7);
if (Number(seconds) != 0) {
return aValue;
}
aValue = aValue.slice(0, sepIndex + 6);
return aValue;
}
function sanitizeValue(aType, aValue)
{
// http://www.whatwg.org/html/#value-sanitization-algorithm
switch (aType) {
case "text":
case "password":
case "search":
case "tel":
return aValue.replace(/[\n\r]/g, "");
case "url":
case "email":
return aValue.replace(/[\n\r]/g, "").replace(/^[\u0020\u0009\t\u000a\u000c\u000d]+|[\u0020\u0009\t\u000a\u000c\u000d]+$/g, "");
case "number":
return isNaN(Number(aValue)) ? "" : aValue;
case "range":
var defaultMinimum = 0;
var defaultMaximum = 100;
var value = Number(aValue);
if (isNaN(value)) {
return ((defaultMaximum - defaultMinimum)/2).toString(); // "50"
}
if (value < defaultMinimum) {
return defaultMinimum.toString();
}
if (value > defaultMaximum) {
return defaultMaximum.toString();
}
return aValue;
case "date":
return sanitizeDate(aValue);
case "time":
return sanitizeTime(aValue);
case "month":
// https://html.spec.whatwg.org/multipage/infrastructure.html#valid-month-string
var match = /^([0-9]{4,})-([0-9]{2})$/.exec(aValue);
if (!match) {
return "";
}
var year = Number(match[1]);
if (year === 0) {
return "";
}
var month = Number(match[2]);
if (month > 12 || month < 1) {
return "";
}
return aValue;
case "week":
// https://html.spec.whatwg.org/multipage/infrastructure.html#valid-week-string
function isLeapYear(aYear) {
return ((aYear % 4 == 0) && (aYear % 100 != 0)) || (aYear % 400 == 0);
}
function getDayofWeek(aYear, aMonth, aDay) { /* 0 = Sunday */
// Tomohiko Sakamoto algorithm.
var monthTable = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4];
aYear -= Number(aMonth < 3);
return (aYear + parseInt(aYear / 4) - parseInt(aYear / 100) +
parseInt(aYear / 400) + monthTable[aMonth - 1] + aDay) % 7;
}
function getMaximumWeekInYear(aYear) {
var day = getDayofWeek(aYear, 1, 1);
return day == 4 || (day == 3 && isLeapYear(aYear)) ? 53 : 52;
}
var match = /^([0-9]{4,})-W([0-9]{2})$/.exec(aValue);
if (!match) {
return "";
}
var year = Number(match[1]);
if (year === 0) {
return "";
}
var week = Number(match[2]);
if (week > 53 || month < 1) {
return "";
}
return 1 <= week && week <= getMaximumWeekInYear(year) ? aValue : "";
case "datetime-local":
return sanitizeDateTimeLocal(aValue);
case "color":
return /^#[0-9A-Fa-f]{6}$/.exec(aValue) ? aValue.toLowerCase() : "#000000";
default:
return aValue;
}
}
function checkSanitizing(element, inputTypeDescription)
{
var testData =
[
// For text, password, search, tel, email:
"\n\rfoo\n\r",
"foo\n\rbar",
" foo ",
" foo\n\r bar ",
// For url:
"\r\n foobar \n\r",
"\u000B foo \u000B",
"\u000A foo \u000A",
"\u000C foo \u000C",
"\u000d foo \u000d",
"\u0020 foo \u0020",
" \u0009 foo \u0009 ",
// For number and range:
"42",
"13.37",
"1.234567898765432",
"12foo",
"1e2",
"3E42",
// For date:
"1970-01-01",
"1234-12-12",
"1234567890-01-02",
"2012-12-31",
"2012-02-29",
"2000-02-29",
"1234",
"1234-",
"12345",
"1234-01",
"1234-012",
"1234-01-",
"12-12",
"999-01-01",
"1234-56-78-91",
"1234-567-78",
"1234--7-78",
"abcd-12-12",
"thisinotadate",
"2012-13-01",
"1234-12-42",
" 2012-13-01",
" 123-01-01",
"2012- 3-01",
"12- 10- 01",
" 12-0-1",
"2012-3-001",
"2012-12-00",
"2012-12-1r",
"2012-11-31",
"2011-02-29",
"2100-02-29",
"a2000-01-01",
"2000a-01-0'",
"20aa00-01-01",
"2000a2000-01-01",
"2000-1-1",
"2000-1-01",
"2000-01-1",
"2000-01-01 ",
"2000- 01-01",
"-1970-01-01",
"0000-00-00",
"0001-00-00",
"0000-01-01",
"1234-12 12",
"1234 12-12",
"1234 12 12",
// For time:
"1",
"10",
"10:",
"10:1",
"21:21",
":21:21",
"-21:21",
" 21:21",
"21-21",
"21:21:",
"21:211",
"121:211",
"21:21 ",
"00:00",
"-1:00",
"24:00",
"00:60",
"01:01",
"23:59",
"99:99",
"8:30",
"19:2",
"19:a2",
"4c:19",
"10:.1",
"1.:10",
"13:37:42",
"13:37.42",
"13:37:42 ",
"13:37:42.",
"13:37:61.",
"13:37:00",
"13:37:99",
"13:37:b5",
"13:37:-1",
"13:37:.1",
"13:37:1.",
"13:37:42.001",
"13:37:42.001",
"13:37:42.abc",
"13:37:42.00c",
"13:37:42.a23",
"13:37:42.12e",
"13:37:42.1e1",
"13:37:42.e11",
"13:37:42.1",
"13:37:42.99",
"13:37:42.0",
"13:37:42.00",
"13:37:42.000",
"13:37:42.-1",
"13:37:42.1.1",
"13:37:42.1,1",
"13:37:42.",
"foo12:12",
"13:37:42.100000000000",
// For color
"#00ff00",
"#000000",
"red",
"#0f0",
"#FFFFAA",
"FFAABB",
"fFAaBb",
"FFAAZZ",
"ABCDEF",
"#7654321",
// For month
"1970-01",
"1234-12",
"123456789-01",
"2013-13",
"0000-00",
"2015-00",
"0001-01",
"1-1",
"888-05",
"2013-3",
"2013-may",
"2000-1a",
"2013-03-13",
"december",
"abcdef",
"12",
" 2013-03",
"2013 - 03",
"2013 03",
"2013/03",
// For week
"1970-W01",
"1970-W53",
"1964-W53",
"1900-W10",
"2004-W53",
"2065-W53",
"2099-W53",
"2010-W53",
"2016-W30",
"1900-W3",
"2016-w30",
"2016-30",
"16-W30",
"2016-Week30",
"2000-100",
"0000-W01",
"00-W01",
"123456-W05",
"1985-W100",
"week",
// For datetime-local
"1970-01-01T00:00",
"1970-01-01Z12:00",
"1970-01-01 00:00:00",
"1970-01-01T00:00:00.0",
"1970-01-01T00:00:00.00",
"1970-01-01T00:00:00.000",
"1970-01-01 00:00:00.20",
"1969-12-31 23:59",
"1969-12-31 23:59:00",
"1969-12-31 23:59:00.000",
"1969-12-31 23:59:00.30",
"123456-01-01T12:00",
"123456-01-01T12:00:00",
"123456-01-01T12:00:00.0",
"123456-01-01T12:00:00.00",
"123456-01-01T12:00:00.000",
"123456-01-01T12:00:30",
"123456-01-01T12:00:00.123",
"10000-12-31 20:00",
"10000-12-31 20:00:00",
"10000-12-31 20:00:00.0",
"10000-12-31 20:00:00.00",
"10000-12-31 20:00:00.000",
"10000-12-31 20:00:30",
"10000-12-31 20:00:00.123",
"2016-13-01T12:00",
"2016-12-32T12:00",
"2016-11-08 15:40:30.0",
"2016-11-08T15:40:30.00",
"2016-11-07T17:30:10",
"2016-12-1T12:45",
"2016-12-01T12:45:30.123456",
"2016-12-01T24:00",
"2016-12-01T12:88:30",
"2016-12-01T12:30:99",
"2016-12-01T12:30:100",
"2016-12-01",
"2016-12-01T",
"2016-Dec-01T00:00",
"12-05-2016T00:00",
"datetime-local"
];
for (value of testData) {
element.setAttribute('value', value);
delayed_is(element.value, sanitizeValue(type, value),
"The value has not been correctly sanitized for type=" + type);
delayed_is(element.getAttribute('value'), value,
"The content value should not have been sanitized");
if (type in valueModeValue) {
element.setAttribute('value', 'tulip');
element.value = value;
delayed_is(element.value, sanitizeValue(type, value),
"The value has not been correctly sanitized for type=" + type);
delayed_is(element.getAttribute('value'), 'tulip',
"The content value should not have been sanitized");
}
element.setAttribute('value', '');
form.reset();
element.type = 'checkbox'; // We know this type has no sanitizing algorithm.
element.setAttribute('value', value);
delayed_is(element.value, value, "The value should not have been sanitized");
element.type = type;
delayed_is(element.value, sanitizeValue(type, value),
"The value has not been correctly sanitized for type=" + type);
delayed_is(element.getAttribute('value'), value,
"The content value should not have been sanitized");
element.setAttribute('value', '');
form.reset();
element.setAttribute('value', value);
form.reset();
delayed_is(element.value, sanitizeValue(type, value),
"The value has not been correctly sanitized for type=" + type);
delayed_is(element.getAttribute('value'), value,
"The content value should not have been sanitized");
// Cleaning-up.
element.setAttribute('value', '');
form.reset();
}
flushDelayedTests(inputTypeDescription);
}
for (type of inputTypes) {
var form = document.forms[0];
var element = document.createElement("input");
element.style.display = "none";
element.type = type;
form.appendChild(element);
checkSanitizing(element, "type=" + type + ", no frame, no editor");
element.style.display = "";
checkSanitizing(element, "type=" + type + ", frame, no editor");
element.focus();
element.blur();
checkSanitizing(element, "type=" + type + ", frame, editor");
element.style.display = "none";
checkSanitizing(element, "type=" + type + ", no frame, editor");
form.removeChild(element);
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,123 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=829606
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 829606</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 829606 **/
/*
* This test checks that setting .value on an text field (input or textarea)
* doesn't scroll the field to its beginning.
*/
SimpleTest.waitForExplicitFinish();
var gTestRunner = null;
function test(aElementName)
{
var element = document.getElementsByTagName(aElementName)[0];
element.focus();
var baseSnapshot = snapshotWindow(window);
// This is a sanity check.
var s2 = snapshotWindow(window);
var results = compareSnapshots(baseSnapshot, snapshotWindow(window), true);
ok(results[0], "sanity check: screenshots should be the same");
element.selectionStart = element.selectionEnd = element.value.length;
setTimeout(function() {
sendString('f');
requestAnimationFrame(function() {
var selectionAtTheEndSnapshot = snapshotWindow(window);
results = compareSnapshots(baseSnapshot, selectionAtTheEndSnapshot, false);
ok(results[0], "after appending a character, string should have changed");
element.value = element.value;
var tmpSnapshot = snapshotWindow(window);
results = compareSnapshots(baseSnapshot, tmpSnapshot, false);
ok(results[0], "re-settig the value should change nothing");
results = compareSnapshots(selectionAtTheEndSnapshot, tmpSnapshot, true);
ok(results[0], "re-settig the value should change nothing");
element.selectionStart = element.selectionEnd = 0;
element.blur();
gTestRunner.next();
});
}, 0);
}
// This test checks that when a textarea has a long list of values and the
// textarea's value is then changed, the values are shown correctly.
function testCorrectUpdateOnScroll()
{
var textarea = document.createElement('textarea');
textarea.rows = 5;
textarea.cols = 10;
textarea.value = 'a\nb\nc\nd';
document.getElementById('content').appendChild(textarea);
var baseSnapshot = snapshotWindow(window);
textarea.value = '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n';
textarea.selectionStart = textarea.selectionEnd = textarea.value.length;
var fullSnapshot = snapshotWindow(window);
var results = compareSnapshots(baseSnapshot, fullSnapshot, false);
ok(results[0], "sanity check: screenshots should not be the same");
textarea.value = 'a\nb\nc\nd';
var tmpSnapshot = snapshotWindow(window);
results = compareSnapshots(baseSnapshot, tmpSnapshot, true);
ok(results[0], "textarea view should look like the beginning");
setTimeout(function() {
gTestRunner.next();
}, 0);
}
function* runTest()
{
test('input');
yield undefined;
test('textarea');
yield undefined;
testCorrectUpdateOnScroll();
yield undefined;
SimpleTest.finish();
}
gTestRunner = runTest();
SimpleTest.waitForFocus(function() {
gTestRunner.next();
});;
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=829606">Mozilla Bug 829606</a>
<p id="display"></p>
<div id="content">
<textarea rows='1' cols='5' style='-moz-appearance:none;'>this is a \n long text</textarea>
<input size='5' value="this is a very long text" style='-moz-appearance:none;'>
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -1,206 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1288591
-->
<head>
<title>Test key events for time control</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta charset="UTF-8">
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1288591">Mozilla Bug 1288591</a>
<p id="display"></p>
<div id="content">
<input id="input" type="time">
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
// Turn off Spatial Navigation because it hijacks arrow keydown events:
SimpleTest.waitForFocus(function() {
SpecialPowers.pushPrefEnv({"set":[["snav.enabled", false]]}, function() {
test();
SimpleTest.finish();
});
});
var testData = [
/**
* keys: keys to send to the input element.
* initialVal: initial value set to the input element.
* expectedVal: expected value of the input element after sending the keys.
*/
{
// Type 1030 and select AM.
keys: ["1030", "KEY_ArrowDown"],
initialVal: "",
expectedVal: "10:30"
},
{
// Type 3 in the hour field will automatically advance to the minute field.
keys: ["330", "KEY_ArrowDown"],
initialVal: "",
expectedVal: "03:30"
},
{
// Type 5 in the hour field will automatically advance to the minute field.
// Type 7 in the minute field will automatically advance to the AM/PM field.
keys: ["57", "KEY_ArrowDown"],
initialVal: "",
expectedVal: "05:07"
},
{
// Advance to AM/PM field and change to PM.
keys: ["KEY_Tab", "KEY_Tab", "KEY_ArrowDown"],
initialVal: "10:30",
expectedVal: "22:30"
},
{
// Right key should do the same thing as TAB key.
keys: ["KEY_ArrowRight", "KEY_ArrowRight", "KEY_ArrowDown"],
initialVal: "10:30",
expectedVal: "22:30"
},
{
// Advance to minute field then back to hour field and decrement.
keys: ["KEY_ArrowRight", "KEY_ArrowLeft", "KEY_ArrowDown"],
initialVal: "10:30",
expectedVal: "09:30"
},
{
// Focus starts on the first field, hour in this case, and increment.
keys: ["KEY_ArrowUp"],
initialVal: "16:00",
expectedVal: "17:00"
},
{
// Advance to minute field and decrement.
keys: ["KEY_Tab", "KEY_ArrowDown"],
initialVal: "16:00",
expectedVal: "16:59"
},
{
// Advance to minute field and increment.
keys: ["KEY_Tab", "KEY_ArrowUp"],
initialVal: "16:59",
expectedVal: "16:00"
},
{
// PageUp on hour field increments hour by 3.
keys: ["KEY_PageUp"],
initialVal: "05:00",
expectedVal: "08:00"
},
{
// PageDown on hour field decrements hour by 3.
keys: ["KEY_PageDown"],
initialVal: "05:00",
expectedVal: "02:00"
},
{
// PageUp on minute field increments minute by 10.
keys: ["KEY_Tab", "KEY_PageUp"],
initialVal: "14:00",
expectedVal: "14:10"
},
{
// PageDown on minute field decrements minute by 10.
keys: ["KEY_Tab", "KEY_PageDown"],
initialVal: "14:00",
expectedVal: "14:50"
},
{
// Home key on hour field sets it to the minimum hour, which is 1 in 12-hour
// clock.
keys: ["KEY_Home"],
initialVal: "03:10",
expectedVal: "01:10"
},
{
// End key on hour field sets it to the maximum hour, which is 12 in 12-hour
// clock.
keys: ["KEY_End"],
initialVal: "03:10",
expectedVal: "00:10"
},
{
// Home key on minute field sets it to the minimum minute, which is 0.
keys: ["KEY_Tab", "KEY_Home"],
initialVal: "19:30",
expectedVal: "19:00"
},
{
// End key on minute field sets it to the minimum minute, which is 59.
keys: ["KEY_Tab", "KEY_End"],
initialVal: "19:30",
expectedVal: "19:59"
},
// Second field will show up when needed.
{
// PageUp on second field increments second by 10.
keys: ["KEY_Tab", "KEY_Tab", "KEY_PageUp"],
initialVal: "08:10:10",
expectedVal: "08:10:20"
},
{
// PageDown on second field increments second by 10.
keys: ["KEY_Tab", "KEY_Tab", "KEY_PageDown"],
initialVal: "08:10:10",
expectedVal: "08:10:00"
},
{
// Home key on second field sets it to the minimum second, which is 0.
keys: ["KEY_Tab", "KEY_Tab", "KEY_Home"],
initialVal: "16:00:30",
expectedVal: "16:00:00"
},
{
// End key on second field sets it to the minimum second, which is 59.
keys: ["KEY_Tab", "KEY_Tab", "KEY_End"],
initialVal: "16:00:30",
expectedVal: "16:00:59"
},
{
// Incomplete value maps to empty .value.
keys: ["1"],
initialVal: "",
expectedVal: ""
},
];
function sendKeys(aKeys, aElem) {
for (let i = 0; i < aKeys.length; i++) {
// Force layout flush between keys to ensure focus is correct.
// This shouldn't be necessary; bug 1450219 tracks this.
aElem.clientTop;
let key = aKeys[i];
if (key.startsWith("KEY_")) {
synthesizeKey(key);
} else {
sendString(key);
}
}
}
function test() {
var elem = document.getElementById("input");
for (let { keys, initialVal, expectedVal } of testData) {
elem.focus();
elem.value = initialVal;
sendKeys(keys, elem);
is(elem.value, expectedVal,
"Test with " + keys + ", result should be " + expectedVal);
elem.value = "";
elem.blur();
}
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,134 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1374967
-->
<head>
<title>Test second and millisecond fields in input type=time</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta charset="UTF-8">
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1374967">Mozilla Bug 1374967</a>
<p id="display"></p>
<div id="content">
<input id="input1" type="time">
<input id="input2" type="time" value="12:30:40">
<input id="input3" type="time" value="12:30:40.567">
<input id="input4" type="time" step="1">
<input id="input5" type="time" step="61">
<input id="input6" type="time" step="120">
<input id="input7" type="time" step="0.01">
<input id="input8" type="time" step="0.001">
<input id="input9" type="time" step="1.001">
<input id="input10" type="time" min="01:30:05">
<input id="input11" type="time" min="01:30:05.100">
<input id="dummy">
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
test();
SimpleTest.finish();
});
const NUM_OF_FIELDS_DEFAULT = 3;
const NUM_OF_FIELDS_WITH_SECOND = NUM_OF_FIELDS_DEFAULT + 1;
const NUM_OF_FIELDS_WITH_MILLISEC = NUM_OF_FIELDS_WITH_SECOND + 1;
function countNumberOfFields(aElement) {
is(aElement.type, "time", "Input element type should be 'time'");
let inputRect = aElement.getBoundingClientRect();
let firstField_X = 15;
let firstField_Y = inputRect.height / 2;
// Make sure to start on the first field.
synthesizeMouse(aElement, firstField_X, firstField_Y, {});
is(document.activeElement, aElement, "Input element should be focused");
let n = 0;
while (document.activeElement == aElement) {
n++;
synthesizeKey("KEY_Tab");
}
return n;
}
function test() {
// Normal input time element.
let elem = document.getElementById("input1");
is(countNumberOfFields(elem), NUM_OF_FIELDS_DEFAULT, "Default input time");
// Dynamically changing the value with second part.
elem.value = "10:20:30";
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND,
"Input time after changing value with second part");
// Dynamically changing the step to 1 millisecond.
elem.step = "0.001";
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
"Input time after changing step to 1 millisecond");
// Input time with value with second part.
elem = document.getElementById("input2");
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND,
"Input time with value with second part");
// Input time with value with second and millisecond part.
elem = document.getElementById("input3");
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
"Input time with value with second and millisecond part");
// Input time with step set as 1 second.
elem = document.getElementById("input4");
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND,
"Input time with step set as 1 second");
// Input time with step set as 61 seconds.
elem = document.getElementById("input5");
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND,
"Input time with step set as 61 seconds");
// Input time with step set as 2 minutes.
elem = document.getElementById("input6");
is(countNumberOfFields(elem), NUM_OF_FIELDS_DEFAULT,
"Input time with step set as 2 minutes");
// Input time with step set as 10 milliseconds.
elem = document.getElementById("input7");
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
"Input time with step set as 10 milliseconds");
// Input time with step set as 100 milliseconds.
elem = document.getElementById("input8");
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
"Input time with step set as 100 milliseconds");
// Input time with step set as 1001 milliseconds.
elem = document.getElementById("input9");
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
"Input time with step set as 1001 milliseconds");
// Input time with min with second part and default step (60 seconds). Note
// that step base is min, when there is a min.
elem = document.getElementById("input10");
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND,
"Input time with min with second part");
// Input time with min with second and millisecond part and default step (60
// seconds). Note that step base is min, when there is a min.
elem = document.getElementById("input11");
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
"Input time with min with second and millisecond part");
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,121 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=764481
-->
<head>
<title>Test for Bug 764481</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=764481">Mozilla Bug 764481</a>
<p id="display"></p>
<div id="content" style="display: none" >
</div>
<pre id="test">
<script type="application/javascript">
var input = document.createElement("input");
var testData = [
{
prefs: [["dom.forms.color", false]],
inputType: "color",
expectedType: "text"
}, {
prefs: [["dom.forms.color", true]],
inputType: "color",
expectedType: "color"
}, {
prefs: [["dom.experimental_forms", false], ["dom.forms.datetime", false]],
inputType: "date",
expectedType: "text"
}, {
prefs: [["dom.experimental_forms", true], ["dom.forms.datetime", false]],
inputType: "date",
expectedType: "date"
}, {
prefs: [["dom.experimental_forms", false], ["dom.forms.datetime", true]],
inputType: "date",
expectedType: "date"
}, {
prefs: [["dom.experimental_forms", false], ["dom.forms.datetime", false]],
inputType: "time",
expectedType: "text"
}, {
prefs: [["dom.experimental_forms", true], ["dom.forms.datetime", false]],
inputType: "time",
expectedType: "time"
}, {
prefs: [["dom.experimental_forms", false], ["dom.forms.datetime", true]],
inputType: "time",
expectedType: "time"
}, {
prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", false]],
inputType: "month",
expectedType: "text"
}, {
prefs: [["dom.forms.datetime", true], ["dom.forms.datetime.others", false]],
inputType: "month",
expectedType: "text"
}, {
prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", true]],
inputType: "month",
expectedType: "month"
}, {
prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", false]],
inputType: "week",
expectedType: "text"
}, {
prefs: [["dom.forms.datetime", true], ["dom.forms.datetime.others", false]],
inputType: "week",
expectedType: "text"
}, {
prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", true]],
inputType: "week",
expectedType: "week"
}, {
prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", false]],
inputType: "datetime-local",
expectedType: "text"
}, {
prefs: [["dom.forms.datetime", true], ["dom.forms.datetime.others", false]],
inputType: "datetime-local",
expectedType: "text"
}, {
prefs: [["dom.forms.datetime", false], ["dom.forms.datetime.others", true]],
inputType: "datetime-local",
expectedType: "datetime-local"
}
];
function testInputTypePreference(aData) {
return SpecialPowers.pushPrefEnv({'set': aData.prefs})
.then(() => {
// Change the type of input to text and then back to the tested input type,
// so that HTMLInputElement::ParseAttribute gets called with the pref enabled.
input.type = "text";
input.type = aData.inputType;
is(input.type, aData.expectedType, "input type should be '" +
aData.expectedType + "'' when pref " + aData.prefs + " is set");
is(input.getAttribute('type'), aData.inputType,
"input 'type' attribute should not change");
});
}
SimpleTest.waitForExplicitFinish();
let promise = Promise.resolve();
for (let i = 0; i < testData.length; i++) {
let data = testData[i];
promise = promise.then(() => testInputTypePreference(data));
}
promise.catch(error => ok(false, "Promise reject: " + error))
.then(() => SimpleTest.finish());
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,236 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=765772
-->
<head>
<title>Test for Bug 765772</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug 765772</a>
<p id="display"></p>
<iframe name="submit_frame" style="visibility: hidden;"></iframe>
<div id="content">
<form id='f' target="submit_frame" action="foo">
<input name=i id="i" step='any' >
</form>
</div>
<pre id="test">
<script type="application/javascript">
/*
* This test checks that when a user types in some input types, it will not be
* in a state where the value will be un-sanitized and usable (by a script).
*/
var input = document.getElementById('i');
var form = document.getElementById('f');
var submitFrame = document.getElementsByTagName('iframe')[0];
var testData = [];
var gCurrentTest = null;
var gValidData = [];
var gInvalidData = [];
function submitForm() {
form.submit();
}
function sendKeyEventToSubmitForm() {
sendKey("return");
}
function urlify(aStr) {
return aStr.replace(/:/g, '%3A');
}
function runTestsForNextInputType()
{
let {done} = testRunner.next();
if (done) {
SimpleTest.finish();
}
}
function checkValueSubmittedIsValid()
{
is(frames['submit_frame'].location.href,
'http://mochi.test:8888/tests/dom/html/test/forms/xbl/foo?i='
+ urlify(gValidData[valueIndex++]),
"The submitted value should not have been sanitized");
input.value = "";
if (valueIndex >= gValidData.length) {
if (gCurrentTest.canHaveBadInputValidityState) {
// Don't run the submission tests on the invalid input if submission
// will be blocked by invalid input.
runTestsForNextInputType();
return;
}
valueIndex = 0;
submitFrame.onload = checkValueSubmittedIsInvalid;
testData = gInvalidData;
}
testSubmissions();
}
function checkValueSubmittedIsInvalid()
{
is(frames['submit_frame'].location.href,
'http://mochi.test:8888/tests/dom/html/test/forms/xbl/foo?i=',
"The submitted value should have been sanitized");
valueIndex++;
input.value = "";
if (valueIndex >= gInvalidData.length) {
if (submitMethod == sendKeyEventToSubmitForm) {
runTestsForNextInputType();
return;
}
valueIndex = 0;
submitMethod = sendKeyEventToSubmitForm;
submitFrame.onload = checkValueSubmittedIsValid;
testData = gValidData;
}
testSubmissions();
}
function testSubmissions() {
input.focus();
sendString(testData[valueIndex]);
submitMethod();
}
var valueIndex = 0;
var submitMethod = submitForm;
SimpleTest.waitForExplicitFinish();
function* runTest()
{
SimpleTest.requestLongerTimeout(4);
var data = [
{
type: 'number',
canHaveBadInputValidityState: true,
validData: [
"42",
"-42", // should work for negative values
"42.1234",
"123.123456789123", // double precision
"1e2", // e should be usable
"2e1",
"1e-1", // value after e can be negative
"1E2", // E can be used instead of e
],
invalidData: [
"e",
"e2",
"1e0.1",
"foo",
"42,13", // comma can't be used as a decimal separator
]
},
{
type: 'month',
validData: [
'0001-01',
'2012-12',
'100000-01',
],
invalidData: [
'1-01',
'-',
'december',
'2012-dec',
'2012/12',
'2012-99',
'2012-1',
]
},
{
type: 'week',
validData: [
'0001-W01',
'1970-W53',
'100000-W52',
'2016-W30',
],
invalidData: [
'1-W01',
'week',
'2016-30',
'2010-W80',
'2000/W30',
'1985-W00',
'1000-W'
]
},
{
type: 'datetime-local',
validData: [
'0001-01-01T00:00',
'2016-11-07T16:45',
'2016-11-07T16:45:30',
'2016-11-07T16:45:30.10',
'2016-11-07T16:45:00.111',
],
invalidData: [
'1-01-01T00:00',
'1970-01-01T9:30',
'2016/11/07T16:45',
'2016-11-07T16.45',
'T',
'datetime-local'
]
},
];
for (test of data) {
gCurrentTest = test;
input.type = test.type;
gValidData = test.validData;
gInvalidData = test.invalidData;
for (data of gValidData) {
input.value = "";
input.focus();
sendString(data);
input.blur();
is(input.value, data, "valid user input should not be sanitized");
}
for (data of gInvalidData) {
input.value = "";
input.focus();
sendString(data);
input.blur();
is(input.value, "", "invalid user input should be sanitized");
}
input.value = '';
testData = gValidData;
valueIndex = 0;
submitFrame.onload = checkValueSubmittedIsValid;
testSubmissions();
yield undefined;
}
}
var testRunner = runTest();
addLoadEvent(function () {
testRunner.next();
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,84 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=597650
-->
<head>
<title>Test for Bug 597650</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=597650">Mozilla Bug 597650</a>
<p id="display"></p>
<div id="content">
<label id="l">
<input id="h"></input>
<input type="text" id="i"></input>
</label>
<label id="lh" for="h"></label>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 597650 **/
label = document.getElementById("l");
labelForH = document.getElementById("lh");
inputI = document.getElementById("i");
inputH = document.getElementById("h");
var labelableTypes = ["text", "search", "tel", "url", "email", "password",
"datetime", "date", "month", "week", "time",
"number", "range", "color", "checkbox", "radio",
"file", "submit", "image", "reset", "button"];
var nonLabelableTypes = ["hidden"];
for (var i in labelableTypes) {
test(labelableTypes[i], true);
}
for (var i in nonLabelableTypes) {
test(nonLabelableTypes[i], false);
}
function test(type, isLabelable) {
inputH.type = type;
if (isLabelable) {
testControl(label, inputH, type, true);
testControl(labelForH, inputH, type, true);
} else {
testControl(label, inputI, type, false);
testControl(labelForH, null, type, false);
inputH.type = "text";
testControl(label, inputH, "text", true);
testControl(labelForH, inputH, "text", true);
inputH.type = type;
testControl(label, inputI, type, false);
testControl(labelForH, null, type, false);
label.removeChild(inputH);
testControl(label, inputI, "text", true);
var element = document.createElement('input');
element.type = type;
label.insertBefore(element, inputI);
testControl(label, inputI, "text", true);
}
}
function testControl(label, control, type, labelable) {
if (labelable) {
is(label.control, control, "Input controls of type " + type
+ " should be labeled");
} else {
is(label.control, control, "Input controls of type " + type
+ " should be ignored by <label>");
}
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,473 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=635499
-->
<head>
<title>Test for Bug 635499</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=635499">Mozilla Bug 635499</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 635499 **/
var data = [
{ type: 'hidden', apply: false },
{ type: 'text', apply: false },
{ type: 'search', apply: false },
{ type: 'tel', apply: false },
{ type: 'url', apply: false },
{ type: 'email', apply: false },
{ type: 'password', apply: false },
{ type: 'date', apply: true },
{ type: 'month', apply: true },
{ type: 'week', apply: true },
{ type: 'time', apply: true },
{ type: 'datetime-local', apply: true },
{ type: 'number', apply: true },
{ type: 'range', apply: true },
{ type: 'color', apply: false },
{ type: 'checkbox', apply: false },
{ type: 'radio', apply: false },
{ type: 'file', apply: false },
{ type: 'submit', apply: false },
{ type: 'image', apply: false },
{ type: 'reset', apply: false },
{ type: 'button', apply: false },
];
var input = document.createElement("input");
document.getElementById('content').appendChild(input);
/**
* @aValidity - boolean indicating whether the element is expected to be valid
* (aElement.validity.valid is true) or not. The value passed is ignored and
* overridden with true if aApply is false.
* @aApply - boolean indicating whether the min/max attributes apply to this
* element type.
* @aRangeApply - A boolean that's set to true if the current input type is a
* "[candidate] for constraint validation" and it "[has] range limitations"
* per http://www.whatwg.org/specs/web-apps/current-work/multipage/selectors.html#selector-in-range
* (in other words, one of the pseudo classes :in-range and :out-of-range
* should apply (which, depends on aValidity)).
* Else (neither :in-range or :out-of-range should match) set to false.
*/
function checkValidity(aElement, aValidity, aApply, aRangeApply)
{
aValidity = aApply ? aValidity : true;
is(aElement.validity.valid, aValidity,
"element validity should be " + aValidity);
is(aElement.validity.rangeOverflow, !aValidity,
"element overflow status should be " + !aValidity);
var overflowMsg =
(aElement.type == "date" || aElement.type == "time" ||
aElement.type == "month" || aElement.type == "week" ||
aElement.type == "datetime-local") ?
("Please select a value that is no later than " + aElement.max + ".") :
("Please select a value that is no more than " + aElement.max + ".");
is(aElement.validationMessage,
aValidity ? "" : overflowMsg, "Checking range overflow validation message");
is(aElement.matches(":valid"), aElement.willValidate && aValidity,
(aElement.willValidate && aValidity) ? ":valid should apply" : "valid shouldn't apply");
is(aElement.matches(":invalid"), aElement.willValidate && !aValidity,
(aElement.wil && aValidity) ? ":invalid shouldn't apply" : "valid should apply");
if (!aRangeApply) {
ok(!aElement.matches(":in-range"), ":in-range should not match");
ok(!aElement.matches(":out-of-range"),
":out-of-range should not match");
} else {
is(aElement.matches(":in-range"), aValidity,
":in-range matches status should be " + aValidity);
is(aElement.matches(":out-of-range"), !aValidity,
":out-of-range matches status should be " + !aValidity);
}
}
for (var test of data) {
input.type = test.type;
var apply = test.apply;
// The element should be valid. Range should not apply when @min and @max are
// undefined, except if the input type is 'range' (since that type has a
// default minimum and maximum).
if (input.type == 'range') {
checkValidity(input, true, apply, true);
} else {
checkValidity(input, true, apply, false);
}
checkValidity(input, true, apply, test.type == 'range');
switch (input.type) {
case 'hidden':
case 'text':
case 'search':
case 'password':
case 'url':
case 'tel':
case 'email':
case 'number':
case 'checkbox':
case 'radio':
case 'file':
case 'submit':
case 'reset':
case 'button':
case 'image':
case 'color':
input.max = '-1';
break;
case 'date':
input.max = '2012-06-27';
break;
case 'time':
input.max = '02:20';
break;
case 'range':
// range is special, since setting max to -1 will make it invalid since
// it's default would then be 0, meaning it suffers from overflow.
input.max = '-1';
checkValidity(input, false, apply, apply);
// Now make it something that won't cause an error below:
input.max = '10';
break;
case 'month':
input.max = '2016-12';
break;
case 'week':
input.max = '2016-W39';
break;
case 'datetime-local':
input.max = '2016-12-31T23:59:59';
break;
default:
ok(false, 'please, add a case for this new type (' + input.type + ')');
}
checkValidity(input, true, apply, apply);
switch (input.type) {
case 'text':
case 'hidden':
case 'search':
case 'password':
case 'tel':
case 'radio':
case 'checkbox':
case 'reset':
case 'button':
case 'submit':
case 'image':
input.value = '0';
checkValidity(input, true, apply, apply);
break;
case 'url':
input.value = 'http://mozilla.org';
checkValidity(input, true, apply, apply);
break;
case 'email':
input.value = 'foo@bar.com';
checkValidity(input, true, apply, apply);
break;
case 'file':
var file = new File([''], '635499_file');
SpecialPowers.wrap(input).mozSetFileArray([file]);
checkValidity(input, true, apply, apply);
break;
case 'date':
input.max = '2012-06-27';
input.value = '2012-06-26';
checkValidity(input, true, apply, apply);
input.value = '2012-06-27';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '2012-06-28';
checkValidity(input, false, apply, apply);
input.max = '2012-06-30';
checkValidity(input, true, apply, apply);
input.value = '2012-07-05';
checkValidity(input, false, apply, apply);
input.value = '1000-01-01';
checkValidity(input, true, apply, apply);
input.value = '20120-01-01';
checkValidity(input, false, apply, apply);
input.max = '0050-01-01';
checkValidity(input, false, apply, apply);
input.value = '0049-01-01';
checkValidity(input, true, apply, apply);
input.max = '';
checkValidity(input, true, apply, false);
input.max = 'foo';
checkValidity(input, true, apply, false);
break;
case 'number':
input.max = '2';
input.value = '1';
checkValidity(input, true, apply, apply);
input.value = '2';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '3';
checkValidity(input, false, apply, apply);
input.max = '5';
checkValidity(input, true, apply, apply);
input.value = '42';
checkValidity(input, false, apply, apply);
input.max = '';
checkValidity(input, true, apply, false);
input.max = 'foo';
checkValidity(input, true, apply, false);
// Check that we correctly convert input.max to a double in validationMessage.
if (input.type == 'number') {
input.max = "4.333333333333333333333333333333333331";
input.value = "5";
is(input.validationMessage,
"Please select a value that is no more than 4.33333333333333.",
"validation message");
}
break;
case 'range':
input.max = '2';
input.value = '1';
checkValidity(input, true, apply, apply);
input.value = '2';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '3';
checkValidity(input, true, apply, apply);
is(input.value, input.max, "the value should have been set to max");
input.max = '5';
checkValidity(input, true, apply, apply);
input.value = '42';
checkValidity(input, true, apply, apply);
is(input.value, input.max, "the value should have been set to max");
input.max = '';
checkValidity(input, true, apply, apply);
input.max = 'foo';
checkValidity(input, true, apply, apply);
// Check that we correctly convert input.max to a double in validationMessage.
input.step = 'any';
input.min = 5;
input.max = 0.66666666666666666666666666666666666
input.value = 1;
is(input.validationMessage,
"Please select a value that is no more than 0.666666666666667.",
"validation message")
break;
case 'time':
// Don't worry about that.
input.step = 'any';
input.max = '10:10';
input.value = '10:09';
checkValidity(input, true, apply, apply);
input.value = '10:10';
checkValidity(input, true, apply, apply);
input.value = '10:10:00';
checkValidity(input, true, apply, apply);
input.value = '10:10:00.000';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '10:11';
checkValidity(input, false, apply, apply);
input.value = '10:10:00.001';
checkValidity(input, false, apply, apply);
input.max = '01:00:00.01';
input.value = '01:00:00.001';
checkValidity(input, true, apply, apply);
input.value = '01:00:00';
checkValidity(input, true, apply, apply);
input.value = '01:00:00.1';
checkValidity(input, false, apply, apply);
input.max = '';
checkValidity(input, true, apply, false);
input.max = 'foo';
checkValidity(input, true, apply, false);
break;
case 'month':
input.value = '2016-06';
checkValidity(input, true, apply, apply);
input.value = '2016-12';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '2017-01';
checkValidity(input, false, apply, apply);
input.max = '2017-07';
checkValidity(input, true, apply, apply);
input.value = '2017-12';
checkValidity(input, false, apply, apply);
input.value = '1000-01';
checkValidity(input, true, apply, apply);
input.value = '20160-01';
checkValidity(input, false, apply, apply);
input.max = '0050-01';
checkValidity(input, false, apply, apply);
input.value = '0049-12';
checkValidity(input, true, apply, apply);
input.max = '';
checkValidity(input, true, apply, false);
input.max = 'foo';
checkValidity(input, true, apply, false);
break;
case 'week':
input.value = '2016-W01';
checkValidity(input, true, apply, apply);
input.value = '2016-W39';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '2017-W01';
checkValidity(input, false, apply, apply);
input.max = '2017-W01';
checkValidity(input, true, apply, apply);
input.value = '2017-W52';
checkValidity(input, false, apply, apply);
input.value = '1000-W01';
checkValidity(input, true, apply, apply);
input.value = '2100-W01';
checkValidity(input, false, apply, apply);
input.max = '0050-W01';
checkValidity(input, false, apply, apply);
input.value = '0049-W52';
checkValidity(input, true, apply, apply);
input.max = '';
checkValidity(input, true, apply, false);
input.max = 'foo';
checkValidity(input, true, apply, false);
break;
case 'datetime-local':
input.value = '2016-01-01T12:00';
checkValidity(input, true, apply, apply);
input.value = '2016-12-31T23:59:59';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '2016-12-31T23:59:59.123';
checkValidity(input, false, apply, apply);
input.value = '2017-01-01T10:00';
checkValidity(input, false, apply, apply);
input.max = '2017-01-01T10:00';
checkValidity(input, true, apply, apply);
input.value = '2017-01-01T10:00:30';
checkValidity(input, false, apply, apply);
input.value = '1000-01-01T12:00';
checkValidity(input, true, apply, apply);
input.value = '2100-01-01T12:00';
checkValidity(input, false, apply, apply);
input.max = '0050-12-31T23:59:59.999';
checkValidity(input, false, apply, apply);
input.value = '0050-12-31T23:59:59';
checkValidity(input, true, apply, apply);
input.max = '';
checkValidity(input, true, apply, false);
input.max = 'foo';
checkValidity(input, true, apply, false);
break;
}
// Cleaning up,
input.removeAttribute('max');
input.value = '';
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,473 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=635553
-->
<head>
<title>Test for Bug 635553</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=635499">Mozilla Bug 635499</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 635553 **/
var data = [
{ type: 'hidden', apply: false },
{ type: 'text', apply: false },
{ type: 'search', apply: false },
{ type: 'tel', apply: false },
{ type: 'url', apply: false },
{ type: 'email', apply: false },
{ type: 'password', apply: false },
{ type: 'date', apply: true },
{ type: 'month', apply: true },
{ type: 'week', apply: true },
{ type: 'time', apply: true },
{ type: 'datetime-local', apply: true },
{ type: 'number', apply: true },
{ type: 'range', apply: true },
{ type: 'color', apply: false },
{ type: 'checkbox', apply: false },
{ type: 'radio', apply: false },
{ type: 'file', apply: false },
{ type: 'submit', apply: false },
{ type: 'image', apply: false },
{ type: 'reset', apply: false },
{ type: 'button', apply: false },
];
var input = document.createElement("input");
document.getElementById('content').appendChild(input);
/**
* @aValidity - boolean indicating whether the element is expected to be valid
* (aElement.validity.valid is true) or not. The value passed is ignored and
* overridden with true if aApply is false.
* @aApply - boolean indicating whether the min/max attributes apply to this
* element type.
* @aRangeApply - A boolean that's set to true if the current input type is a
* "[candidate] for constraint validation" and it "[has] range limitations"
* per http://www.whatwg.org/specs/web-apps/current-work/multipage/selectors.html#selector-in-range
* (in other words, one of the pseudo classes :in-range and :out-of-range
* should apply (which, depends on aValidity)).
* Else (neither :in-range or :out-of-range should match) set to false.
*/
function checkValidity(aElement, aValidity, aApply, aRangeApply)
{
aValidity = aApply ? aValidity : true;
is(aElement.validity.valid, aValidity,
"element validity should be " + aValidity);
is(aElement.validity.rangeUnderflow, !aValidity,
"element underflow status should be " + !aValidity);
var underflowMsg =
(aElement.type == "date" || aElement.type == "time" ||
aElement.type == "month" || aElement.type == "week" ||
aElement.type == "datetime-local") ?
("Please select a value that is no earlier than " + aElement.min + ".") :
("Please select a value that is no less than " + aElement.min + ".");
is(aElement.validationMessage,
aValidity ? "" : underflowMsg, "Checking range underflow validation message");
is(aElement.matches(":valid"), aElement.willValidate && aValidity,
(aElement.willValidate && aValidity) ? ":valid should apply" : "valid shouldn't apply");
is(aElement.matches(":invalid"), aElement.willValidate && !aValidity,
(aElement.wil && aValidity) ? ":invalid shouldn't apply" : "valid should apply");
if (!aRangeApply) {
ok(!aElement.matches(":in-range"), ":in-range should not match");
ok(!aElement.matches(":out-of-range"),
":out-of-range should not match");
} else {
is(aElement.matches(":in-range"), aValidity,
":in-range matches status should be " + aValidity);
is(aElement.matches(":out-of-range"), !aValidity,
":out-of-range matches status should be " + !aValidity);
}
}
for (var test of data) {
input.type = test.type;
var apply = test.apply;
if (test.todo) {
todo_is(input.type, test.type, test.type + " isn't implemented yet");
continue;
}
// The element should be valid. Range should not apply when @min and @max are
// undefined, except if the input type is 'range' (since that type has a
// default minimum and maximum).
if (input.type == 'range') {
checkValidity(input, true, apply, true);
} else {
checkValidity(input, true, apply, false);
}
switch (input.type) {
case 'hidden':
case 'text':
case 'search':
case 'password':
case 'url':
case 'tel':
case 'email':
case 'number':
case 'checkbox':
case 'radio':
case 'file':
case 'submit':
case 'reset':
case 'button':
case 'image':
case 'color':
input.min = '999';
break;
case 'date':
input.min = '2012-06-27';
break;
case 'time':
input.min = '20:20';
break;
case 'range':
// range is special, since setting min to 999 will make it invalid since
// it's default maximum is 100, its value would be 999, and it would
// suffer from overflow.
break;
case 'month':
input.min = '2016-06';
break;
case 'week':
input.min = '2016-W39';
break;
case 'datetime-local':
input.min = '2017-01-01T00:00';
break;
default:
ok(false, 'please, add a case for this new type (' + input.type + ')');
}
// The element should still be valid and range should apply if it can.
checkValidity(input, true, apply, apply);
switch (input.type) {
case 'text':
case 'hidden':
case 'search':
case 'password':
case 'tel':
case 'radio':
case 'checkbox':
case 'reset':
case 'button':
case 'submit':
case 'image':
case 'color':
input.value = '0';
checkValidity(input, true, apply, apply);
break;
case 'url':
input.value = 'http://mozilla.org';
checkValidity(input, true, apply, apply);
break;
case 'email':
input.value = 'foo@bar.com';
checkValidity(input, true, apply, apply);
break;
case 'file':
var file = new File([''], '635499_file');
SpecialPowers.wrap(input).mozSetFileArray([file]);
checkValidity(input, true, apply, apply);
break;
case 'date':
input.value = '2012-06-28';
checkValidity(input, true, apply, apply);
input.value = '2012-06-27';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '2012-06-26';
checkValidity(input, false, apply, apply);
input.min = '2012-02-29';
checkValidity(input, true, apply, apply);
input.value = '2012-02-28';
checkValidity(input, false, apply, apply);
input.value = '1000-01-01';
checkValidity(input, false, apply, apply);
input.value = '20120-01-01';
checkValidity(input, true, apply, apply);
input.min = '0050-01-01';
checkValidity(input, true, apply, apply);
input.value = '0049-01-01';
checkValidity(input, false, apply, apply);
input.min = '';
checkValidity(input, true, apply, false);
input.min = 'foo';
checkValidity(input, true, apply, false);
break;
case 'number':
input.min = '0';
input.value = '1';
checkValidity(input, true, apply, apply);
input.value = '0';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '-1';
checkValidity(input, false, apply, apply);
input.min = '-1';
checkValidity(input, true, apply, apply);
input.value = '-42';
checkValidity(input, false, apply, apply);
input.min = '';
checkValidity(input, true, apply, false);
input.min = 'foo';
checkValidity(input, true, apply, false);
// Check that we correctly convert input.min to a double in
// validationMessage.
input.min = "4.333333333333333333333333333333333331";
input.value = "2";
is(input.validationMessage,
"Please select a value that is no less than 4.33333333333333.",
"validation message");
break;
case 'range':
input.min = '0';
input.value = '1';
checkValidity(input, true, apply, apply);
input.value = '0';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '-1';
checkValidity(input, true, apply, apply);
is(input.value, input.min, "the value should have been set to min");
input.min = '-1';
checkValidity(input, true, apply, apply);
input.value = '-42';
checkValidity(input, true, apply, apply);
is(input.value, input.min, "the value should have been set to min");
input.min = '';
checkValidity(input, true, apply, true);
input.min = 'foo';
checkValidity(input, true, apply, true);
// We don't check the conversion of input.min to a double in
// validationMessage for 'range' since range will always clamp the value
// up to at least the minimum (so we will never see the min in a
// validationMessage).
break;
case 'time':
// Don't worry about that.
input.step = 'any';
input.min = '20:20';
input.value = '20:20:01';
checkValidity(input, true, apply, apply);
input.value = '20:20:00';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '10:00';
checkValidity(input, false, apply, apply);
input.min = '20:20:00.001';
input.value = '20:20';
checkValidity(input, false, apply, apply);
input.value = '00:00';
checkValidity(input, false, apply, apply);
input.value = '23:59';
checkValidity(input, true, apply, apply);
input.value = '20:20:01';
checkValidity(input, true, apply, apply);
input.value = '20:20:00.01';
checkValidity(input, true, apply, apply);
input.value = '20:20:00.1';
checkValidity(input, true, apply, apply);
input.min = '00:00:00';
input.value = '01:00';
checkValidity(input, true, apply, apply);
input.value = '00:00:00.000';
checkValidity(input, true, apply, apply);
input.min = '';
checkValidity(input, true, apply, false);
input.min = 'foo';
checkValidity(input, true, apply, false);
break;
case 'month':
input.value = '2016-07';
checkValidity(input, true, apply, apply);
input.value = '2016-06';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '2016-05';
checkValidity(input, false, apply, apply);
input.min = '2016-01';
checkValidity(input, true, apply, apply);
input.value = '2015-12';
checkValidity(input, false, apply, apply);
input.value = '1000-01';
checkValidity(input, false, apply, apply);
input.value = '10000-01';
checkValidity(input, true, apply, apply);
input.min = '0010-01';
checkValidity(input, true, apply, apply);
input.value = '0001-01';
checkValidity(input, false, apply, apply);
input.min = '';
checkValidity(input, true, apply, false);
input.min = 'foo';
checkValidity(input, true, apply, false);
break;
case 'week':
input.value = '2016-W40';
checkValidity(input, true, apply, apply);
input.value = '2016-W39';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '2016-W38';
checkValidity(input, false, apply, apply);
input.min = '2016-W01';
checkValidity(input, true, apply, apply);
input.value = '2015-W53';
checkValidity(input, false, apply, apply);
input.value = '1000-W01';
checkValidity(input, false, apply, apply);
input.value = '10000-01';
checkValidity(input, true, apply, apply);
input.min = '0010-W01';
checkValidity(input, true, apply, apply);
input.value = '0001-W01';
checkValidity(input, false, apply, apply);
input.min = '';
checkValidity(input, true, apply, false);
input.min = 'foo';
checkValidity(input, true, apply, false);
break;
case 'datetime-local':
input.value = '2017-12-31T23:59';
checkValidity(input, true, apply, apply);
input.value = '2017-01-01T00:00';
checkValidity(input, true, apply, apply);
input.value = '2017-01-01T00:00:00.123';
checkValidity(input, true, apply, apply);
input.value = 'foo';
checkValidity(input, true, apply, apply);
input.value = '2016-12-31T23:59';
checkValidity(input, false, apply, apply);
input.min = '2016-01-01T00:00';
checkValidity(input, true, apply, apply);
input.value = '2015-12-31T23:59';
checkValidity(input, false, apply, apply);
input.value = '1000-01-01T00:00';
checkValidity(input, false, apply, apply);
input.value = '10000-01-01T00:00';
checkValidity(input, true, apply, apply);
input.min = '0010-01-01T12:00';
checkValidity(input, true, apply, apply);
input.value = '0010-01-01T10:00';
checkValidity(input, false, apply, apply);
input.min = '';
checkValidity(input, true, apply, false);
input.min = 'foo';
checkValidity(input, true, apply, false);
break;
default:
ok(false, 'write tests for ' + input.type);
}
// Cleaning up,
input.removeAttribute('min');
input.value = '';
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,111 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=565538
-->
<head>
<title>Test for Bug 565538</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=565538">Mozilla Bug 565538</a>
<p id="display"></p>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 565538 **/
var gElementTestData = [
/* element result */
['input', true],
['button', false],
['fieldset', false],
['label', false],
['option', false],
['optgroup', false],
['output', false],
['legend', false],
['select', false],
['textarea', false],
['object', false],
];
var gInputTestData = [
/* type result */
['password', true],
['tel', true],
['text', true],
['button', false],
['checkbox', false],
['file', false],
['hidden', false],
['reset', false],
['image', false],
['radio', false],
['submit', false],
['search', true],
['email', true],
['url', true],
['number', false],
['range', false],
['date', false],
['time', false],
['color', false],
['month', false],
['week', false],
['datetime-local', false],
];
function checkMozIsTextFieldDefined(aElement, aResult)
{
var element = document.createElement(aElement);
var msg = "mozIsTextField should be "
if (aResult) {
msg += "defined";
} else {
msg += "undefined";
}
is('mozIsTextField' in element, aResult, msg);
}
function checkMozIsTextFieldValue(aInput, aResult)
{
is(aInput.mozIsTextField(false), aResult,
"mozIsTextField(false) should return " + aResult);
if (aInput.type == 'password') {
ok(!aInput.mozIsTextField(true),
"mozIsTextField(true) should return false for password");
} else {
is(aInput.mozIsTextField(true), aResult,
"mozIsTextField(true) should return " + aResult);
}
}
function checkMozIsTextFieldValueTodo(aInput, aResult)
{
todo_is(aInput.mozIsTextField(false), aResult,
"mozIsTextField(false) should return " + aResult);
todo_is(aInput.mozIsTextField(true), aResult,
"mozIsTextField(true) should return " + aResult);
}
// Check if the method is defined for the correct elements.
for (data of gElementTestData) {
checkMozIsTextFieldDefined(data[0], data[1]);
}
// Check if the method returns the correct value.
var input = document.createElement('input');
for (data of gInputTestData) {
input.type = data[0];
checkMozIsTextFieldValue(input, data[1]);
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,84 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=556013
-->
<head>
<title>Test for Bug 556013</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=556013">Mozilla Bug 556013</a>
<p id="display"></p>
<iframe style='width:50px; height: 50px;' name='t'></iframe>
<div id="content">
<form target='t' action='data:text/html,' novalidate>
<input id='av' required>
<input id='a' type='submit'>
</form>
<form target='t' action='data:text/html,' novalidate>
<input id='bv' type='checkbox' required>
<button id='b' type='submit'></button>
</form>
<form target='t' action='data:text/html,' novalidate>
<input id='c' required>
</form>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 556013 **/
/**
* novalidate should prevent form validation, thus not blocking form submission.
*
* NOTE: if there is no invalidformsubmit observer, the form submission will
* never be blocked and this test might be a false-positive but that should not
* be a problem.
*/
document.forms[0].addEventListener("submit", function(aEvent) {
ok(true, "novalidate has been correctly used for first form");
document.getElementById('b').click();
}, {once: true});
document.forms[1].addEventListener("submit", function(aEvent) {
ok(true, "novalidate has been correctly used for second form");
var c = document.getElementById('c');
c.focus();
synthesizeKey("KEY_Enter");
}, {once: true});
document.forms[2].addEventListener("submit", function(aEvent) {
ok(true, "novalidate has been correctly used for third form");
SimpleTest.executeSoon(SimpleTest.finish);
}, {once: true});
/**
* We have to be sure invalid events are not send too.
* They should be sent before the submit event so we can just create a test
* failure if we got one. All of them should be catched if sent.
* At worst, we got random green which isn't harmful.
*/
function invalidHandling(aEvent)
{
aEvent.target.removeEventListener("invalid", invalidHandling);
ok(false, "invalid event should not be sent");
}
document.getElementById('av').addEventListener("invalid", invalidHandling);
document.getElementById('bv').addEventListener("invalid", invalidHandling);
document.getElementById('c').addEventListener("invalid", invalidHandling);
SimpleTest.waitForExplicitFinish();
// This is going to call all the tests (with a chain reaction).
SimpleTest.waitForFocus(function() {
document.getElementById('a').click();
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,324 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=345512
-->
<head>
<title>Test for Bug 345512</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
input { background-color: rgb(0,0,0) !important; }
input:valid { background-color: rgb(0,255,0) !important; }
input:invalid { background-color: rgb(255,0,0) !important; }
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=345512">Mozilla Bug 345512</a>
<p id="display"></p>
<div id="content" style="display: none">
<input id='i' pattern="tulip" oninvalid="invalidEventHandler(event);">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 345512 **/
var gInvalid = false;
function invalidEventHandler(e)
{
is(e.type, "invalid", "Invalid event type should be invalid");
gInvalid = true;
}
function completeValidityCheck(element, alwaysValid, isBarred)
{
// Check when pattern matches.
if (element.type == 'email') {
element.pattern = ".*@bar.com";
element.value = "foo@bar.com";
} else if (element.type == 'url') {
element.pattern = "http://.*\\.com$";
element.value = "http://mozilla.com";
} else if (element.type == 'file') {
element.pattern = "foo";
SpecialPowers.wrap(element).mozSetFileArray([new File(["foo"], "foo")]);
} else {
element.pattern = "foo";
element.value = "foo";
}
checkValidPattern(element, true, isBarred);
// Check when pattern does not match.
if (element.type == 'email') {
element.pattern = ".*@bar.com";
element.value = "foo@foo.com";
} else if (element.type == 'url') {
element.pattern = "http://.*\\.com$";
element.value = "http://mozilla.org";
} else if (element.type == 'file') {
element.pattern = "foo";
SpecialPowers.wrap(element).mozSetFileArray([new File(["bar"], "bar")]);
} else {
element.pattern = "foo";
element.value = "bar";
}
if (!alwaysValid) {
checkInvalidPattern(element, true);
} else {
checkValidPattern(element, true, isBarred);
}
}
function checkValidPattern(element, completeCheck, isBarred)
{
if (completeCheck) {
gInvalid = false;
ok(!element.validity.patternMismatch,
"Element should not suffer from pattern mismatch");
ok(element.validity.valid, "Element should be valid");
ok(element.checkValidity(), "Element should be valid");
ok(!gInvalid, "Invalid event shouldn't have been thrown");
is(element.validationMessage, '',
"Validation message should be the empty string");
if (element.type != 'radio' && element.type != 'checkbox') {
is(window.getComputedStyle(element).getPropertyValue('background-color'),
isBarred ? "rgb(0, 0, 0)" : "rgb(0, 255, 0)",
"The pseudo-class is not correctly applied");
}
} else {
ok(!element.validity.patternMismatch,
"Element should not suffer from pattern mismatch");
}
}
function checkInvalidPattern(element, completeCheck)
{
if (completeCheck) {
gInvalid = false;
ok(element.validity.patternMismatch,
"Element should suffer from pattern mismatch");
ok(!element.validity.valid, "Element should not be valid");
ok(!element.checkValidity(), "Element should not be valid");
ok(gInvalid, "Invalid event should have been thrown");
is(element.validationMessage,
"Please match the requested format.",
"Validation message is not valid");
} else {
ok(element.validity.patternMismatch,
"Element should suffer from pattern mismatch");
}
if (element.type != 'radio' && element.type != 'checkbox') {
is(window.getComputedStyle(element).getPropertyValue('background-color'),
"rgb(255, 0, 0)", ":invalid pseudo-class should apply");
}
}
function checkSyntaxError(element)
{
ok(!element.validity.patternMismatch,
"On SyntaxError, element should not suffer");
}
function checkPatternValidity(element)
{
element.pattern = "foo";
element.value = '';
checkValidPattern(element);
element.value = "foo";
checkValidPattern(element);
element.value = "bar";
checkInvalidPattern(element);
element.value = "foobar";
checkInvalidPattern(element);
element.value = "foofoo";
checkInvalidPattern(element);
element.pattern = "foo\"bar";
element.value = "foo\"bar";
checkValidPattern(element);
element.value = 'foo"bar';
checkValidPattern(element);
element.pattern = "foo'bar";
element.value = "foo\'bar";
checkValidPattern(element);
element.pattern = "foo\\(bar";
element.value = "foo(bar";
checkValidPattern(element);
element.value = "foo";
checkInvalidPattern(element);
element.pattern = "foo\\)bar";
element.value = "foo)bar";
checkValidPattern(element);
element.value = "foo";
checkInvalidPattern(element);
// Check for 'i' flag disabled. Should be case sensitive.
element.value = "Foo";
checkInvalidPattern(element);
// We can't check for the 'g' flag because we only test, we don't execute.
// We can't check for the 'm' flag because .value shouldn't contain line breaks.
// We need '\\\\' because '\\' will produce '\\' and we want to escape the '\'
// for the regexp.
element.pattern = "foo\\\\bar";
element.value = "foo\\bar";
checkValidPattern(element);
// We may want to escape the ' in the pattern, but this is a SyntaxError
// when unicode flag is set.
element.pattern = "foo\\'bar";
element.value = "foo'bar";
checkSyntaxError(element);
element.value = "baz";
checkSyntaxError(element);
// We should check the pattern attribute do not pollute |RegExp.lastParen|.
is(RegExp.lastParen, "", "RegExp.lastParen should be the empty string");
element.pattern = "(foo)";
element.value = "foo";
checkValidPattern(element);
is(RegExp.lastParen, "", "RegExp.lastParen should be the empty string");
// That may sound weird but the empty string is a valid pattern value.
element.pattern = "";
element.value = "";
checkValidPattern(element);
element.value = "foo";
checkInvalidPattern(element);
// Checking some complex patterns. As we are using js regexp mechanism, these
// tests doesn't aim to test the regexp mechanism.
element.pattern = "\\d{2}\\s\\d{2}\\s\\d{4}"
element.value = "01 01 2010"
checkValidPattern(element);
element.value = "01/01/2010"
checkInvalidPattern(element);
element.pattern = "[0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z_+])*@([0-9a-zA-Z][-\\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9}";
element.value = "foo@bar.com";
checkValidPattern(element);
element.value = "...@bar.com";
checkInvalidPattern(element);
element.pattern = "^(?:\\w{3,})$";
element.value = "foo";
checkValidPattern(element);
element.value = "f";
checkInvalidPattern(element);
// If @title is specified, it should be added in the validation message.
if (element.type == 'email') {
element.pattern = "foo@bar.com"
element.value = "bar@foo.com";
} else if (element.type == 'url') {
element.pattern = "http://mozilla.com";
element.value = "http://mozilla.org";
} else {
element.pattern = "foo";
element.value = "bar";
}
element.title = "this is an explanation of the regexp";
is(element.validationMessage,
"Please match the requested format: " + element.title + ".",
"Validation message is not valid");
element.title = "";
is(element.validationMessage,
"Please match the requested format.",
"Validation message is not valid");
element.pattern = "foo";
if (element.type == 'email') {
element.value = "bar@foo.com";
} else if (element.type == 'url') {
element.value = "http://mozilla.org";
} else {
element.value = "bar";
}
checkInvalidPattern(element);
element.removeAttribute('pattern');
checkValidPattern(element, true);
// Unicode pattern
for (var pattern of ["\\u{1F438}{2}", "\u{1F438}{2}",
"\\uD83D\\uDC38{2}", "\uD83D\uDC38{2}",
"\u{D83D}\u{DC38}{2}"]) {
element.pattern = pattern;
element.value = "\u{1F438}\u{1F438}";
checkValidPattern(element);
element.value = "\uD83D\uDC38\uD83D\uDC38";
checkValidPattern(element);
element.value = "\uD83D\uDC38\uDC38";
checkInvalidPattern(element);
}
element.pattern = "\\u{D83D}\\u{DC38}{2}";
element.value = "\u{1F438}\u{1F438}";
checkInvalidPattern(element);
element.value = "\uD83D\uDC38\uD83D\uDC38";
checkInvalidPattern(element);
element.value = "\uD83D\uDC38\uDC38";
checkInvalidPattern(element);
}
var input = document.getElementById('i');
// |validTypes| are the types which accept @pattern
// and |invalidTypes| are the ones which do not accept it.
var validTypes = Array('text', 'password', 'search', 'tel', 'email', 'url');
var barredTypes = Array('hidden', 'reset', 'button');
var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'range', 'date',
'time', 'color', 'submit', 'image', 'month', 'week',
'datetime-local');
for (type of validTypes) {
input.type = type;
completeValidityCheck(input, false);
checkPatternValidity(input);
}
for (type of barredTypes) {
input.type = type;
completeValidityCheck(input, true, true);
}
for (type of invalidTypes) {
input.type = type;
completeValidityCheck(input, true);
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,420 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=345822
-->
<head>
<title>Test for Bug 345822</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=345822">Mozilla Bug 345822</a>
<p id="display"></p>
<div id="content">
<form>
</form>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 345822 **/
function checkNotSufferingFromBeingMissing(element, doNotApply)
{
ok(!element.validity.valueMissing,
"Element should not suffer from value missing");
ok(element.validity.valid, "Element should be valid");
ok(element.checkValidity(), "Element should be valid");
is(element.validationMessage, "",
"Validation message should be the empty string");
if (doNotApply) {
ok(!element.matches(':valid'), ":valid should not apply");
ok(!element.matches(':invalid'), ":invalid should not apply");
ok(!element.matches(':-moz-ui-valid'), ":-moz-ui-valid should not apply");
ok(!element.matches(':-moz-ui-invalid'), ":-moz-ui-invalid should not apply");
} else {
ok(element.matches(':valid'), ":valid should apply");
ok(!element.matches(':invalid'), ":invalid should not apply");
ok(element.matches(':-moz-ui-valid'), ":-moz-ui-valid should apply");
ok(!element.matches(':-moz-ui-invalid'), ":-moz-ui-invalid should not apply");
}
}
function checkSufferingFromBeingMissing(element, hasMozUIInvalid)
{
ok(element.validity.valueMissing, "Element should suffer from value missing");
ok(!element.validity.valid, "Element should not be valid");
ok(!element.checkValidity(), "Element should not be valid");
if (element.type == 'checkbox')
{
is(element.validationMessage,
"Please check this box if you want to proceed.",
"Validation message is wrong");
}
else if (element.type == 'radio')
{
is(element.validationMessage,
"Please select one of these options.",
"Validation message is wrong");
}
else if (element.type == 'file')
{
is(element.validationMessage,
"Please select a file.",
"Validation message is wrong");
}
else if (element.type == 'number')
{
is(element.validationMessage,
"Please enter a number.",
"Validation message is wrong");
}
else // text fields
{
is(element.validationMessage,
"Please fill out this field.",
"Validation message is wrong");
}
ok(!element.matches(':valid'), ":valid should apply");
ok(element.matches(':invalid'), ":invalid should not apply");
ok(!element.matches(':-moz-ui-valid'), ":-moz-ui-valid should not apply");
is(element.matches(':-moz-ui-invalid'), hasMozUIInvalid, ":-moz-ui-invalid expected state is " + hasMozUIInvalid);
}
function checkTextareaRequiredValidity()
{
var element = document.createElement('textarea');
document.forms[0].appendChild(element);
SpecialPowers.wrap(element).value = '';
element.required = false;
checkNotSufferingFromBeingMissing(element);
element.required = true;
checkSufferingFromBeingMissing(element, true);
element.readOnly = true;
checkNotSufferingFromBeingMissing(element, true);
element.readOnly = false;
checkSufferingFromBeingMissing(element, true);
SpecialPowers.wrap(element).value = 'foo';
checkNotSufferingFromBeingMissing(element);
SpecialPowers.wrap(element).value = '';
checkSufferingFromBeingMissing(element, true);
element.required = false;
checkNotSufferingFromBeingMissing(element);
element.focus();
element.required = true;
SpecialPowers.wrap(element).value = 'foobar';
element.blur();
element.form.reset();
checkSufferingFromBeingMissing(element, false);
SpecialPowers.wrap(element).value = '';
element.form.reportValidity();
checkSufferingFromBeingMissing(element, true);
element.form.reset();
checkSufferingFromBeingMissing(element, false);
// TODO: for the moment, a textarea outside of a document is mutable.
SpecialPowers.wrap(element).value = ''; // To make -moz-ui-valid apply.
element.required = false;
document.forms[0].removeChild(element);
checkNotSufferingFromBeingMissing(element);
}
function checkInputRequiredNotApply(type, isBarred)
{
var element = document.createElement('input');
element.type = type;
document.forms[0].appendChild(element);
SpecialPowers.wrap(element).value = '';
element.required = false;
checkNotSufferingFromBeingMissing(element, isBarred);
element.required = true;
checkNotSufferingFromBeingMissing(element, isBarred);
element.required = false;
document.forms[0].removeChild(element);
checkNotSufferingFromBeingMissing(element, isBarred);
}
function checkInputRequiredValidity(type)
{
var element = document.createElement('input');
element.type = type;
document.forms[0].appendChild(element);
SpecialPowers.wrap(element).value = '';
element.required = false;
checkNotSufferingFromBeingMissing(element);
element.required = true;
checkSufferingFromBeingMissing(element, true);
element.readOnly = true;
checkNotSufferingFromBeingMissing(element, true);
element.readOnly = false;
checkSufferingFromBeingMissing(element, true);
if (element.type == 'email') {
SpecialPowers.wrap(element).value = 'foo@bar.com';
} else if (element.type == 'url') {
SpecialPowers.wrap(element).value = 'http://mozilla.org/';
} else if (element.type == 'number') {
SpecialPowers.wrap(element).value = '42';
} else if (element.type == 'date') {
SpecialPowers.wrap(element).value = '2010-10-10';
} else if (element.type == 'time') {
SpecialPowers.wrap(element).value = '21:21';
} else if (element.type = 'month') {
SpecialPowers.wrap(element).value = '2010-10';
} else {
SpecialPowers.wrap(element).value = 'foo';
}
checkNotSufferingFromBeingMissing(element);
SpecialPowers.wrap(element).value = '';
checkSufferingFromBeingMissing(element, true);
element.focus();
element.required = true;
SpecialPowers.wrap(element).value = 'foobar';
element.blur();
element.form.reset();
checkSufferingFromBeingMissing(element, false);
SpecialPowers.wrap(element).value = '';
element.form.reportValidity();
checkSufferingFromBeingMissing(element, true);
element.form.reset();
checkSufferingFromBeingMissing(element, false);
element.required = true;
SpecialPowers.wrap(element).value = ''; // To make :-moz-ui-valid apply.
checkSufferingFromBeingMissing(element, true);
document.forms[0].removeChild(element);
// Removing the child changes nothing about whether it's valid
checkSufferingFromBeingMissing(element, true);
}
function checkInputRequiredValidityForCheckbox()
{
var element = document.createElement('input');
element.type = 'checkbox';
document.forms[0].appendChild(element);
element.checked = false;
element.required = false;
checkNotSufferingFromBeingMissing(element);
element.required = true;
checkSufferingFromBeingMissing(element, true);
element.checked = true;
checkNotSufferingFromBeingMissing(element);
element.checked = false;
checkSufferingFromBeingMissing(element, true);
element.required = false;
checkNotSufferingFromBeingMissing(element);
element.focus();
element.required = true;
element.checked = true;
element.blur();
element.form.reset();
checkSufferingFromBeingMissing(element, false);
element.required = true;
element.checked = false;
element.form.reportValidity();
checkSufferingFromBeingMissing(element, true);
element.form.reset();
checkSufferingFromBeingMissing(element, false);
element.required = true;
element.checked = false;
document.forms[0].removeChild(element);
checkSufferingFromBeingMissing(element, true);
}
function checkInputRequiredValidityForRadio()
{
var element = document.createElement('input');
element.type = 'radio';
element.name = 'test'
document.forms[0].appendChild(element);
element.checked = false;
element.required = false;
checkNotSufferingFromBeingMissing(element);
element.required = true;
checkSufferingFromBeingMissing(element, true);
element.checked = true;
checkNotSufferingFromBeingMissing(element);
element.checked = false;
checkSufferingFromBeingMissing(element, true);
// A required radio button should not suffer from value missing if another
// radio button from the same group is checked.
var element2 = document.createElement('input');
element2.type = 'radio';
element2.name = 'test';
element2.checked = true;
element2.required = false;
document.forms[0].appendChild(element2);
// Adding a checked radio should make required radio in the group not
// suffering from being missing.
checkNotSufferingFromBeingMissing(element);
element.checked = false;
element2.checked = false;
checkSufferingFromBeingMissing(element, true);
// The other radio button should not be disabled.
// A disabled checked radio button in the radio group
// is enough to not suffer from value missing.
element2.checked = true;
element2.disabled = true;
checkNotSufferingFromBeingMissing(element);
// If a radio button is not required but another radio button is required in
// the same group, the not required radio button should suffer from value
// missing.
element2.disabled = false;
element2.checked = false;
element.required = false;
element2.required = true;
checkSufferingFromBeingMissing(element, true);
checkSufferingFromBeingMissing(element2, true);
element.checked = true;
checkNotSufferingFromBeingMissing(element2);
// The checked radio is not in the group anymore, element2 should be invalid.
element.form.removeChild(element);
checkNotSufferingFromBeingMissing(element);
checkSufferingFromBeingMissing(element2, true);
element2.focus();
element2.required = true;
element2.checked = true;
element2.blur();
element2.form.reset();
checkSufferingFromBeingMissing(element2, false);
element2.required = true;
element2.checked = false;
element2.form.reportValidity();
checkSufferingFromBeingMissing(element2, true);
element2.form.reset();
checkSufferingFromBeingMissing(element2, false);
element2.required = true;
element2.checked = false;
document.forms[0].removeChild(element2);
checkSufferingFromBeingMissing(element2, true);
}
function checkInputRequiredValidityForFile()
{
var element = document.createElement('input');
element.type = 'file'
document.forms[0].appendChild(element);
var file = new File([""], "345822_file");
SpecialPowers.wrap(element).value = "";
element.required = false;
checkNotSufferingFromBeingMissing(element);
element.required = true;
checkSufferingFromBeingMissing(element, true);
SpecialPowers.wrap(element).mozSetFileArray([file]);
checkNotSufferingFromBeingMissing(element);
SpecialPowers.wrap(element).value = "";
checkSufferingFromBeingMissing(element, true);
element.required = false;
checkNotSufferingFromBeingMissing(element);
element.focus();
SpecialPowers.wrap(element).mozSetFileArray([file]);
element.required = true;
element.blur();
element.form.reset();
checkSufferingFromBeingMissing(element, false);
element.required = true;
SpecialPowers.wrap(element).value = '';
element.form.reportValidity();
checkSufferingFromBeingMissing(element, true);
element.form.reset();
checkSufferingFromBeingMissing(element, false);
element.required = true;
SpecialPowers.wrap(element).value = '';
document.forms[0].removeChild(element);
checkSufferingFromBeingMissing(element, true);
}
checkTextareaRequiredValidity();
// The require attribute behavior depend of the input type.
// First of all, checks for types that make the element barred from
// constraint validation.
var typeBarredFromConstraintValidation = ["hidden", "button", "reset"];
for (type of typeBarredFromConstraintValidation) {
checkInputRequiredNotApply(type, true);
}
// Then, checks for the types which do not use the required attribute.
var typeRequireNotApply = ['range', 'color', 'submit', 'image'];
for (type of typeRequireNotApply) {
checkInputRequiredNotApply(type, false);
}
// Now, checking for all types which accept the required attribute.
var typeRequireApply = ["text", "password", "search", "tel", "email", "url",
"number", "date", "time", "month", "week",
"datetime-local"];
for (type of typeRequireApply) {
checkInputRequiredValidity(type);
}
checkInputRequiredValidityForCheckbox();
checkInputRequiredValidityForRadio();
checkInputRequiredValidityForFile();
</script>
</pre>
</body>
</html>

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,104 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for HTMLTextAreaElement attributes reflection</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="../../reflect.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<pre id="test">
<script type="application/javascript">
/** Test for HTMLTextAreaElement attributes reflection **/
// .autofocus
reflectBoolean({
element: document.createElement("textarea"),
attribute: "autofocus",
});
//.cols
reflectUnsignedInt({
element: document.createElement("textarea"),
attribute: "cols",
nonZero: true,
defaultValue: 20,
fallback: true,
});
todo("dirName" in document.createElement("textarea"),
"dirName isn't implemented yet");
// .disabled
reflectBoolean({
element: document.createElement("textarea"),
attribute: "disabled",
});
// TODO: form (HTMLFormElement)
// .maxLength
reflectInt({
element: document.createElement("textarea"),
attribute: "maxLength",
nonNegative: true,
});
// .name
reflectString({
element: document.createElement("textarea"),
attribute: "name",
otherValues: [ "isindex", "_charset_" ],
});
// .placeholder
reflectString({
element: document.createElement("textarea"),
attribute: "placeholder",
otherValues: [ "foo\nbar", "foo\rbar", "foo\r\nbar" ],
});
// .readOnly
reflectBoolean({
element: document.createElement("textarea"),
attribute: "readOnly",
});
// .required
reflectBoolean({
element: document.createElement("textarea"),
attribute: "required",
});
// .rows
reflectUnsignedInt({
element: document.createElement("textarea"),
attribute: "rows",
nonZero: true,
defaultValue: 2,
fallback: true,
});
// .wrap
// TODO: make it an enumerated attributes limited to only known values, bug 670869.
reflectString({
element: document.createElement("textarea"),
attribute: "wrap",
otherValues: [ "soft", "hard" ],
});
// .type doesn't reflect a content attribute.
// .defaultValue doesn't reflect a content attribute.
// .value doesn't reflect a content attribute.
// .textLength doesn't reflect a content attribute.
// .willValidate doesn't reflect a content attribute.
// .validity doesn't reflect a content attribute.
// .validationMessage doesn't reflect a content attribute.
// .labels doesn't reflect a content attribute.
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,358 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=345624
-->
<head>
<title>Test for Bug 345624</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
input, textarea, fieldset, button, select, keygen, output, object { background-color: rgb(0,0,0) !important; }
:valid { background-color: rgb(0,255,0) !important; }
:invalid { background-color: rgb(255,0,0) !important; }
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=345624">Mozilla Bug 345624</a>
<p id="display"></p>
<div id="content" style="display: none">
<fieldset id='f'></fieldset>
<input id='i' oninvalid="invalidEventHandler(event);">
<button id='b' oninvalid="invalidEventHandler(event);"></button>
<select id='s' oninvalid="invalidEventHandler(event);"></select>
<textarea id='t' oninvalid="invalidEventHandler(event);"></textarea>
<output id='o' oninvalid="invalidEventHandler(event);"></output>
<keygen id='k'></keygen>
<object id='obj'></object>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 345624 **/
var gInvalid = false;
function invalidEventHandler(aEvent)
{
function checkInvalidEvent(aEvent)
{
is(aEvent.type, "invalid", "Invalid event type should be invalid");
ok(!aEvent.bubbles, "Invalid event should not bubble");
ok(aEvent.cancelable, "Invalid event should be cancelable");
}
checkInvalidEvent(aEvent);
gInvalid = true;
}
function checkConstraintValidationAPIExist(element)
{
ok('willValidate' in element, "willValidate is not available in the DOM");
ok('validationMessage' in element, "validationMessage is not available in the DOM");
ok('validity' in element, "validity is not available in the DOM");
if ('validity' in element) {
validity = element.validity;
ok('valueMissing' in validity, "validity.valueMissing is not available in the DOM");
ok('typeMismatch' in validity, "validity.typeMismatch is not available in the DOM");
ok('badInput' in validity, "validity.badInput is not available in the DOM");
ok('patternMismatch' in validity, "validity.patternMismatch is not available in the DOM");
ok('tooLong' in validity, "validity.tooLong is not available in the DOM");
ok('rangeUnderflow' in validity, "validity.rangeUnderflow is not available in the DOM");
ok('rangeOverflow' in validity, "validity.rangeOverflow is not available in the DOM");
ok('stepMismatch' in validity, "validity.stepMismatch is not available in the DOM");
ok('customError' in validity, "validity.customError is not available in the DOM");
ok('valid' in validity, "validity.valid is not available in the DOM");
}
}
function checkConstraintValidationAPIDefaultValues(element)
{
// Not checking willValidate because the default value depends of the element
is(element.validationMessage, "", "validationMessage default value should be empty string");
ok(!element.validity.valueMissing, "The element should not suffer from a constraint validation");
ok(!element.validity.typeMismatch, "The element should not suffer from a constraint validation");
ok(!element.validity.badInput, "The element should not suffer from a constraint validation");
ok(!element.validity.patternMismatch, "The element should not suffer from a constraint validation");
ok(!element.validity.tooLong, "The element should not suffer from a constraint validation");
ok(!element.validity.rangeUnderflow, "The element should not suffer from a constraint validation");
ok(!element.validity.rangeOverflow, "The element should not suffer from a constraint validation");
ok(!element.validity.stepMismatch, "The element should not suffer from a constraint validation");
ok(!element.validity.customError, "The element should not suffer from a constraint validation");
ok(element.validity.valid, "The element should be valid by default");
ok(element.checkValidity(), "The element should be valid by default");
}
function checkDefaultPseudoClass()
{
is(window.getComputedStyle(document.getElementById('f'))
.getPropertyValue('background-color'), "rgb(0, 255, 0)",
":valid should apply");
is(window.getComputedStyle(document.getElementById('o'))
.getPropertyValue('background-color'), "rgb(0, 255, 0)",
":valid should apply");
is(window.getComputedStyle(document.getElementById('obj'))
.getPropertyValue('background-color'), "rgb(0, 0, 0)",
"Nor :valid and :invalid should apply");
todo_is(window.getComputedStyle(document.getElementById('k'))
.getPropertyValue('background-color'), "rgb(0, 0, 0)",
"Nor :valid and :invalid should apply");
is(window.getComputedStyle(document.getElementById('s'))
.getPropertyValue('background-color'), "rgb(0, 255, 0)",
":valid pseudo-class should apply");
is(window.getComputedStyle(document.getElementById('i'))
.getPropertyValue('background-color'), "rgb(0, 255, 0)",
":valid pseudo-class should apply");
is(window.getComputedStyle(document.getElementById('t'))
.getPropertyValue('background-color'), "rgb(0, 255, 0)",
":valid pseudo-class should apply");
is(window.getComputedStyle(document.getElementById('b'))
.getPropertyValue('background-color'), "rgb(0, 255, 0)",
":valid pseudo-class should apply");
}
function checkSpecificWillValidate()
{
// fieldset, output, object, keygen (TODO) and select elements
ok(!document.getElementById('f').willValidate, "Fielset element should be barred from constraint validation");
ok(!document.getElementById('obj').willValidate, "Object element should be barred from constraint validation");
todo(!document.getElementById('k').willValidate, "Keygen element should be barred from constraint validation");
ok(document.getElementById('o').willValidate, "Output element should not be barred from constraint validation");
ok(document.getElementById('s').willValidate, "Select element should not be barred from constraint validation");
// input element
i = document.getElementById('i');
i.type = "hidden";
ok(!i.willValidate, "Hidden state input should be barred from constraint validation");
is(window.getComputedStyle(i).getPropertyValue('background-color'),
"rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
i.type = "reset";
ok(!i.willValidate, "Reset button state input should be barred from constraint validation");
is(window.getComputedStyle(i).getPropertyValue('background-color'),
"rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
i.type = "button";
ok(!i.willValidate, "Button state input should be barred from constraint validation");
is(window.getComputedStyle(i).getPropertyValue('background-color'),
"rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
i.type = "image";
ok(i.willValidate, "Image state input should not be barred from constraint validation");
is(window.getComputedStyle(i).getPropertyValue('background-color'),
"rgb(0, 255, 0)", ":valid and :invalid should apply");
i.type = "submit";
ok(i.willValidate, "Submit state input should not be barred from constraint validation");
is(window.getComputedStyle(i).getPropertyValue('background-color'),
"rgb(0, 255, 0)", ":valid and :invalid should apply");
i.type = "number";
ok(i.willValidate, "Number state input should not be barred from constraint validation");
is(window.getComputedStyle(i).getPropertyValue('background-color'),
"rgb(0, 255, 0)", ":valid pseudo-class should apply");
i.type = "";
i.readOnly = 'true';
ok(!i.willValidate, "Readonly input should be barred from constraint validation");
is(window.getComputedStyle(i).getPropertyValue('background-color'),
"rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
i.removeAttribute('readOnly');
ok(i.willValidate, "Default input element should not be barred from constraint validation");
is(window.getComputedStyle(i).getPropertyValue('background-color'),
"rgb(0, 255, 0)", ":valid pseudo-class should apply");
// button element
b = document.getElementById('b');
b.type = "reset";
ok(!b.willValidate, "Reset state button should be barred from constraint validation");
is(window.getComputedStyle(b).getPropertyValue('background-color'),
"rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
b.type = "button";
ok(!b.willValidate, "Button state button should be barred from constraint validation");
is(window.getComputedStyle(b).getPropertyValue('background-color'),
"rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
b.type = "submit";
ok(b.willValidate, "Submit state button should not be barred from constraint validation");
is(window.getComputedStyle(b).getPropertyValue('background-color'),
"rgb(0, 255, 0)", ":valid and :invalid should apply");
b.type = "";
ok(b.willValidate, "Default button element should not be barred from constraint validation");
is(window.getComputedStyle(b).getPropertyValue('background-color'),
"rgb(0, 255, 0)", ":valid pseudo-class should apply");
// textarea element
t = document.getElementById('t');
t.readOnly = true;
ok(!t.willValidate, "Readonly textarea should be barred from constraint validation");
is(window.getComputedStyle(t).getPropertyValue('background-color'),
"rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
t.removeAttribute('readOnly');
ok(t.willValidate, "Default textarea element should not be barred from constraint validation");
is(window.getComputedStyle(t).getPropertyValue('background-color'),
"rgb(0, 255, 0)", ":valid pseudo-class should apply");
// TODO: PROGRESS
// TODO: METER
}
function checkCommonWillValidate(element)
{
// Not checking the default value because it has been checked previously.
// Not checking output elements because they can't be disabled.
if (element.tagName != 'OUTPUT') {
element.disabled = true;
ok(!element.willValidate, "Disabled element should be barred from constraint validation");
is(window.getComputedStyle(element).getPropertyValue('background-color'),
"rgb(0, 0, 0)", "Nor :valid and :invalid should apply");
element.removeAttribute('disabled');
}
// TODO: If an element has a datalist element ancestor, it is barred from constraint validation.
}
function checkCustomError(element, isBarred)
{
element.setCustomValidity("message");
if (!isBarred) {
is(element.validationMessage, "message",
"When the element has a custom validity message, validation message should return it");
} else {
is(element.validationMessage, "",
"An element barred from constraint validation can't have a validation message");
}
ok(element.validity.customError, "The element should suffer from a custom error");
ok(!element.validity.valid, "The element should not be valid with a custom error");
if (element.tagName == "FIELDSET") {
is(window.getComputedStyle(element).getPropertyValue('background-color'),
isBarred ? "rgb(0, 255, 0)" : "rgb(255, 0, 0)",
":invalid pseudo-classs should apply" + element.tagName);
}
else {
is(window.getComputedStyle(element).getPropertyValue('background-color'),
isBarred ? "rgb(0, 0, 0)" : "rgb(255, 0, 0)",
":invalid pseudo-classs should apply" + element.tagName);
}
element.setCustomValidity("");
is(element.validationMessage, "", "The element should not have a validation message when reseted");
ok(!element.validity.customError, "The element should not suffer anymore from a custom error");
ok(element.validity.valid, "The element should now be valid");
is(window.getComputedStyle(element).getPropertyValue('background-color'),
isBarred && element.tagName != "FIELDSET" ? "rgb(0, 0, 0)" : "rgb(0, 255, 0)",
":valid pseudo-classs should apply");
}
function checkCheckValidity(element)
{
element.setCustomValidity("message");
ok(!element.checkValidity(), "checkValidity() should return false when the element is not valid");
ok(gInvalid, "Invalid event should have been handled");
gInvalid = false;
element.setCustomValidity("");
ok(element.checkValidity(), "Element should be valid");
ok(!gInvalid, "Invalid event should not have been handled");
}
function checkValidityStateObjectAliveWithoutElement(element)
{
// We are creating a temporary element and getting it's ValidityState object.
// Then, we make sure it is removed by the garbage collector and we check the
// ValidityState default values (it should not crash).
var v = document.createElement(element).validity;
SpecialPowers.gc();
ok(!v.valueMissing,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.typeMismatch,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.badInput,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.patternMismatch,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.tooLong,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.rangeUnderflow,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.rangeOverflow,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.stepMismatch,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(!v.customError,
"When the element is not alive, it shouldn't suffer from constraint validation");
ok(v.valid, "When the element is not alive, it should be valid");
}
checkConstraintValidationAPIExist(document.getElementById('f'));
checkConstraintValidationAPIExist(document.getElementById('i'));
checkConstraintValidationAPIExist(document.getElementById('b'));
checkConstraintValidationAPIExist(document.getElementById('s'));
checkConstraintValidationAPIExist(document.getElementById('t'));
checkConstraintValidationAPIExist(document.getElementById('k'));
checkConstraintValidationAPIExist(document.getElementById('o'));
checkConstraintValidationAPIExist(document.getElementById('obj'));
checkConstraintValidationAPIDefaultValues(document.getElementById('f'));
checkConstraintValidationAPIDefaultValues(document.getElementById('i'));
checkConstraintValidationAPIDefaultValues(document.getElementById('b'));
checkConstraintValidationAPIDefaultValues(document.getElementById('s'));
checkConstraintValidationAPIDefaultValues(document.getElementById('t'));
checkConstraintValidationAPIDefaultValues(document.getElementById('k'));
checkConstraintValidationAPIDefaultValues(document.getElementById('o'));
checkConstraintValidationAPIDefaultValues(document.getElementById('obj'));
checkDefaultPseudoClass();
checkSpecificWillValidate();
// Not checking button, fieldset, object and keygen
// because they are always barred from constraint validation.
checkCommonWillValidate(document.getElementById('i'));
checkCommonWillValidate(document.getElementById('s'));
checkCommonWillValidate(document.getElementById('t'));
checkCommonWillValidate(document.getElementById('o'));
/* TODO: add "keygen" element */
checkCustomError(document.getElementById('i'), false);
checkCustomError(document.getElementById('s'), false);
checkCustomError(document.getElementById('t'), false);
checkCustomError(document.getElementById('o'), false);
checkCustomError(document.getElementById('b'), false);
checkCustomError(document.getElementById('f'), true);
checkCustomError(document.getElementById('obj'), true);
// Not checking button, fieldset, object and keygen
// because they are always barred from constraint validation.
checkCheckValidity(document.getElementById('i'));
checkCheckValidity(document.getElementById('s'));
checkCheckValidity(document.getElementById('t'));
checkCheckValidity(document.getElementById('o'));
/* TODO: add "keygen" element */
checkValidityStateObjectAliveWithoutElement("fieldset");
checkValidityStateObjectAliveWithoutElement("input");
checkValidityStateObjectAliveWithoutElement("button");
checkValidityStateObjectAliveWithoutElement("select");
checkValidityStateObjectAliveWithoutElement("textarea");
checkValidityStateObjectAliveWithoutElement("output");
checkValidityStateObjectAliveWithoutElement("object");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,19 +0,0 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test for constraint validation of form controls not in documents</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
test(function() {
var input = document.createElement('input');
input.required = true;
assert_false(input.checkValidity());
}, "Should validate input not in document");
test(function() {
var textarea = document.createElement('textarea');
textarea.required = true;
assert_false(textarea.checkValidity());
}, "Should validate textarea not in document");
</script>

Просмотреть файл

@ -1,57 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=874640
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 874640</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 874640 **/
var states = [
// dom.experimental_forms, dom.forms.datetime, dom.forms.datetime.others, expectedValueAsDate
[ 'true', 'true', ,'true', 'true' ],
[ 'true', 'false', 'false', 'true' ],
[ 'false', 'true', 'false', 'true' ],
[ 'false', 'false', 'true', 'true' ],
[ 'false', 'false', 'false', 'false' ],
'end'
];
SimpleTest.waitForExplicitFinish();
function runTest(iframe) {
var state = states.shift();
if (state == 'end') {
SimpleTest.finish();
return;
}
SpecialPowers.pushPrefEnv({"set":[
["dom.experimental_forms", state[0] === 'true'],
["dom.forms.datetime", state[1] === 'true'],
["dom.forms.datetime.others", state[2] === 'true']]},
function() {
iframe.srcdoc = '<script>' +
'parent.is("valueAsDate" in document.createElement("input"), ' +
state[3] + ', "valueAsDate presence state should be ' + state[3] + '");' +
'<\/script>'
});
}
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=874640">Mozilla Bug 874640</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe onload='runTest(this);'></iframe>
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -1,751 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=769370
-->
<head>
<title>Test for input.valueAsDate</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=769370">Mozilla Bug 769370</a>
<iframe name="testFrame" style="display: none"></iframe>
<p id="display"></p>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 769370**/
/**
* This test is checking .valueAsDate.
*/
var element = document.createElement("input");
var validTypes =
[
["text", false],
["password", false],
["search", false],
["tel", false],
["email", false],
["url", false],
["hidden", false],
["checkbox", false],
["radio", false],
["file", false],
["submit", false],
["image", false],
["reset", false],
["button", false],
["number", false],
["range", false],
["date", true],
["time", true],
["color", false],
["month", true],
["week", true],
["datetime-local", true],
];
function checkAvailability()
{
for (let data of validTypes) {
var exceptionCatched = false;
element.type = data[0];
try {
element.valueAsDate;
} catch (e) {
exceptionCatched = true;
}
is(exceptionCatched, false,
"valueAsDate shouldn't throw exception on getting");
exceptionCatched = false;
try {
element.valueAsDate = new Date();
} catch (e) {
exceptionCatched = true;
}
is(exceptionCatched, !data[1], "valueAsDate for " + data[0] +
" availability is not correct");
}
}
function checkGarbageValues()
{
for (let type of validTypes) {
if (!type[1]) {
continue;
}
type = type[0];
var element = document.createElement('input');
element.type = type;
element.value = "test";
element.valueAsDate = null;
is(element.value, "", "valueAsDate should set the value to the empty string");
element.value = "test";
element.valueAsDate = undefined;
is(element.value, "", "valueAsDate should set the value to the empty string");
element.value = "test";
element.valueAsDate = new Date(NaN);
is(element.value, "", "valueAsDate should set the value to the empty string");
var illegalValues = [
"foobar", 42, {}, function() { return 42; }, function() { return Date(); }
];
for (let value of illegalValues) {
try {
var caught = false;
element.valueAsDate = value;
} catch(e) {
is(e.name, "TypeError", "Exception should be 'TypeError'.");
caught = true;
}
ok(caught, "Assigning " + value + " to .valueAsDate should throw");
}
}
}
function checkDateGet()
{
var validData =
[
[ "2012-07-12", 1342051200000 ],
[ "1970-01-01", 0 ],
[ "1970-01-02", 86400000 ],
[ "1969-12-31", -86400000 ],
[ "0311-01-31", -52350451200000 ],
[ "275760-09-13", 8640000000000000 ],
[ "0001-01-01", -62135596800000 ],
[ "2012-02-29", 1330473600000 ],
[ "2011-02-28", 1298851200000 ],
];
var invalidData =
[
[ "invaliddate" ],
[ "-001-12-31" ],
[ "901-12-31" ],
[ "1901-13-31" ],
[ "1901-12-32" ],
[ "1901-00-12" ],
[ "1901-01-00" ],
[ "1900-02-29" ],
[ "0000-01-01" ],
[ "" ],
// This date is valid for the input element, but is out of
// the date object range. In this case, on getting valueAsDate,
// a Date object will be created, but it will have a NaN internal value,
// and will return the string "Invalid Date".
[ "275760-09-14", true ],
];
element.type = "date";
for (let data of validData) {
element.value = data[0];
is(element.valueAsDate.valueOf(), data[1],
"valueAsDate should return the " +
"valid date object representing this date");
}
for (let data of invalidData) {
element.value = data[0];
if (data[1]) {
is(String(element.valueAsDate), "Invalid Date",
"valueAsDate should return an invalid Date object " +
"when the element value is not a valid date");
} else {
is(element.valueAsDate, null,
"valueAsDate should return null " +
"when the element value is not a valid date");
}
}
}
function checkDateSet()
{
var testData =
[
[ 1342051200000, "2012-07-12" ],
[ 0, "1970-01-01" ],
// Maximum valid date (limited by the ecma date object range).
[ 8640000000000000, "275760-09-13" ],
// Minimum valid date (limited by the input element minimum valid value).
[ -62135596800000 , "0001-01-01" ],
[ 1330473600000, "2012-02-29" ],
[ 1298851200000, "2011-02-28" ],
// "Values must be truncated to valid dates"
[ 42.1234, "1970-01-01" ],
[ 123.123456789123, "1970-01-01" ],
[ 1e-1, "1970-01-01" ],
[ 1298851200010, "2011-02-28" ],
[ -1, "1969-12-31" ],
[ -86400000, "1969-12-31" ],
[ 86400000, "1970-01-02" ],
// Negative years, this is out of range for the input element,
// the corresponding date string is the empty string
[ -62135596800001, "" ],
// Invalid dates.
];
element.type = "date";
for (let data of testData) {
element.valueAsDate = new Date(data[0]);
is(element.value, data[1], "valueAsDate should set the value to "
+ data[1]);
element.valueAsDate = new testFrame.Date(data[0]);
is(element.value, data[1], "valueAsDate with other-global date should " +
"set the value to " + data[1]);
}
}
function checkTimeGet()
{
var tests = [
// Some invalid values to begin.
{ value: "", result: null },
{ value: "foobar", result: null },
{ value: "00:", result: null },
{ value: "24:00", result: null },
{ value: "00:99", result: null },
{ value: "00:00:", result: null },
{ value: "00:00:99", result: null },
{ value: "00:00:00:", result: null },
{ value: "00:00:00.", result: null },
{ value: "00:00:00.0000", result: null },
// Some simple valid values.
{ value: "00:00", result: { time: 0, hours: 0, minutes: 0, seconds: 0, ms: 0 } },
{ value: "00:01", result: { time: 60000, hours: 0, minutes: 1, seconds: 0, ms: 0 } },
{ value: "01:00", result: { time: 3600000, hours: 1, minutes: 0, seconds: 0, ms: 0 } },
{ value: "01:01", result: { time: 3660000, hours: 1, minutes: 1, seconds: 0, ms: 0 } },
{ value: "13:37", result: { time: 49020000, hours: 13, minutes: 37, seconds: 0, ms: 0 } },
// Valid values including seconds.
{ value: "00:00:01", result: { time: 1000, hours: 0, minutes: 0, seconds: 1, ms: 0 } },
{ value: "13:37:42", result: { time: 49062000, hours: 13, minutes: 37, seconds: 42, ms: 0 } },
// Valid values including seconds fractions.
{ value: "00:00:00.001", result: { time: 1, hours: 0, minutes: 0, seconds: 0, ms: 1 } },
{ value: "00:00:00.123", result: { time: 123, hours: 0, minutes: 0, seconds: 0, ms: 123 } },
{ value: "00:00:00.100", result: { time: 100, hours: 0, minutes: 0, seconds: 0, ms: 100 } },
{ value: "00:00:00.000", result: { time: 0, hours: 0, minutes: 0, seconds: 0, ms: 0 } },
{ value: "20:17:31.142", result: { time: 73051142, hours: 20, minutes: 17, seconds: 31, ms: 142 } },
// Highest possible value.
{ value: "23:59:59.999", result: { time: 86399999, hours: 23, minutes: 59, seconds: 59, ms: 999 } },
// Some values with one or two digits for the fraction of seconds.
{ value: "00:00:00.1", result: { time: 100, hours: 0, minutes: 0, seconds: 0, ms: 100 } },
{ value: "00:00:00.14", result: { time: 140, hours: 0, minutes: 0, seconds: 0, ms: 140 } },
{ value: "13:37:42.7", result: { time: 49062700, hours: 13, minutes: 37, seconds: 42, ms: 700 } },
{ value: "23:31:12.23", result: { time: 84672230, hours: 23, minutes: 31, seconds: 12, ms: 230 } },
];
var element = document.createElement('input');
element.type = 'time';
for (let test of tests) {
element.value = test.value;
if (test.result === null) {
is(element.valueAsDate, null, "element.valueAsDate should return null");
} else {
var date = element.valueAsDate;
isnot(date, null, "element.valueAsDate should not be null");
is(date.getTime(), test.result.time);
is(date.getUTCHours(), test.result.hours);
is(date.getUTCMinutes(), test.result.minutes);
is(date.getUTCSeconds(), test.result.seconds);
is(date.getUTCMilliseconds(), test.result.ms);
}
}
}
function checkTimeSet()
{
var tests = [
// Simple tests.
{ value: 0, result: "00:00" },
{ value: 1, result: "00:00:00.001" },
{ value: 100, result: "00:00:00.100" },
{ value: 1000, result: "00:00:01" },
{ value: 60000, result: "00:01" },
{ value: 3600000, result: "01:00" },
{ value: 83622234, result: "23:13:42.234" },
// Some edge cases.
{ value: 86400000, result: "00:00" },
{ value: 86400001, result: "00:00:00.001" },
{ value: 170022234, result: "23:13:42.234" },
{ value: 432000000, result: "00:00" },
{ value: -1, result: "23:59:59.999" },
{ value: -86400000, result: "00:00" },
{ value: -86400001, result: "23:59:59.999" },
{ value: -56789, result: "23:59:03.211" },
{ value: 0.9, result: "00:00" },
];
var element = document.createElement('input');
element.type = 'time';
for (let test of tests) {
element.valueAsDate = new Date(test.value);
is(element.value, test.result,
"element.value should have been changed by setting valueAsDate");
}
}
function checkWithBustedPrototype()
{
for (let type of validTypes) {
if (!type[1]) {
continue;
}
type = type[0];
var element = document.createElement('input');
element.type = type;
var backupPrototype = {};
backupPrototype.getUTCFullYear = Date.prototype.getUTCFullYear;
backupPrototype.getUTCMonth = Date.prototype.getUTCMonth;
backupPrototype.getUTCDate = Date.prototype.getUTCDate;
backupPrototype.getTime = Date.prototype.getTime;
backupPrototype.setUTCFullYear = Date.prototype.setUTCFullYear;
Date.prototype.getUTCFullYear = function() { return {}; };
Date.prototype.getUTCMonth = function() { return {}; };
Date.prototype.getUTCDate = function() { return {}; };
Date.prototype.getTime = function() { return {}; };
Date.prototype.setUTCFullYear = function(y,m,d) { };
element.valueAsDate = new Date();
isnot(element.valueAsDate, null, ".valueAsDate should not return null");
// The object returned by element.valueAsDate should return a Date object
// with the same prototype:
is(element.valueAsDate.getUTCFullYear, Date.prototype.getUTCFullYear,
"prototype is the same");
is(element.valueAsDate.getUTCMonth, Date.prototype.getUTCMonth,
"prototype is the same");
is(element.valueAsDate.getUTCDate, Date.prototype.getUTCDate,
"prototype is the same");
is(element.valueAsDate.getTime, Date.prototype.getTime,
"prototype is the same");
is(element.valueAsDate.setUTCFullYear, Date.prototype.setUTCFullYear,
"prototype is the same");
// However the Date should have the correct information.
// Skip type=month for now, since .valueAsNumber returns number of months
// and not milliseconds.
if (type != "month") {
var witnessDate = new Date(element.valueAsNumber);
is(element.valueAsDate.valueOf(), witnessDate.valueOf(), "correct Date");
}
// Same test as above but using NaN instead of {}.
Date.prototype.getUTCFullYear = function() { return NaN; };
Date.prototype.getUTCMonth = function() { return NaN; };
Date.prototype.getUTCDate = function() { return NaN; };
Date.prototype.getTime = function() { return NaN; };
Date.prototype.setUTCFullYear = function(y,m,d) { };
element.valueAsDate = new Date();
isnot(element.valueAsDate, null, ".valueAsDate should not return null");
// The object returned by element.valueAsDate should return a Date object
// with the same prototype:
is(element.valueAsDate.getUTCFullYear, Date.prototype.getUTCFullYear,
"prototype is the same");
is(element.valueAsDate.getUTCMonth, Date.prototype.getUTCMonth,
"prototype is the same");
is(element.valueAsDate.getUTCDate, Date.prototype.getUTCDate,
"prototype is the same");
is(element.valueAsDate.getTime, Date.prototype.getTime,
"prototype is the same");
is(element.valueAsDate.setUTCFullYear, Date.prototype.setUTCFullYear,
"prototype is the same");
// However the Date should have the correct information.
// Skip type=month for now, since .valueAsNumber returns number of months
// and not milliseconds.
if (type != "month") {
var witnessDate = new Date(element.valueAsNumber);
is(element.valueAsDate.valueOf(), witnessDate.valueOf(), "correct Date");
}
Date.prototype.getUTCFullYear = backupPrototype.getUTCFullYear;
Date.prototype.getUTCMonth = backupPrototype.getUTCMonth;
Date.prototype.getUTCDate = backupPrototype.getUTCDate;
Date.prototype.getTime = backupPrototype.getTime;
Date.prototype.setUTCFullYear = backupPrototype.setUTCFullYear;
}
}
function checkMonthGet()
{
var validData =
[
[ "2016-07", 1467331200000 ],
[ "1970-01", 0 ],
[ "1970-02", 2678400000 ],
[ "1969-12", -2678400000 ],
[ "0001-01", -62135596800000 ],
[ "275760-09", 8639998963200000 ],
];
var invalidData =
[
[ "invalidmonth" ],
[ "0000-01" ],
[ "2016-00" ],
[ "123-01" ],
[ "2017-13" ],
[ "" ],
// This month is valid for the input element, but is out of
// the date object range. In this case, on getting valueAsDate,
// a Date object will be created, but it will have a NaN internal value,
// and will return the string "Invalid Date".
[ "275760-10", true ],
];
element.type = "month";
for (let data of validData) {
element.value = data[0];
is(element.valueAsDate.valueOf(), data[1],
"valueAsDate should return the " +
"valid date object representing this month");
}
for (let data of invalidData) {
element.value = data[0];
if (data[1]) {
is(String(element.valueAsDate), "Invalid Date",
"valueAsDate should return an invalid Date object " +
"when the element value is not a valid month");
} else {
is(element.valueAsDate, null,
"valueAsDate should return null " +
"when the element value is not a valid month");
}
}
}
function checkMonthSet()
{
var testData =
[
[ 1342051200000, "2012-07" ],
[ 0, "1970-01" ],
// Maximum valid month (limited by the ecma date object range).
[ 8640000000000000, "275760-09" ],
// Minimum valid month (limited by the input element minimum valid value).
[ -62135596800000 , "0001-01" ],
[ 1330473600000, "2012-02" ],
[ 1298851200000, "2011-02" ],
// "Values must be truncated to valid months"
[ 42.1234, "1970-01" ],
[ 123.123456789123, "1970-01" ],
[ 1e-1, "1970-01" ],
[ 1298851200010, "2011-02" ],
[ -1, "1969-12" ],
[ -86400000, "1969-12" ],
[ 86400000, "1970-01" ],
// Negative years, this is out of range for the input element,
// the corresponding month string is the empty string
[ -62135596800001, "" ],
];
element.type = "month";
for (let data of testData) {
element.valueAsDate = new Date(data[0]);
is(element.value, data[1], "valueAsDate should set the value to "
+ data[1]);
element.valueAsDate = new testFrame.Date(data[0]);
is(element.value, data[1], "valueAsDate with other-global date should " +
"set the value to " + data[1]);
}
}
function checkWeekGet()
{
var validData =
[
// Common years starting on different days of week.
[ "2007-W01", Date.UTC(2007, 0, 1) ], // Mon
[ "2013-W01", Date.UTC(2012, 11, 31) ], // Tue
[ "2014-W01", Date.UTC(2013, 11, 30) ], // Wed
[ "2015-W01", Date.UTC(2014, 11, 29) ], // Thu
[ "2010-W01", Date.UTC(2010, 0, 4) ], // Fri
[ "2011-W01", Date.UTC(2011, 0, 3) ], // Sat
[ "2017-W01", Date.UTC(2017, 0, 2) ], // Sun
// Common years ending on different days of week.
[ "2007-W52", Date.UTC(2007, 11, 24) ], // Mon
[ "2013-W52", Date.UTC(2013, 11, 23) ], // Tue
[ "2014-W52", Date.UTC(2014, 11, 22) ], // Wed
[ "2015-W53", Date.UTC(2015, 11, 28) ], // Thu
[ "2010-W52", Date.UTC(2010, 11, 27) ], // Fri
[ "2011-W52", Date.UTC(2011, 11, 26) ], // Sat
[ "2017-W52", Date.UTC(2017, 11, 25) ], // Sun
// Leap years starting on different days of week.
[ "1996-W01", Date.UTC(1996, 0, 1) ], // Mon
[ "2008-W01", Date.UTC(2007, 11, 31) ], // Tue
[ "2020-W01", Date.UTC(2019, 11, 30) ], // Wed
[ "2004-W01", Date.UTC(2003, 11, 29) ], // Thu
[ "2016-W01", Date.UTC(2016, 0, 4) ], // Fri
[ "2000-W01", Date.UTC(2000, 0, 3) ], // Sat
[ "2012-W01", Date.UTC(2012, 0, 2) ], // Sun
// Leap years ending on different days of week.
[ "2012-W52", Date.UTC(2012, 11, 24) ], // Mon
[ "2024-W52", Date.UTC(2024, 11, 23) ], // Tue
[ "1980-W52", Date.UTC(1980, 11, 22) ], // Wed
[ "1992-W53", Date.UTC(1992, 11, 28) ], // Thu
[ "2004-W53", Date.UTC(2004, 11, 27) ], // Fri
[ "1988-W52", Date.UTC(1988, 11, 26) ], // Sat
[ "2000-W52", Date.UTC(2000, 11, 25) ], // Sun
// Other normal cases.
[ "2016-W36", 1473033600000 ],
[ "1969-W52", -864000000 ],
[ "1970-W01", -259200000 ],
[ "275760-W37", 8639999568000000 ],
];
var invalidData =
[
[ "invalidweek" ],
[ "0000-W01" ],
[ "2016-W00" ],
[ "123-W01" ],
[ "2016-W53" ],
[ "" ],
// This week is valid for the input element, but is out of
// the date object range. In this case, on getting valueAsDate,
// a Date object will be created, but it will have a NaN internal value,
// and will return the string "Invalid Date".
[ "275760-W38", true ],
];
element.type = "week";
for (let data of validData) {
element.value = data[0];
is(element.valueAsDate.valueOf(), data[1],
"valueAsDate should return the " +
"valid date object representing this week");
}
for (let data of invalidData) {
element.value = data[0];
if (data[1]) {
is(String(element.valueAsDate), "Invalid Date",
"valueAsDate should return an invalid Date object " +
"when the element value is not a valid week");
} else {
is(element.valueAsDate, null,
"valueAsDate should return null " +
"when the element value is not a valid week");
}
}
}
function checkWeekSet()
{
var testData =
[
// Common years starting on different days of week.
[ Date.UTC(2007, 0, 1), "2007-W01" ], // Mon
[ Date.UTC(2013, 0, 1), "2013-W01" ], // Tue
[ Date.UTC(2014, 0, 1), "2014-W01" ], // Wed
[ Date.UTC(2015, 0, 1), "2015-W01" ], // Thu
[ Date.UTC(2010, 0, 1), "2009-W53" ], // Fri
[ Date.UTC(2011, 0, 1), "2010-W52" ], // Sat
[ Date.UTC(2017, 0, 1), "2016-W52" ], // Sun
// Common years ending on different days of week.
[ Date.UTC(2007, 11, 31), "2008-W01" ], // Mon
[ Date.UTC(2013, 11, 31), "2014-W01" ], // Tue
[ Date.UTC(2014, 11, 31), "2015-W01" ], // Wed
[ Date.UTC(2015, 11, 31), "2015-W53" ], // Thu
[ Date.UTC(2010, 11, 31), "2010-W52" ], // Fri
[ Date.UTC(2011, 11, 31), "2011-W52" ], // Sat
[ Date.UTC(2017, 11, 31), "2017-W52" ], // Sun
// Leap years starting on different days of week.
[ Date.UTC(1996, 0, 1), "1996-W01" ], // Mon
[ Date.UTC(2008, 0, 1), "2008-W01" ], // Tue
[ Date.UTC(2020, 0, 1), "2020-W01" ], // Wed
[ Date.UTC(2004, 0, 1), "2004-W01" ], // Thu
[ Date.UTC(2016, 0, 1), "2015-W53" ], // Fri
[ Date.UTC(2000, 0, 1), "1999-W52" ], // Sat
[ Date.UTC(2012, 0, 1), "2011-W52" ], // Sun
// Leap years ending on different days of week.
[ Date.UTC(2012, 11, 31), "2013-W01" ], // Mon
[ Date.UTC(2024, 11, 31), "2025-W01" ], // Tue
[ Date.UTC(1980, 11, 31), "1981-W01" ], // Wed
[ Date.UTC(1992, 11, 31), "1992-W53" ], // Thu
[ Date.UTC(2004, 11, 31), "2004-W53" ], // Fri
[ Date.UTC(1988, 11, 31), "1988-W52" ], // Sat
[ Date.UTC(2000, 11, 31), "2000-W52" ], // Sun
// Other normal cases.
[ Date.UTC(2016, 8, 9), "2016-W36" ],
[ Date.UTC(2010, 0, 3), "2009-W53" ],
[ Date.UTC(2010, 0, 4), "2010-W01" ],
[ Date.UTC(2010, 0, 10), "2010-W01" ],
[ Date.UTC(2010, 0, 11), "2010-W02" ],
[ 0, "1970-W01" ],
// Maximum valid month (limited by the ecma date object range).
[ 8640000000000000, "275760-W37" ],
// Minimum valid month (limited by the input element minimum valid value).
[ -62135596800000 , "0001-W01" ],
// "Values must be truncated to valid week"
[ 42.1234, "1970-W01" ],
[ 123.123456789123, "1970-W01" ],
[ 1e-1, "1970-W01" ],
[ -1.1, "1970-W01" ],
[ -345600000, "1969-W52" ],
// Negative years, this is out of range for the input element,
// the corresponding week string is the empty string
[ -62135596800001, "" ],
];
element.type = "week";
for (let data of testData) {
element.valueAsDate = new Date(data[0]);
is(element.value, data[1], "valueAsDate should set the value to "
+ data[1]);
element.valueAsDate = new testFrame.Date(data[0]);
is(element.value, data[1], "valueAsDate with other-global date should " +
"set the value to " + data[1]);
}
}
function checkDatetimeLocalGet()
{
var validData =
[
// Simple cases.
[ "2016-12-27T10:30", Date.UTC(2016, 11, 27, 10, 30, 0) ],
[ "2016-12-27T10:30:40", Date.UTC(2016, 11, 27, 10, 30, 40) ],
[ "2016-12-27T10:30:40.567", Date.UTC(2016, 11, 27, 10, 30, 40, 567) ],
[ "1969-12-31T12:00:00", Date.UTC(1969, 11, 31, 12, 0, 0) ],
[ "1970-01-01T00:00", 0 ],
// Leap years.
[ "1804-02-29 12:34", Date.UTC(1804, 1, 29, 12, 34, 0) ],
[ "2016-02-29T12:34", Date.UTC(2016, 1, 29, 12, 34, 0) ],
[ "2016-12-31T12:34:56", Date.UTC(2016, 11, 31, 12, 34, 56) ],
[ "2016-01-01T12:34:56.789", Date.UTC(2016, 0, 1, 12, 34, 56, 789) ],
[ "2017-01-01 12:34:56.789", Date.UTC(2017, 0, 1, 12, 34, 56, 789) ],
// Maximum valid datetime-local (limited by the ecma date object range).
[ "275760-09-13T00:00", 8640000000000000 ],
// Minimum valid datetime-local (limited by the input element minimum valid value).
[ "0001-01-01T00:00", -62135596800000 ],
];
var invalidData =
[
[ "invaliddateime-local" ],
[ "0000-01-01T00:00" ],
[ "2016-12-25T00:00Z" ],
[ "2015-02-29T12:34" ],
[ "1-1-1T12:00" ],
[ "" ],
// This datetime-local is valid for the input element, but is out of the
// date object range. In this case, on getting valueAsDate, a Date object
// will be created, but it will have a NaN internal value, and will return
// the string "Invalid Date".
[ "275760-09-13T12:00", true ],
];
element.type = "datetime-local";
for (let data of validData) {
element.value = data[0];
is(element.valueAsDate.valueOf(), data[1],
"valueAsDate should return the " +
"valid date object representing this datetime-local");
}
for (let data of invalidData) {
element.value = data[0];
if (data[1]) {
is(String(element.valueAsDate), "Invalid Date",
"valueAsDate should return an invalid Date object " +
"when the element value is not a valid datetime-local");
} else {
is(element.valueAsDate, null,
"valueAsDate should return null " +
"when the element value is not a valid datetime-local");
}
}
}
function checkDatetimeLocalSet()
{
var testData =
[
// Simple cases.
[ Date.UTC(2016, 11, 27, 10, 30, 0), "2016-12-27T10:30" ],
[ Date.UTC(2016, 11, 27, 10, 30, 30), "2016-12-27T10:30:30" ],
[ Date.UTC(1999, 11, 31, 23, 59, 59), "1999-12-31T23:59:59" ],
[ Date.UTC(1999, 11, 31, 23, 59, 59, 999), "1999-12-31T23:59:59.999" ],
[ Date.UTC(123456, 7, 8, 9, 10), "123456-08-08T09:10" ],
[ 0, "1970-01-01T00:00" ],
// Maximum valid datetime-local (limited by the ecma date object range).
[ 8640000000000000, "275760-09-13T00:00" ],
// Minimum valid datetime-local (limited by the input element minimum valid value).
[ -62135596800000, "0001-01-01T00:00" ],
// Leap years.
[ Date.UTC(1804, 1, 29, 12, 34, 0), "1804-02-29T12:34" ],
[ Date.UTC(2016, 1, 29, 12, 34, 0), "2016-02-29T12:34" ],
[ Date.UTC(2016, 11, 31, 12, 34, 56), "2016-12-31T12:34:56" ],
[ Date.UTC(2016, 0, 1, 12, 34, 56, 789), "2016-01-01T12:34:56.789" ],
[ Date.UTC(2017, 0, 1, 12, 34, 56, 789), "2017-01-01T12:34:56.789" ],
// "Values must be truncated to valid datetime-local"
[ 123.123456789123, "1970-01-01T00:00:00.123" ],
[ 1e-1, "1970-01-01T00:00" ],
[ -1.1, "1969-12-31T23:59:59.999" ],
[ -345600000, "1969-12-28T00:00" ],
// Negative years, this is out of range for the input element,
// the corresponding datetime-local string is the empty string
[ -62135596800001, "" ],
];
element.type = "datetime-local";
for (let data of testData) {
element.valueAsDate = new Date(data[0]);
is(element.value, data[1], "valueAsDate should set the value to " +
data[1]);
element.valueAsDate = new testFrame.Date(data[0]);
is(element.value, data[1], "valueAsDate with other-global date should " +
"set the value to " + data[1]);
}
}
checkAvailability();
checkGarbageValues();
checkWithBustedPrototype();
// Test <input type='date'>.
checkDateGet();
checkDateSet();
// Test <input type='time'>.
checkTimeGet();
checkTimeSet();
// Test <input type='month'>.
checkMonthGet();
checkMonthSet();
// Test <input type='week'>.
checkWeekGet();
checkWeekSet();
// Test <input type='datetime-local'>.
checkDatetimeLocalGet();
checkDatetimeLocalSet();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,858 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=636737
-->
<head>
<title>Test for Bug input.valueAsNumber</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=636737">Mozilla Bug 636737</a>
<p id="display"></p>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 636737 **/
/**
* This test is checking .valueAsNumber.
*/
function checkAvailability()
{
var testData =
[
["text", false],
["password", false],
["search", false],
["tel", false],
["email", false],
["url", false],
["hidden", false],
["checkbox", false],
["radio", false],
["file", false],
["submit", false],
["image", false],
["reset", false],
["button", false],
["number", true],
["range", true],
["date", true],
["time", true],
["color", false],
["month", true],
["week", true],
["datetime-local", true],
];
var element = document.createElement('input');
for (let data of testData) {
var exceptionCatched = false;
element.type = data[0];
try {
element.valueAsNumber;
} catch (e) {
exceptionCatched = true;
}
is(exceptionCatched, false,
"valueAsNumber shouldn't throw exception on getting");
exceptionCatched = false;
try {
element.valueAsNumber = 42;
} catch (e) {
exceptionCatched = true;
}
is(exceptionCatched, !data[1], "valueAsNumber for " + data[0] +
" availability is not correct");
}
}
function checkNumberGet()
{
var testData =
[
["42", 42],
["-42", -42], // should work for negative values
["42.1234", 42.1234],
["123.123456789123", 123.123456789123], // double precision
["1e2", 100], // e should be usable
["2e1", 20],
["1e-1", 0.1], // value after e can be negative
["1E2", 100], // E can be used instead of e
["e", null],
["e2", null],
["1e0.1", null],
["", null], // the empty string is not a number
["foo", null],
["42,13", null], // comma can't be used as a decimal separator
];
var element = document.createElement('input');
element.type = "number";
for (let data of testData) {
element.value = data[0];
// Given that NaN != NaN, we have to use null when the expected value is NaN.
if (data[1] != null) {
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
"floating point representation of the value");
} else {
ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " +
"when the element value is not a number");
}
}
}
function checkNumberSet()
{
var testData =
[
[42, "42"],
[-42, "-42"], // should work for negative values
[42.1234, "42.1234"],
[123.123456789123, "123.123456789123"], // double precision
[1e2, "100"], // e should be usable
[2e1, "20"],
[1e-1, "0.1"], // value after e can be negative
[1E2, "100"], // E can be used instead of e
// Setting a string will set NaN.
["foo", ""],
// "" is converted to 0.
["", "0"],
[42, "42"], // Keep this here, it is used by the next test.
// Setting Infinity should throw and not change the current value.
[Infinity, "42", true],
[-Infinity, "42", true],
// Setting NaN should change the value to the empty string.
[NaN, ""],
];
var element = document.createElement('input');
element.type = "number";
for (let data of testData) {
var caught = false;
try {
element.valueAsNumber = data[0];
is(element.value, data[1],
"valueAsNumber should be able to set the value");
} catch (e) {
caught = true;
}
if (data[2]) {
ok(caught, "valueAsNumber should have thrown");
is(element.value, data[1], "value should not have changed");
} else {
ok(!caught, "valueAsNumber should not have thrown");
}
}
}
function checkRangeGet()
{
// For type=range we should never get NaN since the user agent is required
// to fix up the input's value to be something sensible.
var min = -200;
var max = 200;
var defaultValue = min + (max - min)/2;
var testData =
[
["42", 42],
["-42", -42], // should work for negative values
["42.1234", 42.1234],
["123.123456789123", 123.123456789123], // double precision
["1e2", 100], // e should be usable
["2e1", 20],
["1e-1", 0.1], // value after e can be negative
["1E2", 100], // E can be used instead of e
["e", defaultValue],
["e2", defaultValue],
["1e0.1", defaultValue],
["", defaultValue],
["foo", defaultValue],
["42,13", defaultValue],
];
var element = document.createElement('input');
element.type = "range";
element.setAttribute("min", min); // avoids out of range sanitization
element.setAttribute("max", max);
element.setAttribute("step", "any"); // avoids step mismatch sanitization
for (let data of testData) {
element.value = data[0];
// Given that NaN != NaN, we have to use null when the expected value is NaN.
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
"floating point representation of the value");
}
}
function checkRangeSet()
{
var min = -200;
var max = 200;
var defaultValue = String(min + (max - min)/2);
var testData =
[
[42, "42"],
[-42, "-42"], // should work for negative values
[42.1234, "42.1234"],
[123.123456789123, "123.123456789123"], // double precision
[1e2, "100"], // e should be usable
[2e1, "20"],
[1e-1, "0.1"], // value after e can be negative
[1E2, "100"], // E can be used instead of e
["foo", defaultValue],
["", defaultValue],
[42, "42"], // Keep this here, it is used by the next test.
// Setting Infinity should throw and not change the current value.
[Infinity, "42", true],
[-Infinity, "42", true],
// Setting NaN should change the value to the empty string.
[NaN, defaultValue],
];
var element = document.createElement('input');
element.type = "range";
element.setAttribute("min", min); // avoids out of range sanitization
element.setAttribute("max", max);
element.setAttribute("step", "any"); // avoids step mismatch sanitization
for (let data of testData) {
var caught = false;
try {
element.valueAsNumber = data[0];
is(element.value, data[1],
"valueAsNumber should be able to set the value");
} catch (e) {
caught = true;
}
if (data[2]) {
ok(caught, "valueAsNumber should have thrown");
is(element.value, data[1], "value should not have changed");
} else {
ok(!caught, "valueAsNumber should not have thrown");
}
}
}
function checkDateGet()
{
var validData =
[
[ "2012-07-12", 1342051200000 ],
[ "1970-01-01", 0 ],
// We are supposed to support at least until this date.
// (corresponding to the date object maximal value)
[ "275760-09-13", 8640000000000000 ],
// Minimum valid date (limited by the input element minimum valid value)
[ "0001-01-01", -62135596800000 ],
[ "2012-02-29", 1330473600000 ],
[ "2011-02-28", 1298851200000 ],
];
var invalidData =
[
"invaliddate",
"",
"275760-09-14",
"999-12-31",
"-001-12-31",
"0000-01-01",
"2011-02-29",
"1901-13-31",
"1901-12-32",
"1901-00-12",
"1901-01-00",
"1900-02-29",
];
var element = document.createElement('input');
element.type = "date";
for (let data of validData) {
element.value = data[0];
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
"timestamp representing this date");
}
for (let data of invalidData) {
element.value = data;
ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " +
"when the element value is not a valid date");
}
}
function checkDateSet()
{
var testData =
[
[ 1342051200000, "2012-07-12" ],
[ 0, "1970-01-01" ],
// Maximum valid date (limited by the ecma date object range).
[ 8640000000000000, "275760-09-13" ],
// Minimum valid date (limited by the input element minimum valid value)
[ -62135596800000, "0001-01-01" ],
[ 1330473600000, "2012-02-29" ],
[ 1298851200000, "2011-02-28" ],
// "Values must be truncated to valid dates"
[ 42.1234, "1970-01-01" ],
[ 123.123456789123, "1970-01-01" ],
[ 1e2, "1970-01-01" ],
[ 1E9, "1970-01-12" ],
[ 1e-1, "1970-01-01" ],
[ 2e10, "1970-08-20" ],
[ 1298851200010, "2011-02-28" ],
[ -1, "1969-12-31" ],
[ -86400000, "1969-12-31" ],
[ 86400000, "1970-01-02" ],
// Invalid numbers.
// Those are implicitly converted to numbers
[ "", "1970-01-01" ],
[ true, "1970-01-01" ],
[ false, "1970-01-01" ],
[ null, "1970-01-01" ],
// Those are converted to NaN, the corresponding date string is the empty string
[ "invaliddatenumber", "" ],
[ NaN, "" ],
[ undefined, "" ],
// Out of range, the corresponding date string is the empty string
[ -62135596800001, "" ],
// Infinity will keep the current value and throw (so we need to set a current value).
[ 1298851200010, "2011-02-28" ],
[ Infinity, "2011-02-28", true ],
[ -Infinity, "2011-02-28", true ],
];
var element = document.createElement('input');
element.type = "date";
for (let data of testData) {
var caught = false;
try {
element.valueAsNumber = data[0];
is(element.value, data[1], "valueAsNumber should set the value to " + data[1]);
} catch(e) {
caught = true;
}
if (data[2]) {
ok(caught, "valueAsNumber should have thrown");
is(element.value, data[1], "the value should not have changed");
} else {
ok(!caught, "valueAsNumber should not have thrown");
}
}
}
function checkTimeGet()
{
var tests = [
// Some invalid values to begin.
{ value: "", result: NaN },
{ value: "foobar", result: NaN },
{ value: "00:", result: NaN },
{ value: "24:00", result: NaN },
{ value: "00:99", result: NaN },
{ value: "00:00:", result: NaN },
{ value: "00:00:99", result: NaN },
{ value: "00:00:00:", result: NaN },
{ value: "00:00:00.", result: NaN },
{ value: "00:00:00.0000", result: NaN },
// Some simple valid values.
{ value: "00:00", result: 0 },
{ value: "00:01", result: 60000 },
{ value: "01:00", result: 3600000 },
{ value: "01:01", result: 3660000 },
{ value: "13:37", result: 49020000 },
// Valid values including seconds.
{ value: "00:00:01", result: 1000 },
{ value: "13:37:42", result: 49062000 },
// Valid values including seconds fractions.
{ value: "00:00:00.001", result: 1 },
{ value: "00:00:00.123", result: 123 },
{ value: "00:00:00.100", result: 100 },
{ value: "00:00:00.000", result: 0 },
{ value: "20:17:31.142", result: 73051142 },
// Highest possible value.
{ value: "23:59:59.999", result: 86399999 },
// Some values with one or two digits for the fraction of seconds.
{ value: "00:00:00.1", result: 100 },
{ value: "00:00:00.14", result: 140 },
{ value: "13:37:42.7", result: 49062700 },
{ value: "23:31:12.23", result: 84672230 },
];
var element = document.createElement('input');
element.type = 'time';
for (let test of tests) {
element.value = test.value;
if (isNaN(test.result)) {
ok(isNaN(element.valueAsNumber),
"invalid value should have .valueAsNumber return NaN");
} else {
is(element.valueAsNumber, test.result,
".valueAsNumber should return " + test.result);
}
}
}
function checkTimeSet()
{
var tests = [
// Some NaN values (should set to empty string).
{ value: NaN, result: "" },
{ value: "foobar", result: "" },
{ value: function() {}, result: "" },
// Inifinity (should throw).
{ value: Infinity, throw: true },
{ value: -Infinity, throw: true },
// "" converts to 0... JS is fun :)
{ value: "", result: "00:00" },
// Simple tests.
{ value: 0, result: "00:00" },
{ value: 1, result: "00:00:00.001" },
{ value: 100, result: "00:00:00.100" },
{ value: 1000, result: "00:00:01" },
{ value: 60000, result: "00:01" },
{ value: 3600000, result: "01:00" },
{ value: 83622234, result: "23:13:42.234" },
// Some edge cases.
{ value: 86400000, result: "00:00" },
{ value: 86400001, result: "00:00:00.001" },
{ value: 170022234, result: "23:13:42.234" },
{ value: 432000000, result: "00:00" },
{ value: -1, result: "23:59:59.999" },
{ value: -86400000, result: "00:00" },
{ value: -86400001, result: "23:59:59.999" },
{ value: -56789, result: "23:59:03.211" },
{ value: 0.9, result: "00:00" },
];
var element = document.createElement('input');
element.type = 'time';
for (let test of tests) {
try {
var caught = false;
element.valueAsNumber = test.value;
is(element.value, test.result, "value should return " + test.result);
} catch(e) {
caught = true;
}
if (!test.throw) {
test.throw = false;
}
is(caught, test.throw, "the test throwing status should be " + test.throw);
}
}
function checkMonthGet()
{
var validData =
[
[ "2016-07", 558 ],
[ "1970-01", 0 ],
[ "1969-12", -1 ],
[ "0001-01", -23628 ],
[ "10000-12", 96371 ],
[ "275760-09", 3285488 ],
];
var invalidData =
[
"invalidmonth",
"0000-01",
"2000-00",
"2012-13",
// Out of range.
"275760-10",
];
var element = document.createElement('input');
element.type = "month";
for (let data of validData) {
element.value = data[0];
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
"integer value representing this month");
}
for (let data of invalidData) {
element.value = data;
ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " +
"when the element value is not a valid month");
}
}
function checkMonthSet()
{
var testData =
[
[ 558, "2016-07" ],
[ 0, "1970-01" ],
[ -1, "1969-12" ],
[ 96371, "10000-12" ],
[ 12, "1971-01" ],
[ -12, "1969-01" ],
// Maximum valid month (limited by the ecma date object range)
[ 3285488, "275760-09" ],
// Minimum valid month (limited by the input element minimum valid value)
[ -23628, "0001-01" ],
// "Values must be truncated to valid months"
[ 0.3, "1970-01" ],
[ -1.1, "1969-11" ],
[ 1e2, "1978-05" ],
[ 1e-1, "1970-01" ],
// Invalid numbers.
// Those are implicitly converted to numbers
[ "", "1970-01" ],
[ true, "1970-02" ],
[ false, "1970-01" ],
[ null, "1970-01" ],
// Those are converted to NaN, the corresponding month string is the empty string
[ "invalidmonth", "" ],
[ NaN, "" ],
[ undefined, "" ],
// Out of range, the corresponding month string is the empty string
[ -23629, "" ],
[ 3285489, "" ],
// Infinity will keep the current value and throw (so we need to set a current value)
[ 558, "2016-07" ],
[ Infinity, "2016-07", true ],
[ -Infinity, "2016-07", true ],
];
var element = document.createElement('input');
element.type = "month";
for (let data of testData) {
var caught = false;
try {
element.valueAsNumber = data[0];
is(element.value, data[1], "valueAsNumber should set the value to " + data[1]);
} catch(e) {
caught = true;
}
if (data[2]) {
ok(caught, "valueAsNumber should have thrown");
is(element.value, data[1], "the value should not have changed");
} else {
ok(!caught, "valueAsNumber should not have thrown");
}
}
}
function checkWeekGet()
{
var validData =
[
// Common years starting on different days of week.
[ "2007-W01", Date.UTC(2007, 0, 1) ], // Mon
[ "2013-W01", Date.UTC(2012, 11, 31) ], // Tue
[ "2014-W01", Date.UTC(2013, 11, 30) ], // Wed
[ "2015-W01", Date.UTC(2014, 11, 29) ], // Thu
[ "2010-W01", Date.UTC(2010, 0, 4) ], // Fri
[ "2011-W01", Date.UTC(2011, 0, 3) ], // Sat
[ "2017-W01", Date.UTC(2017, 0, 2) ], // Sun
// Common years ending on different days of week.
[ "2007-W52", Date.UTC(2007, 11, 24) ], // Mon
[ "2013-W52", Date.UTC(2013, 11, 23) ], // Tue
[ "2014-W52", Date.UTC(2014, 11, 22) ], // Wed
[ "2015-W53", Date.UTC(2015, 11, 28) ], // Thu
[ "2010-W52", Date.UTC(2010, 11, 27) ], // Fri
[ "2011-W52", Date.UTC(2011, 11, 26) ], // Sat
[ "2017-W52", Date.UTC(2017, 11, 25) ], // Sun
// Leap years starting on different days of week.
[ "1996-W01", Date.UTC(1996, 0, 1) ], // Mon
[ "2008-W01", Date.UTC(2007, 11, 31) ], // Tue
[ "2020-W01", Date.UTC(2019, 11, 30) ], // Wed
[ "2004-W01", Date.UTC(2003, 11, 29) ], // Thu
[ "2016-W01", Date.UTC(2016, 0, 4) ], // Fri
[ "2000-W01", Date.UTC(2000, 0, 3) ], // Sat
[ "2012-W01", Date.UTC(2012, 0, 2) ], // Sun
// Leap years ending on different days of week.
[ "2012-W52", Date.UTC(2012, 11, 24) ], // Mon
[ "2024-W52", Date.UTC(2024, 11, 23) ], // Tue
[ "1980-W52", Date.UTC(1980, 11, 22) ], // Wed
[ "1992-W53", Date.UTC(1992, 11, 28) ], // Thu
[ "2004-W53", Date.UTC(2004, 11, 27) ], // Fri
[ "1988-W52", Date.UTC(1988, 11, 26) ], // Sat
[ "2000-W52", Date.UTC(2000, 11, 25) ], // Sun
// Other normal cases.
[ "2015-W53", Date.UTC(2015, 11, 28) ],
[ "2016-W36", Date.UTC(2016, 8, 5) ],
[ "1970-W01", Date.UTC(1969, 11, 29) ],
[ "275760-W37", Date.UTC(275760, 8, 8) ],
];
var invalidData =
[
"invalidweek",
"0000-W01",
"2016-W00",
"2016-W53",
// Out of range.
"275760-W38",
];
var element = document.createElement('input');
element.type = "week";
for (let data of validData) {
element.value = data[0];
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
"integer value representing this week");
}
for (let data of invalidData) {
element.value = data;
ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " +
"when the element value is not a valid week");
}
}
function checkWeekSet()
{
var testData =
[
// Common years starting on different days of week.
[ Date.UTC(2007, 0, 1), "2007-W01" ], // Mon
[ Date.UTC(2013, 0, 1), "2013-W01" ], // Tue
[ Date.UTC(2014, 0, 1), "2014-W01" ], // Wed
[ Date.UTC(2015, 0, 1), "2015-W01" ], // Thu
[ Date.UTC(2010, 0, 1), "2009-W53" ], // Fri
[ Date.UTC(2011, 0, 1), "2010-W52" ], // Sat
[ Date.UTC(2017, 0, 1), "2016-W52" ], // Sun
// Common years ending on different days of week.
[ Date.UTC(2007, 11, 31), "2008-W01" ], // Mon
[ Date.UTC(2013, 11, 31), "2014-W01" ], // Tue
[ Date.UTC(2014, 11, 31), "2015-W01" ], // Wed
[ Date.UTC(2015, 11, 31), "2015-W53" ], // Thu
[ Date.UTC(2010, 11, 31), "2010-W52" ], // Fri
[ Date.UTC(2011, 11, 31), "2011-W52" ], // Sat
[ Date.UTC(2017, 11, 31), "2017-W52" ], // Sun
// Leap years starting on different days of week.
[ Date.UTC(1996, 0, 1), "1996-W01" ], // Mon
[ Date.UTC(2008, 0, 1), "2008-W01" ], // Tue
[ Date.UTC(2020, 0, 1), "2020-W01" ], // Wed
[ Date.UTC(2004, 0, 1), "2004-W01" ], // Thu
[ Date.UTC(2016, 0, 1), "2015-W53" ], // Fri
[ Date.UTC(2000, 0, 1), "1999-W52" ], // Sat
[ Date.UTC(2012, 0, 1), "2011-W52" ], // Sun
// Leap years ending on different days of week.
[ Date.UTC(2012, 11, 31), "2013-W01" ], // Mon
[ Date.UTC(2024, 11, 31), "2025-W01" ], // Tue
[ Date.UTC(1980, 11, 31), "1981-W01" ], // Wed
[ Date.UTC(1992, 11, 31), "1992-W53" ], // Thu
[ Date.UTC(2004, 11, 31), "2004-W53" ], // Fri
[ Date.UTC(1988, 11, 31), "1988-W52" ], // Sat
[ Date.UTC(2000, 11, 31), "2000-W52" ], // Sun
// Other normal cases.
[ Date.UTC(2008, 8, 26), "2008-W39" ],
[ Date.UTC(2016, 0, 4), "2016-W01" ],
[ Date.UTC(2016, 0, 10), "2016-W01" ],
[ Date.UTC(2016, 0, 11), "2016-W02" ],
// Maximum valid week (limited by the ecma date object range).
[ 8640000000000000, "275760-W37" ],
// Minimum valid week (limited by the input element minimum valid value)
[ -62135596800000, "0001-W01" ],
// "Values must be truncated to valid weeks"
[ 0.3, "1970-W01" ],
[ 1e-1, "1970-W01" ],
[ -1.1, "1970-W01" ],
[ -345600000, "1969-W52" ],
// Invalid numbers.
// Those are implicitly converted to numbers
[ "", "1970-W01" ],
[ true, "1970-W01" ],
[ false, "1970-W01" ],
[ null, "1970-W01" ],
// Those are converted to NaN, the corresponding week string is the empty string
[ "invalidweek", "" ],
[ NaN, "" ],
[ undefined, "" ],
// Infinity will keep the current value and throw (so we need to set a current value).
[ Date.UTC(2016, 8, 8), "2016-W36" ],
[ Infinity, "2016-W36", true ],
[ -Infinity, "2016-W36", true ],
];
var element = document.createElement('input');
element.type = "week";
for (let data of testData) {
var caught = false;
try {
element.valueAsNumber = data[0];
is(element.value, data[1], "valueAsNumber should set the value to " +
data[1]);
} catch(e) {
caught = true;
}
if (data[2]) {
ok(caught, "valueAsNumber should have thrown");
is(element.value, data[1], "the value should not have changed");
} else {
ok(!caught, "valueAsNumber should not have thrown");
}
}
}
function checkDatetimeLocalGet() {
var validData =
[
// Simple cases.
[ "2016-12-20T09:58", Date.UTC(2016, 11, 20, 9, 58) ],
[ "2016-12-20T09:58:30", Date.UTC(2016, 11, 20, 9, 58, 30) ],
[ "2016-12-20T09:58:30.123", Date.UTC(2016, 11, 20, 9, 58, 30, 123) ],
[ "2017-01-01T10:00", Date.UTC(2017, 0, 1, 10, 0, 0) ],
[ "1969-12-31T12:00:00", Date.UTC(1969, 11, 31, 12, 0, 0) ],
[ "1970-01-01T00:00", 0 ],
// Leap years.
[ "1804-02-29 12:34", Date.UTC(1804, 1, 29, 12, 34, 0) ],
[ "2016-02-29T12:34", Date.UTC(2016, 1, 29, 12, 34, 0) ],
[ "2016-12-31T12:34:56", Date.UTC(2016, 11, 31, 12, 34, 56) ],
[ "2016-01-01T12:34:56.789", Date.UTC(2016, 0, 1, 12, 34, 56, 789) ],
[ "2017-01-01 12:34:56.789", Date.UTC(2017, 0, 1, 12, 34, 56, 789) ],
// Maximum valid datetime-local (limited by the ecma date object range).
[ "275760-09-13T00:00", 8640000000000000 ],
// Minimum valid datetime-local (limited by the input element minimum valid value).
[ "0001-01-01T00:00", -62135596800000 ],
];
var invalidData =
[
"invaliddatetime-local",
"0000-01-01T00:00",
"2016-12-25T00:00Z",
"2015-02-29T12:34",
"1-1-1T12:00",
// Out of range.
"275760-09-13T12:00",
];
var element = document.createElement('input');
element.type = "datetime-local";
for (let data of validData) {
element.value = data[0];
is(element.valueAsNumber, data[1], "valueAsNumber should return the " +
"integer value representing this datetime-local");
}
for (let data of invalidData) {
element.value = data;
ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " +
"when the element value is not a valid datetime-local");
}
}
function checkDatetimeLocalSet()
{
var testData =
[
// Simple cases.
[ Date.UTC(2016, 11, 20, 9, 58, 0), "2016-12-20T09:58", ],
[ Date.UTC(2016, 11, 20, 9, 58, 30), "2016-12-20T09:58:30" ],
[ Date.UTC(2016, 11, 20, 9, 58, 30, 123), "2016-12-20T09:58:30.123" ],
[ Date.UTC(2017, 0, 1, 10, 0, 0), "2017-01-01T10:00" ],
[ Date.UTC(1969, 11, 31, 12, 0, 0), "1969-12-31T12:00" ],
[ 0, "1970-01-01T00:00" ],
// Maximum valid week (limited by the ecma date object range).
[ 8640000000000000, "275760-09-13T00:00" ],
// Minimum valid datetime-local (limited by the input element minimum valid value).
[ -62135596800000, "0001-01-01T00:00" ],
// Leap years.
[ Date.UTC(1804, 1, 29, 12, 34, 0), "1804-02-29T12:34" ],
[ Date.UTC(2016, 1, 29, 12, 34, 0), "2016-02-29T12:34" ],
[ Date.UTC(2016, 11, 31, 12, 34, 56), "2016-12-31T12:34:56" ],
[ Date.UTC(2016, 0, 1, 12, 34, 56, 789), "2016-01-01T12:34:56.789" ],
[ Date.UTC(2017, 0, 1, 12, 34, 56, 789), "2017-01-01T12:34:56.789" ],
// "Values must be truncated to valid datetime-local"
[ 0.3, "1970-01-01T00:00" ],
[ 1e-1, "1970-01-01T00:00" ],
[ -1 , "1969-12-31T23:59:59.999" ],
[ -345600000, "1969-12-28T00:00" ],
// Invalid numbers.
// Those are implicitly converted to numbers
[ "", "1970-01-01T00:00" ],
[ true, "1970-01-01T00:00:00.001" ],
[ false, "1970-01-01T00:00" ],
[ null, "1970-01-01T00:00" ],
// Those are converted to NaN, the corresponding week string is the empty string
[ "invaliddatetime-local", "" ],
[ NaN, "" ],
[ undefined, "" ],
// Infinity will keep the current value and throw (so we need to set a current value).
[ Date.UTC(2016, 11, 27, 15, 10, 0), "2016-12-27T15:10" ],
[ Infinity, "2016-12-27T15:10", true ],
[ -Infinity, "2016-12-27T15:10", true ],
];
var element = document.createElement('input');
element.type = "datetime-local";
for (let data of testData) {
var caught = false;
try {
element.valueAsNumber = data[0];
is(element.value, data[1], "valueAsNumber should set the value to " +
data[1]);
} catch(e) {
caught = true;
}
if (data[2]) {
ok(caught, "valueAsNumber should have thrown");
is(element.value, data[1], "the value should not have changed");
} else {
ok(!caught, "valueAsNumber should not have thrown");
}
}
}
checkAvailability();
// <input type='number'> test
checkNumberGet();
checkNumberSet();
// <input type='range'> test
checkRangeGet();
checkRangeSet();
// <input type='date'> test
checkDateGet();
checkDateSet();
// <input type='time'> test
checkTimeGet();
checkTimeSet();
// <input type='month'> test
checkMonthGet();
checkMonthSet();
// <input type='week'> test
checkWeekGet();
checkWeekSet();
// <input type='datetime-local'> test
checkDatetimeLocalGet();
checkDatetimeLocalSet();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -485,10 +485,8 @@ nsresult nsXBLService::LoadBindings(Element* aElement, nsIURI* aURL,
"chrome://global/content/xml/XMLPrettyPrint.xml#prettyprint")) { "chrome://global/content/xml/XMLPrettyPrint.xml#prettyprint")) {
nsAtom* tag = aElement->NodeInfo()->NameAtom(); nsAtom* tag = aElement->NodeInfo()->NameAtom();
MOZ_ASSERT( MOZ_ASSERT(
// datetimebox // pluginProblem
tag == nsGkAtoms::datetimebox || tag == nsGkAtoms::embed || tag == nsGkAtoms::applet ||
// pluginProblem
tag == nsGkAtoms::embed || tag == nsGkAtoms::applet ||
tag == nsGkAtoms::object || tag == nsGkAtoms::object ||
// xbl-marquee // xbl-marquee
tag == nsGkAtoms::marquee, tag == nsGkAtoms::marquee,

Просмотреть файл

@ -661,8 +661,7 @@ nsresult nsXULElement::BindToTree(Document* aDocument, nsIContent* aParent,
tag == nsGkAtoms::scrollcorner || tag == nsGkAtoms::slider || tag == nsGkAtoms::scrollcorner || tag == nsGkAtoms::slider ||
tag == nsGkAtoms::thumb || tag == nsGkAtoms::thumb ||
// other // other
tag == nsGkAtoms::datetimebox || tag == nsGkAtoms::resizer || tag == nsGkAtoms::resizer || tag == nsGkAtoms::label,
tag == nsGkAtoms::label,
"Unexpected XUL element in non-XUL doc"); "Unexpected XUL element in non-XUL doc");
} }
#endif #endif

Просмотреть файл

@ -19,7 +19,6 @@
#include "mozilla/dom/HTMLInputElement.h" #include "mozilla/dom/HTMLInputElement.h"
#include "mozilla/dom/MutationEventBinding.h" #include "mozilla/dom/MutationEventBinding.h"
#include "nsNodeInfoManager.h" #include "nsNodeInfoManager.h"
#include "nsIDateTimeInputArea.h"
#include "nsIObserverService.h" #include "nsIObserverService.h"
#include "jsapi.h" #include "jsapi.h"
#include "nsJSUtils.h" #include "nsJSUtils.h"
@ -37,62 +36,11 @@ NS_IMPL_FRAMEARENA_HELPERS(nsDateTimeControlFrame)
NS_QUERYFRAME_HEAD(nsDateTimeControlFrame) NS_QUERYFRAME_HEAD(nsDateTimeControlFrame)
NS_QUERYFRAME_ENTRY(nsDateTimeControlFrame) NS_QUERYFRAME_ENTRY(nsDateTimeControlFrame)
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
nsDateTimeControlFrame::nsDateTimeControlFrame(ComputedStyle* aStyle) nsDateTimeControlFrame::nsDateTimeControlFrame(ComputedStyle* aStyle)
: nsContainerFrame(aStyle, kClassID) {} : nsContainerFrame(aStyle, kClassID) {}
void nsDateTimeControlFrame::DestroyFrom(nsIFrame* aDestructRoot,
PostDestroyData& aPostDestroyData) {
aPostDestroyData.AddAnonymousContent(mInputAreaContent.forget());
nsContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
}
void nsDateTimeControlFrame::OnValueChanged() {
if (!mInputAreaContent) {
return;
}
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
do_QueryInterface(mInputAreaContent);
if (inputAreaContent) {
inputAreaContent->NotifyInputElementValueChanged();
}
}
void nsDateTimeControlFrame::OnMinMaxStepAttrChanged() {
if (!mInputAreaContent) {
return;
}
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
do_QueryInterface(mInputAreaContent);
if (inputAreaContent) {
inputAreaContent->NotifyMinMaxStepAttrChanged();
}
}
void nsDateTimeControlFrame::HandleFocusEvent() {
if (!mInputAreaContent) {
return;
}
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
do_QueryInterface(mInputAreaContent);
if (inputAreaContent) {
inputAreaContent->FocusInnerTextBox();
}
}
void nsDateTimeControlFrame::HandleBlurEvent() {
if (!mInputAreaContent) {
return;
}
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
do_QueryInterface(mInputAreaContent);
if (inputAreaContent) {
inputAreaContent->BlurInnerTextBox();
}
}
nscoord nsDateTimeControlFrame::GetMinISize(gfxContext* aRenderingContext) { nscoord nsDateTimeControlFrame::GetMinISize(gfxContext* aRenderingContext) {
nscoord result; nscoord result;
DISPLAY_MIN_INLINE_SIZE(this, result); DISPLAY_MIN_INLINE_SIZE(this, result);
@ -258,69 +206,18 @@ void nsDateTimeControlFrame::Reflow(nsPresContext* aPresContext,
NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
} }
/**
* nsDateTimeControlFrame should be a non-leaf frame when UA Widget is enabled,
* so the datetimebox container element inserted under the Shadow Root can be
* picked up. No frames will be generated from elements from the web content,
* given that they have been replaced by the Shadow Root without an <slots>
* element in the DOM tree.
*
* When the UA Widget is disabled, i.e. the datetimebox is bound as anonymous
* content with XBL, nsDateTimeControlFrame has to be a leaf so no frames from
* web content element will be generated.
*/
bool nsDateTimeControlFrame::IsLeafDynamic() const {
return !nsContentUtils::IsUAWidgetEnabled();
}
nsresult nsDateTimeControlFrame::CreateAnonymousContent(
nsTArray<ContentInfo>& aElements) {
if (nsContentUtils::IsUAWidgetEnabled()) {
return NS_OK;
}
// Set up "datetimebox" XUL element which will be XBL-bound to the
// actual controls.
nsNodeInfoManager* nodeInfoManager =
mContent->GetComposedDoc()->NodeInfoManager();
RefPtr<NodeInfo> nodeInfo = nodeInfoManager->GetNodeInfo(
nsGkAtoms::datetimebox, nullptr, kNameSpaceID_XUL, nsINode::ELEMENT_NODE);
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
NS_TrustedNewXULElement(getter_AddRefs(mInputAreaContent), nodeInfo.forget());
aElements.AppendElement(mInputAreaContent);
return NS_OK;
}
void nsDateTimeControlFrame::AppendAnonymousContentTo(
nsTArray<nsIContent*>& aElements, uint32_t aFilter) {
if (mInputAreaContent) {
aElements.AppendElement(mInputAreaContent);
}
}
void nsDateTimeControlFrame::SyncDisabledState() { void nsDateTimeControlFrame::SyncDisabledState() {
if (mInputAreaContent) { Element* dateTimeBoxElement =
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent = static_cast<dom::HTMLInputElement*>(GetContent())
do_QueryInterface(mInputAreaContent); ->GetDateTimeBoxElement();
if (!inputAreaContent) { if (!dateTimeBoxElement) {
return; return;
}
inputAreaContent->UpdateEditAttributes();
} else {
Element* dateTimeBoxElement =
static_cast<dom::HTMLInputElement*>(GetContent())
->GetDateTimeBoxElementInUAWidget();
if (!dateTimeBoxElement) {
return;
}
AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
dateTimeBoxElement, NS_LITERAL_STRING("MozDateTimeAttributeChanged"),
CanBubble::eNo, ChromeOnlyDispatch::eNo);
dispatcher->RunDOMEventWhenSafe();
} }
AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
dateTimeBoxElement, NS_LITERAL_STRING("MozDateTimeAttributeChanged"),
CanBubble::eNo, ChromeOnlyDispatch::eNo);
dispatcher->RunDOMEventWhenSafe();
} }
nsresult nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID, nsresult nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID,
@ -337,41 +234,24 @@ nsresult nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID,
// then we don't need to do anything since we are going to be reframed. // then we don't need to do anything since we are going to be reframed.
if (contentAsInputElem->ControlType() == NS_FORM_INPUT_TIME || if (contentAsInputElem->ControlType() == NS_FORM_INPUT_TIME ||
contentAsInputElem->ControlType() == NS_FORM_INPUT_DATE) { contentAsInputElem->ControlType() == NS_FORM_INPUT_DATE) {
if (mInputAreaContent) { Element* dateTimeBoxElement =
nsCOMPtr<nsIDateTimeInputArea> inputAreaContent = static_cast<dom::HTMLInputElement*>(GetContent())
do_QueryInterface(mInputAreaContent); ->GetDateTimeBoxElement();
if (aAttribute == nsGkAtoms::value) { if (aAttribute == nsGkAtoms::value) {
if (inputAreaContent) { if (dateTimeBoxElement) {
nsContentUtils::AddScriptRunner(NewRunnableMethod( AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
"nsIDateTimeInputArea::NotifyInputElementValueChanged", dateTimeBoxElement,
inputAreaContent, NS_LITERAL_STRING("MozDateTimeValueChanged"), CanBubble::eNo,
&nsIDateTimeInputArea::NotifyInputElementValueChanged)); ChromeOnlyDispatch::eNo);
} dispatcher->RunDOMEventWhenSafe();
} else {
if (inputAreaContent) {
inputAreaContent->UpdateEditAttributes();
}
} }
} else { } else {
Element* dateTimeBoxElement = if (dateTimeBoxElement) {
static_cast<dom::HTMLInputElement*>(GetContent()) AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
->GetDateTimeBoxElementInUAWidget(); dateTimeBoxElement,
if (aAttribute == nsGkAtoms::value) { NS_LITERAL_STRING("MozDateTimeAttributeChanged"),
if (dateTimeBoxElement) { CanBubble::eNo, ChromeOnlyDispatch::eNo);
AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher( dispatcher->RunDOMEventWhenSafe();
dateTimeBoxElement,
NS_LITERAL_STRING("MozDateTimeValueChanged"), CanBubble::eNo,
ChromeOnlyDispatch::eNo);
dispatcher->RunDOMEventWhenSafe();
}
} else {
if (dateTimeBoxElement) {
AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher(
dateTimeBoxElement,
NS_LITERAL_STRING("MozDateTimeAttributeChanged"),
CanBubble::eNo, ChromeOnlyDispatch::eNo);
dispatcher->RunDOMEventWhenSafe();
}
} }
} }
} }
@ -381,10 +261,6 @@ nsresult nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID,
return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
} }
nsIContent* nsDateTimeControlFrame::GetInputAreaContent() {
return mInputAreaContent;
}
void nsDateTimeControlFrame::ContentStatesChanged(EventStates aStates) { void nsDateTimeControlFrame::ContentStatesChanged(EventStates aStates) {
if (aStates.HasState(NS_EVENT_STATE_DISABLED)) { if (aStates.HasState(NS_EVENT_STATE_DISABLED)) {
nsContentUtils::AddScriptRunner(new SyncDisabledStateEvent(this)); nsContentUtils::AddScriptRunner(new SyncDisabledStateEvent(this));

Просмотреть файл

@ -27,8 +27,7 @@ struct DateTimeValue;
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla
class nsDateTimeControlFrame final : public nsContainerFrame, class nsDateTimeControlFrame final : public nsContainerFrame {
public nsIAnonymousContentCreator {
typedef mozilla::dom::DateTimeValue DateTimeValue; typedef mozilla::dom::DateTimeValue DateTimeValue;
explicit nsDateTimeControlFrame(ComputedStyle* aStyle); explicit nsDateTimeControlFrame(ComputedStyle* aStyle);
@ -38,9 +37,6 @@ class nsDateTimeControlFrame final : public nsContainerFrame,
ComputedStyle* aStyle); ComputedStyle* aStyle);
void ContentStatesChanged(mozilla::EventStates aStates) override; void ContentStatesChanged(mozilla::EventStates aStates) override;
void DestroyFrom(nsIFrame* aDestructRoot,
PostDestroyData& aPostDestroyData) override;
NS_DECL_QUERYFRAME NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS(nsDateTimeControlFrame) NS_DECL_FRAMEARENA_HELPERS(nsDateTimeControlFrame)
@ -64,23 +60,9 @@ class nsDateTimeControlFrame final : public nsContainerFrame,
const ReflowInput& aReflowInput, const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) override; nsReflowStatus& aStatus) override;
bool IsLeafDynamic() const override;
// nsIAnonymousContentCreator
nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter) override;
nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute, nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
int32_t aModType) override; int32_t aModType) override;
nsIContent* GetInputAreaContent();
void OnValueChanged();
void OnMinMaxStepAttrChanged();
void HandleFocusEvent();
void HandleBlurEvent();
private: private:
class SyncDisabledStateEvent; class SyncDisabledStateEvent;
friend class SyncDisabledStateEvent; friend class SyncDisabledStateEvent;
@ -104,13 +86,9 @@ class nsDateTimeControlFrame final : public nsContainerFrame,
}; };
/** /**
* Sync the disabled state of the anonymous children up with our content's. * Sync the disabled state of the datetimebox children up with our content's.
*/ */
void SyncDisabledState(); void SyncDisabledState();
// Anonymous child which is bound via XBL to an element that wraps the input
// area and reset button.
RefPtr<mozilla::dom::Element> mInputAreaContent;
}; };
#endif // nsDateTimeControlFrame_h__ #endif // nsDateTimeControlFrame_h__

Просмотреть файл

@ -21,7 +21,7 @@ FRAME_ID(ColumnSetWrapperFrame, ColumnSetWrapper, NotLeaf)
FRAME_ID(nsComboboxControlFrame, ComboboxControl, NotLeaf) FRAME_ID(nsComboboxControlFrame, ComboboxControl, NotLeaf)
FRAME_ID(nsComboboxDisplayFrame, ComboboxDisplay, NotLeaf) FRAME_ID(nsComboboxDisplayFrame, ComboboxDisplay, NotLeaf)
FRAME_ID(nsContinuingTextFrame, Text, Leaf) FRAME_ID(nsContinuingTextFrame, Text, Leaf)
FRAME_ID(nsDateTimeControlFrame, DateTimeControl, DynamicLeaf) FRAME_ID(nsDateTimeControlFrame, DateTimeControl, NotLeaf)
FRAME_ID(nsDeckFrame, Deck, NotLeaf) FRAME_ID(nsDeckFrame, Deck, NotLeaf)
FRAME_ID(nsDocElementBoxFrame, Box, NotLeaf) FRAME_ID(nsDocElementBoxFrame, Box, NotLeaf)
FRAME_ID(nsFieldSetFrame, FieldSet, NotLeaf) FRAME_ID(nsFieldSetFrame, FieldSet, NotLeaf)

Просмотреть файл

@ -774,18 +774,6 @@ video > .caption-box {
font: var(--cue-font-size) sans-serif; font: var(--cue-font-size) sans-serif;
} }
/* datetime elements */
input[type="time"] > xul|datetimebox {
display: flex;
-moz-binding: url("chrome://global/content/bindings/datetimebox.xml#time-input");
}
input[type="date"] > xul|datetimebox {
display: flex;
-moz-binding: url("chrome://global/content/bindings/datetimebox.xml#date-input");
}
/* details & summary */ /* details & summary */
details > summary:first-of-type, details > summary:first-of-type,
details > summary:-moz-native-anonymous { details > summary:-moz-native-anonymous {

Просмотреть файл

@ -36,9 +36,7 @@ class DateTimePickerChild extends ActorChild {
return; return;
} }
if (dateTimeBoxElement instanceof Ci.nsIDateTimeInputArea) { if (this._inputElement.openOrClosedShadowRoot) {
dateTimeBoxElement.wrappedJSObject.setPickerState(false);
} else if (this._inputElement.openOrClosedShadowRoot) {
// dateTimeBoxElement is within UA Widget Shadow DOM. // dateTimeBoxElement is within UA Widget Shadow DOM.
// An event dispatch to it can't be accessed by document. // An event dispatch to it can't be accessed by document.
let win = this._inputElement.ownerGlobal; let win = this._inputElement.ownerGlobal;
@ -111,9 +109,7 @@ class DateTimePickerChild extends ActorChild {
let win = this._inputElement.ownerGlobal; let win = this._inputElement.ownerGlobal;
if (dateTimeBoxElement instanceof Ci.nsIDateTimeInputArea) { if (this._inputElement.openOrClosedShadowRoot) {
dateTimeBoxElement.wrappedJSObject.setValueFromPicker(Cu.cloneInto(aMessage.data, win));
} else if (this._inputElement.openOrClosedShadowRoot) {
// dateTimeBoxElement is within UA Widget Shadow DOM. // dateTimeBoxElement is within UA Widget Shadow DOM.
// An event dispatch to it can't be accessed by document. // An event dispatch to it can't be accessed by document.
dateTimeBoxElement.dispatchEvent( dateTimeBoxElement.dispatchEvent(
@ -154,9 +150,7 @@ class DateTimePickerChild extends ActorChild {
throw new Error("How do we get this event without a UA Widget or XBL binding?"); throw new Error("How do we get this event without a UA Widget or XBL binding?");
} }
if (dateTimeBoxElement instanceof Ci.nsIDateTimeInputArea) { if (this._inputElement.openOrClosedShadowRoot) {
dateTimeBoxElement.wrappedJSObject.setPickerState(true);
} else if (this._inputElement.openOrClosedShadowRoot) {
// dateTimeBoxElement is within UA Widget Shadow DOM. // dateTimeBoxElement is within UA Widget Shadow DOM.
// An event dispatch to it can't be accessed by document, because // An event dispatch to it can't be accessed by document, because
// the event is not composed. // the event is not composed.

Просмотреть файл

@ -67,7 +67,6 @@ toolkit.jar:
content/global/bindings/checkbox.xml (widgets/checkbox.xml) content/global/bindings/checkbox.xml (widgets/checkbox.xml)
content/global/bindings/datekeeper.js (widgets/datekeeper.js) content/global/bindings/datekeeper.js (widgets/datekeeper.js)
content/global/bindings/datepicker.js (widgets/datepicker.js) content/global/bindings/datepicker.js (widgets/datepicker.js)
content/global/bindings/datetimebox.xml (widgets/datetimebox.xml)
content/global/bindings/datetimebox.css (widgets/datetimebox.css) content/global/bindings/datetimebox.css (widgets/datetimebox.css)
* content/global/bindings/dialog.xml (widgets/dialog.xml) * content/global/bindings/dialog.xml (widgets/dialog.xml)
content/global/bindings/general.xml (widgets/general.xml) content/global/bindings/general.xml (widgets/general.xml)

Просмотреть файл

@ -1,7 +0,0 @@
[DEFAULT]
prefs = dom.ua_widget.enabled=false
support-files =
../head.js
[browser_datetime_datepicker.js]
uses-unsafe-cpows = true

Просмотреть файл

@ -1,294 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* import-globals-from ../head.js */
"use strict";
const MONTH_YEAR = ".month-year",
DAYS_VIEW = ".days-view",
BTN_PREV_MONTH = ".prev",
BTN_NEXT_MONTH = ".next";
const DATE_FORMAT = new Intl.DateTimeFormat("en-US", { year: "numeric", month: "long", timeZone: "UTC" }).format;
const DATE_FORMAT_LOCAL = new Intl.DateTimeFormat("en-US", { year: "numeric", month: "long" }).format;
// Create a list of abbreviations for calendar class names
const W = "weekend",
O = "outside",
S = "selection",
R = "out-of-range",
T = "today",
P = "off-step";
// Calendar classlist for 2016-12. Used to verify the classNames are correct.
const calendarClasslist_201612 = [
[W, O], [O], [O], [O], [], [], [W],
[W], [], [], [], [], [], [W],
[W], [], [], [], [S], [], [W],
[W], [], [], [], [], [], [W],
[W], [], [], [], [], [], [W],
[W, O], [O], [O], [O], [O], [O], [W, O],
];
function getCalendarText() {
return helper.getChildren(DAYS_VIEW).map(child => child.textContent);
}
function getCalendarClassList() {
return helper.getChildren(DAYS_VIEW).map(child => Array.from(child.classList));
}
function mergeArrays(a, b) {
return a.map((classlist, index) => classlist.concat(b[index]));
}
let helper = new DateTimeTestHelper();
registerCleanupFunction(() => {
helper.cleanup();
});
/**
* Test that date picker opens to today's date when input field is blank
*/
add_task(async function test_datepicker_today() {
const date = new Date();
await helper.openPicker("data:text/html, <input type='date'>");
if (date.getMonth() === new Date().getMonth()) {
Assert.equal(helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT_LOCAL(date));
} else {
Assert.ok(true, "Skipping datepicker today test if month changes when opening picker.");
}
await helper.tearDown();
});
/**
* Test that date picker opens to the correct month, with calendar days
* displayed correctly, given a date value is set.
*/
add_task(async function test_datepicker_open() {
const inputValue = "2016-12-15";
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}">`);
Assert.equal(helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(inputValue)));
Assert.deepEqual(
getCalendarText(),
[
"27", "28", "29", "30", "1", "2", "3",
"4", "5", "6", "7", "8", "9", "10",
"11", "12", "13", "14", "15", "16", "17",
"18", "19", "20", "21", "22", "23", "24",
"25", "26", "27", "28", "29", "30", "31",
"1", "2", "3", "4", "5", "6", "7",
],
"2016-12",
);
Assert.deepEqual(
getCalendarClassList(),
calendarClasslist_201612,
"2016-12 classNames"
);
await helper.tearDown();
});
/**
* When the prev month button is clicked, calendar should display the dates for
* the previous month.
*/
add_task(async function test_datepicker_prev_month_btn() {
const inputValue = "2016-12-15";
const prevMonth = "2016-11-01";
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}">`);
helper.click(helper.getElement(BTN_PREV_MONTH));
Assert.equal(helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(prevMonth)));
Assert.deepEqual(
getCalendarText(),
[
"30", "31", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "10", "11", "12",
"13", "14", "15", "16", "17", "18", "19",
"20", "21", "22", "23", "24", "25", "26",
"27", "28", "29", "30", "1", "2", "3",
"4", "5", "6", "7", "8", "9", "10",
],
"2016-11",
);
await helper.tearDown();
});
/**
* When the next month button is clicked, calendar should display the dates for
* the next month.
*/
add_task(async function test_datepicker_next_month_btn() {
const inputValue = "2016-12-15";
const nextMonth = "2017-01-01";
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}">`);
helper.click(helper.getElement(BTN_NEXT_MONTH));
Assert.equal(helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(nextMonth)));
Assert.deepEqual(
getCalendarText(),
[
"25", "26", "27", "28", "29", "30", "31",
"1", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "11", "12", "13", "14",
"15", "16", "17", "18", "19", "20", "21",
"22", "23", "24", "25", "26", "27", "28",
"29", "30", "31", "1", "2", "3", "4",
],
"2017-01",
);
await helper.tearDown();
});
/**
* When a date on the calendar is clicked, date picker should close and set
* value to the input box.
*/
add_task(async function test_datepicker_clicked() {
const inputValue = "2016-12-15";
const firstDayOnCalendar = "2016-11-27";
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}">`);
// Click the first item (top-left corner) of the calendar
helper.click(helper.getElement(DAYS_VIEW).children[0]);
await ContentTask.spawn(helper.tab.linkedBrowser, {}, async function() {
let inputEl = content.document.querySelector("input");
await ContentTaskUtils.waitForEvent(inputEl, "input");
});
let value = await ContentTask.spawn(gBrowser.selectedBrowser, null, async () => {
return content.document.querySelector("input").value;
});
Assert.equal(value, firstDayOnCalendar);
await helper.tearDown();
});
/**
* Make sure picker is in correct state when it is reopened.
*/
add_task(async function test_datepicker_reopen_state() {
const inputValue = "2016-12-15";
const nextMonth = "2017-01-01";
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}">`);
// Navigate to the next month but does not commit the change
Assert.equal(helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(inputValue)));
helper.click(helper.getElement(BTN_NEXT_MONTH));
Assert.equal(helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(nextMonth)));
EventUtils.synthesizeKey("VK_ESCAPE", {}, window);
// Ensures the picker opens to the month of the input value
await BrowserTestUtils.synthesizeMouseAtCenter("input", {}, gBrowser.selectedBrowser);
await helper.waitForPickerReady();
Assert.equal(helper.getElement(MONTH_YEAR).textContent, DATE_FORMAT(new Date(inputValue)));
await helper.tearDown();
});
/**
* When min and max attributes are set, calendar should show some dates as
* out-of-range.
*/
add_task(async function test_datepicker_min_max() {
const inputValue = "2016-12-15";
const inputMin = "2016-12-05";
const inputMax = "2016-12-25";
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}" min="${inputMin}" max="${inputMax}">`);
Assert.deepEqual(
getCalendarClassList(),
mergeArrays(calendarClasslist_201612, [
// R denotes out-of-range
[R], [R], [R], [R], [R], [R], [R],
[R], [], [], [], [], [], [],
[], [], [], [], [], [], [],
[], [], [], [], [], [], [],
[], [R], [R], [R], [R], [R], [R],
[R], [R], [R], [R], [R], [R], [R],
]),
"2016-12 with min & max",
);
await helper.tearDown();
});
/**
* When step attribute is set, calendar should show some dates as off-step.
*/
add_task(async function test_datepicker_step() {
const inputValue = "2016-12-15";
const inputStep = "5";
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}" step="${inputStep}">`);
Assert.deepEqual(
getCalendarClassList(),
mergeArrays(calendarClasslist_201612, [
// P denotes off-step
[P], [P], [P], [], [P], [P], [P],
[P], [], [P], [P], [P], [P], [],
[P], [P], [P], [P], [], [P], [P],
[P], [P], [], [P], [P], [P], [P],
[], [P], [P], [P], [P], [], [P],
[P], [P], [P], [], [P], [P], [P],
]),
"2016-12 with step",
);
await helper.tearDown();
});
add_task(async function test_datepicker_abs_min() {
const inputValue = "0001-01-01";
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}">`);
Assert.deepEqual(
getCalendarText(),
[
"", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "10", "11", "12", "13",
"14", "15", "16", "17", "18", "19", "20",
"21", "22", "23", "24", "25", "26", "27",
"28", "29", "30", "31", "1", "2", "3",
"4", "5", "6", "7", "8", "9", "10",
],
"0001-01",
);
await helper.tearDown();
});
add_task(async function test_datepicker_abs_max() {
const inputValue = "275760-09-13";
await helper.openPicker(`data:text/html, <input type="date" value="${inputValue}">`);
Assert.deepEqual(
getCalendarText(),
[
"31", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "10", "11", "12", "13",
"", "", "", "", "", "", "",
"", "", "", "", "", "", "",
"", "", "", "", "", "", "",
"", "", "", "", "", "", "",
],
"275760-09",
);
await helper.tearDown();
});

Просмотреть файл

@ -8,7 +8,6 @@ XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
BROWSER_CHROME_MANIFESTS += [ BROWSER_CHROME_MANIFESTS += [
'browser/browser.ini', 'browser/browser.ini',
'browser/xbl/browser.ini',
] ]
MOCHITEST_CHROME_MANIFESTS += [ MOCHITEST_CHROME_MANIFESTS += [

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -292,7 +292,6 @@ STATIC_ATOMS = [
Atom("dateTime", "date-time"), Atom("dateTime", "date-time"),
Atom("date", "date"), Atom("date", "date"),
Atom("datetime", "datetime"), Atom("datetime", "datetime"),
Atom("datetimebox", "datetimebox"),
Atom("dd", "dd"), Atom("dd", "dd"),
Atom("decimal", "decimal"), Atom("decimal", "decimal"),
Atom("decimalFormat", "decimal-format"), Atom("decimalFormat", "decimal-format"),