зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
d59f80985c
Коммит
ccf133638c
|
@ -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 <input type='date'> 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"),
|
||||||
|
|
Загрузка…
Ссылка в новой задаче