2003-03-19 03:47:09 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 11:12:37 +00:00
|
|
|
/* 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/. */
|
2010-07-14 06:39:48 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
#include "mozilla/dom/HTMLInputElement.h"
|
2013-08-22 06:30:38 +00:00
|
|
|
|
2013-12-09 02:52:54 +00:00
|
|
|
#include "mozilla/ArrayUtils.h"
|
2014-03-17 06:56:54 +00:00
|
|
|
#include "mozilla/AsyncEventDispatcher.h"
|
2013-08-22 06:30:38 +00:00
|
|
|
#include "mozilla/DebugOnly.h"
|
|
|
|
#include "mozilla/dom/Date.h"
|
2012-09-30 16:40:24 +00:00
|
|
|
#include "nsAttrValueInlines.h"
|
2011-07-15 10:31:34 +00:00
|
|
|
|
1998-09-01 01:27:08 +00:00
|
|
|
#include "nsIDOMHTMLInputElement.h"
|
2001-11-02 07:40:01 +00:00
|
|
|
#include "nsITextControlElement.h"
|
2005-09-21 22:02:26 +00:00
|
|
|
#include "nsIDOMNSEditableElement.h"
|
2002-03-07 20:53:40 +00:00
|
|
|
#include "nsIRadioVisitor.h"
|
2002-12-17 23:38:04 +00:00
|
|
|
#include "nsIPhonetic.h"
|
2002-03-07 20:53:40 +00:00
|
|
|
|
1999-12-01 15:12:49 +00:00
|
|
|
#include "nsIControllers.h"
|
2012-06-06 12:16:58 +00:00
|
|
|
#include "nsIStringBundle.h"
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
#include "nsFocusManager.h"
|
2014-02-28 19:52:42 +00:00
|
|
|
#include "nsColorControlFrame.h"
|
2011-06-21 14:13:12 +00:00
|
|
|
#include "nsNumberControlFrame.h"
|
2001-04-18 01:41:20 +00:00
|
|
|
#include "nsPIDOMWindow.h"
|
2013-12-01 13:49:10 +00:00
|
|
|
#include "nsRepeatService.h"
|
2001-02-22 03:01:34 +00:00
|
|
|
#include "nsContentCID.h"
|
1999-12-01 15:12:49 +00:00
|
|
|
#include "nsIComponentManager.h"
|
1998-09-23 17:16:51 +00:00
|
|
|
#include "nsIDOMHTMLFormElement.h"
|
2014-06-03 22:52:36 +00:00
|
|
|
#include "mozilla/dom/ProgressEvent.h"
|
2006-12-26 17:47:52 +00:00
|
|
|
#include "nsGkAtoms.h"
|
1998-09-01 01:27:08 +00:00
|
|
|
#include "nsStyleConsts.h"
|
2004-07-31 23:15:21 +00:00
|
|
|
#include "nsPresContext.h"
|
2004-01-26 19:22:05 +00:00
|
|
|
#include "nsMappedAttributes.h"
|
1998-09-23 17:16:51 +00:00
|
|
|
#include "nsIFormControl.h"
|
|
|
|
#include "nsIForm.h"
|
2010-05-26 12:49:38 +00:00
|
|
|
#include "nsFormSubmission.h"
|
2010-08-20 17:47:30 +00:00
|
|
|
#include "nsFormSubmissionConstants.h"
|
1999-01-26 23:43:52 +00:00
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsIFormControlFrame.h"
|
2008-10-28 00:27:55 +00:00
|
|
|
#include "nsITextControlFrame.h"
|
1999-01-26 23:43:52 +00:00
|
|
|
#include "nsIFrame.h"
|
2013-03-08 09:40:12 +00:00
|
|
|
#include "nsRangeFrame.h"
|
2000-02-23 22:34:40 +00:00
|
|
|
#include "nsIServiceManager.h"
|
2012-07-27 14:03:27 +00:00
|
|
|
#include "nsError.h"
|
2000-07-14 23:20:48 +00:00
|
|
|
#include "nsIEditor.h"
|
2010-08-18 18:33:37 +00:00
|
|
|
#include "nsIIOService.h"
|
2011-05-04 12:49:59 +00:00
|
|
|
#include "nsDocument.h"
|
2012-02-14 02:00:56 +00:00
|
|
|
#include "nsAttrValueOrString.h"
|
1998-09-01 01:27:08 +00:00
|
|
|
|
2005-01-27 22:52:53 +00:00
|
|
|
#include "nsPresState.h"
|
2000-05-04 13:57:35 +00:00
|
|
|
#include "nsIDOMEvent.h"
|
2000-02-15 23:02:55 +00:00
|
|
|
#include "nsIDOMNodeList.h"
|
|
|
|
#include "nsIDOMHTMLCollection.h"
|
2001-11-02 07:40:01 +00:00
|
|
|
#include "nsLinebreakConverter.h" //to strip out carriage returns
|
|
|
|
#include "nsReadableUtils.h"
|
2002-09-16 06:00:08 +00:00
|
|
|
#include "nsUnicharUtils.h"
|
2005-12-12 23:53:06 +00:00
|
|
|
#include "nsLayoutUtils.h"
|
2000-01-14 09:28:54 +00:00
|
|
|
|
2001-05-11 21:11:38 +00:00
|
|
|
#include "nsIDOMMutationEvent.h"
|
2013-09-25 11:21:20 +00:00
|
|
|
#include "mozilla/ContentEvents.h"
|
2014-03-18 04:48:21 +00:00
|
|
|
#include "mozilla/EventDispatcher.h"
|
2014-04-03 04:18:36 +00:00
|
|
|
#include "mozilla/EventStates.h"
|
2014-02-27 10:51:15 +00:00
|
|
|
#include "mozilla/InternalMutationEvent.h"
|
2013-09-25 11:21:19 +00:00
|
|
|
#include "mozilla/TextEvents.h"
|
2013-09-25 11:21:16 +00:00
|
|
|
#include "mozilla/TouchEvents.h"
|
2001-05-11 21:11:38 +00:00
|
|
|
|
2004-07-20 06:11:27 +00:00
|
|
|
#include "nsRuleData.h"
|
2013-01-15 12:22:03 +00:00
|
|
|
#include <algorithm>
|
2001-05-31 22:19:43 +00:00
|
|
|
|
2010-09-05 18:00:05 +00:00
|
|
|
// input type=radio
|
|
|
|
#include "nsIRadioGroupContainer.h"
|
2002-07-20 23:09:24 +00:00
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
// input type=file
|
2014-10-08 16:15:23 +00:00
|
|
|
#include "mozilla/dom/File.h"
|
2012-06-06 02:08:30 +00:00
|
|
|
#include "nsIFile.h"
|
2002-09-16 06:00:08 +00:00
|
|
|
#include "nsNetUtil.h"
|
2010-08-27 15:49:06 +00:00
|
|
|
#include "nsDirectoryServiceDefs.h"
|
|
|
|
#include "nsIContentPrefService.h"
|
2012-06-06 12:16:58 +00:00
|
|
|
#include "nsIMIMEService.h"
|
2010-08-27 15:49:06 +00:00
|
|
|
#include "nsIObserverService.h"
|
|
|
|
#include "nsIPopupWindowManager.h"
|
2010-08-27 15:49:08 +00:00
|
|
|
#include "nsGlobalWindow.h"
|
2002-02-16 01:19:24 +00:00
|
|
|
|
2003-03-19 03:47:09 +00:00
|
|
|
// input type=image
|
|
|
|
#include "nsImageLoadingContent.h"
|
2012-10-12 12:43:01 +00:00
|
|
|
#include "imgRequestProxy.h"
|
2003-03-19 03:47:09 +00:00
|
|
|
|
2008-04-11 17:29:06 +00:00
|
|
|
#include "mozAutoDocUpdate.h"
|
2010-06-09 06:45:32 +00:00
|
|
|
#include "nsContentCreatorFunctions.h"
|
2010-08-18 19:26:22 +00:00
|
|
|
#include "nsContentUtils.h"
|
2012-11-21 10:13:57 +00:00
|
|
|
#include "mozilla/dom/DirectionalityUtils.h"
|
2011-04-11 18:31:00 +00:00
|
|
|
#include "nsRadioVisitor.h"
|
2013-09-06 06:40:45 +00:00
|
|
|
#include "nsTextEditorState.h"
|
2008-04-11 17:29:06 +00:00
|
|
|
|
2011-09-09 02:27:12 +00:00
|
|
|
#include "mozilla/LookAndFeel.h"
|
2012-06-23 12:32:54 +00:00
|
|
|
#include "mozilla/Preferences.h"
|
2012-12-22 14:46:19 +00:00
|
|
|
#include "mozilla/MathAlgorithms.h"
|
2011-09-09 02:27:12 +00:00
|
|
|
|
2012-02-29 22:35:47 +00:00
|
|
|
#include "nsIIDNService.h"
|
|
|
|
|
2012-06-22 09:36:24 +00:00
|
|
|
#include <limits>
|
|
|
|
|
2013-07-08 19:12:18 +00:00
|
|
|
#include "nsIColorPicker.h"
|
2013-08-15 18:17:48 +00:00
|
|
|
#include "nsIStringEnumerator.h"
|
2013-08-21 19:28:26 +00:00
|
|
|
#include "HTMLSplitOnSpacesTokenizer.h"
|
2013-09-22 23:23:30 +00:00
|
|
|
#include "nsIController.h"
|
2013-09-23 03:35:05 +00:00
|
|
|
#include "nsIMIMEInfo.h"
|
2013-07-08 19:12:18 +00:00
|
|
|
|
2012-12-27 18:55:31 +00:00
|
|
|
// input type=date
|
2013-05-02 03:44:11 +00:00
|
|
|
#include "js/Date.h"
|
2012-12-27 18:55:31 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Input)
|
2010-10-25 12:17:38 +00:00
|
|
|
|
1998-09-01 01:27:08 +00:00
|
|
|
// XXX align=left, hspace, vspace, border? other nav4 attrs
|
|
|
|
|
2000-09-09 05:46:14 +00:00
|
|
|
static NS_DEFINE_CID(kXULControllersCID, NS_XULCONTROLLERS_CID);
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
// This must come outside of any namespace, or else it won't overload with the
|
|
|
|
// double based version in nsMathUtils.h
|
2014-06-02 12:08:21 +00:00
|
|
|
inline mozilla::Decimal
|
2013-05-05 23:23:18 +00:00
|
|
|
NS_floorModulo(mozilla::Decimal x, mozilla::Decimal y)
|
|
|
|
{
|
|
|
|
return (x - y * (x / y).floor());
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
// First bits are needed for the control type.
|
|
|
|
#define NS_OUTER_ACTIVATE_EVENT (1 << 9)
|
|
|
|
#define NS_ORIGINAL_CHECKED_VALUE (1 << 10)
|
|
|
|
#define NS_NO_CONTENT_DISPATCH (1 << 11)
|
2009-01-22 00:07:44 +00:00
|
|
|
#define NS_ORIGINAL_INDETERMINATE_VALUE (1 << 12)
|
2006-03-07 17:08:51 +00:00
|
|
|
#define NS_CONTROL_TYPE(bits) ((bits) & ~( \
|
2009-01-22 00:07:44 +00:00
|
|
|
NS_OUTER_ACTIVATE_EVENT | NS_ORIGINAL_CHECKED_VALUE | NS_NO_CONTENT_DISPATCH | \
|
|
|
|
NS_ORIGINAL_INDETERMINATE_VALUE))
|
2006-03-07 17:08:51 +00:00
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
// whether textfields should be selected once focused:
|
|
|
|
// -1: no, 1: yes, 0: uninitialized
|
2012-08-22 15:56:38 +00:00
|
|
|
static int32_t gSelectTextFieldOnFocus;
|
2013-03-28 19:41:32 +00:00
|
|
|
UploadLastDir* HTMLInputElement::gUploadLastDir;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
|
2010-04-15 11:03:00 +00:00
|
|
|
static const nsAttrValue::EnumTable kInputTypeTable[] = {
|
|
|
|
{ "button", NS_FORM_INPUT_BUTTON },
|
|
|
|
{ "checkbox", NS_FORM_INPUT_CHECKBOX },
|
2013-05-23 13:02:23 +00:00
|
|
|
{ "color", NS_FORM_INPUT_COLOR },
|
2012-12-27 16:06:53 +00:00
|
|
|
{ "date", NS_FORM_INPUT_DATE },
|
2010-08-18 18:31:54 +00:00
|
|
|
{ "email", NS_FORM_INPUT_EMAIL },
|
2010-04-15 11:03:00 +00:00
|
|
|
{ "file", NS_FORM_INPUT_FILE },
|
|
|
|
{ "hidden", NS_FORM_INPUT_HIDDEN },
|
|
|
|
{ "reset", NS_FORM_INPUT_RESET },
|
|
|
|
{ "image", NS_FORM_INPUT_IMAGE },
|
2012-06-10 20:23:17 +00:00
|
|
|
{ "number", NS_FORM_INPUT_NUMBER },
|
2010-04-15 11:03:00 +00:00
|
|
|
{ "password", NS_FORM_INPUT_PASSWORD },
|
|
|
|
{ "radio", NS_FORM_INPUT_RADIO },
|
2013-02-16 12:35:57 +00:00
|
|
|
{ "range", NS_FORM_INPUT_RANGE },
|
2010-05-17 10:20:22 +00:00
|
|
|
{ "search", NS_FORM_INPUT_SEARCH },
|
2010-04-15 11:03:00 +00:00
|
|
|
{ "submit", NS_FORM_INPUT_SUBMIT },
|
2010-05-12 07:17:07 +00:00
|
|
|
{ "tel", NS_FORM_INPUT_TEL },
|
2010-04-15 11:03:00 +00:00
|
|
|
{ "text", NS_FORM_INPUT_TEXT },
|
2013-01-08 17:10:00 +00:00
|
|
|
{ "time", NS_FORM_INPUT_TIME },
|
2010-08-18 18:33:37 +00:00
|
|
|
{ "url", NS_FORM_INPUT_URL },
|
2010-04-15 11:03:00 +00:00
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
// Default type is 'text'.
|
2013-05-23 13:02:23 +00:00
|
|
|
static const nsAttrValue::EnumTable* kInputDefaultType = &kInputTypeTable[16];
|
2010-04-15 11:03:00 +00:00
|
|
|
|
2012-08-17 09:53:44 +00:00
|
|
|
static const uint8_t NS_INPUT_INPUTMODE_AUTO = 0;
|
|
|
|
static const uint8_t NS_INPUT_INPUTMODE_NUMERIC = 1;
|
|
|
|
static const uint8_t NS_INPUT_INPUTMODE_DIGIT = 2;
|
|
|
|
static const uint8_t NS_INPUT_INPUTMODE_UPPERCASE = 3;
|
|
|
|
static const uint8_t NS_INPUT_INPUTMODE_LOWERCASE = 4;
|
|
|
|
static const uint8_t NS_INPUT_INPUTMODE_TITLECASE = 5;
|
|
|
|
static const uint8_t NS_INPUT_INPUTMODE_AUTOCAPITALIZED = 6;
|
|
|
|
|
|
|
|
static const nsAttrValue::EnumTable kInputInputmodeTable[] = {
|
|
|
|
{ "auto", NS_INPUT_INPUTMODE_AUTO },
|
|
|
|
{ "numeric", NS_INPUT_INPUTMODE_NUMERIC },
|
|
|
|
{ "digit", NS_INPUT_INPUTMODE_DIGIT },
|
|
|
|
{ "uppercase", NS_INPUT_INPUTMODE_UPPERCASE },
|
|
|
|
{ "lowercase", NS_INPUT_INPUTMODE_LOWERCASE },
|
|
|
|
{ "titlecase", NS_INPUT_INPUTMODE_TITLECASE },
|
|
|
|
{ "autocapitalized", NS_INPUT_INPUTMODE_AUTOCAPITALIZED },
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
// Default inputmode value is "auto".
|
|
|
|
static const nsAttrValue::EnumTable* kInputDefaultInputmode = &kInputInputmodeTable[0];
|
|
|
|
|
2014-06-07 03:17:06 +00:00
|
|
|
const Decimal HTMLInputElement::kStepScaleFactorDate = Decimal(86400000);
|
|
|
|
const Decimal HTMLInputElement::kStepScaleFactorNumberRange = Decimal(1);
|
|
|
|
const Decimal HTMLInputElement::kStepScaleFactorTime = Decimal(1000);
|
|
|
|
const Decimal HTMLInputElement::kDefaultStepBase = Decimal(0);
|
|
|
|
const Decimal HTMLInputElement::kDefaultStep = Decimal(1);
|
|
|
|
const Decimal HTMLInputElement::kDefaultStepTime = Decimal(60);
|
|
|
|
const Decimal HTMLInputElement::kStepAny = Decimal(0);
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2008-12-12 19:25:22 +00:00
|
|
|
#define NS_INPUT_ELEMENT_STATE_IID \
|
|
|
|
{ /* dc3b3d14-23e2-4479-b513-7b369343e3a0 */ \
|
|
|
|
0xdc3b3d14, \
|
|
|
|
0x23e2, \
|
|
|
|
0x4479, \
|
|
|
|
{0xb5, 0x13, 0x7b, 0x36, 0x93, 0x43, 0xe3, 0xa0} \
|
|
|
|
}
|
|
|
|
|
2013-09-04 14:21:32 +00:00
|
|
|
#define PROGRESS_STR "progress"
|
|
|
|
static const uint32_t kProgressEventInterval = 50; // ms
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
class HTMLInputElementState MOZ_FINAL : public nsISupports
|
2008-12-12 19:25:22 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INPUT_ELEMENT_STATE_IID)
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool IsCheckedSet() {
|
2008-12-12 19:25:22 +00:00
|
|
|
return mCheckedSet;
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool GetChecked() {
|
2008-12-12 19:25:22 +00:00
|
|
|
return mChecked;
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
void SetChecked(bool aChecked) {
|
2008-12-12 19:25:22 +00:00
|
|
|
mChecked = aChecked;
|
2011-10-17 14:59:28 +00:00
|
|
|
mCheckedSet = true;
|
2008-12-12 19:25:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const nsString& GetValue() {
|
|
|
|
return mValue;
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
void SetValue(const nsAString& aValue) {
|
2008-12-12 19:25:22 +00:00
|
|
|
mValue = aValue;
|
|
|
|
}
|
|
|
|
|
2014-11-11 17:13:50 +00:00
|
|
|
const nsTArray<nsRefPtr<FileImpl>>& GetFileImpls() {
|
|
|
|
return mFileImpls;
|
2008-12-12 19:25:22 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 17:13:50 +00:00
|
|
|
void SetFileImpls(const nsTArray<nsRefPtr<File>>& aFile) {
|
|
|
|
mFileImpls.Clear();
|
|
|
|
for (uint32_t i = 0, len = aFile.Length(); i < len; ++i) {
|
|
|
|
mFileImpls.AppendElement(aFile[i]->Impl());
|
|
|
|
}
|
2008-12-12 19:25:22 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElementState()
|
2008-12-12 19:25:22 +00:00
|
|
|
: mValue()
|
2011-10-17 14:59:28 +00:00
|
|
|
, mChecked(false)
|
|
|
|
, mCheckedSet(false)
|
2008-12-12 19:25:22 +00:00
|
|
|
{};
|
2013-03-28 19:41:32 +00:00
|
|
|
|
2008-12-12 19:25:22 +00:00
|
|
|
protected:
|
2014-06-25 02:09:15 +00:00
|
|
|
~HTMLInputElementState() {}
|
|
|
|
|
2008-12-12 19:25:22 +00:00
|
|
|
nsString mValue;
|
2014-11-11 17:13:50 +00:00
|
|
|
nsTArray<nsRefPtr<FileImpl>> mFileImpls;
|
2011-09-29 06:19:26 +00:00
|
|
|
bool mChecked;
|
|
|
|
bool mCheckedSet;
|
2008-12-12 19:25:22 +00:00
|
|
|
};
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_DEFINE_STATIC_IID_ACCESSOR(HTMLInputElementState, NS_INPUT_ELEMENT_STATE_IID)
|
2008-12-12 19:25:22 +00:00
|
|
|
|
2014-04-27 07:06:00 +00:00
|
|
|
NS_IMPL_ISUPPORTS(HTMLInputElementState, HTMLInputElementState)
|
2014-03-28 08:45:02 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::nsFilePickerShownCallback::nsFilePickerShownCallback(
|
2013-07-22 12:46:27 +00:00
|
|
|
HTMLInputElement* aInput, nsIFilePicker* aFilePicker)
|
2012-08-17 15:35:01 +00:00
|
|
|
: mFilePicker(aFilePicker)
|
|
|
|
, mInput(aInput)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-04-27 07:06:00 +00:00
|
|
|
NS_IMPL_ISUPPORTS(UploadLastDir::ContentPrefCallback, nsIContentPrefCallback2)
|
2013-03-30 02:08:57 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
UploadLastDir::ContentPrefCallback::HandleCompletion(uint16_t aReason)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIFile> localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
|
|
|
|
NS_ENSURE_STATE(localFile);
|
|
|
|
|
|
|
|
if (aReason == nsIContentPrefCallback2::COMPLETE_ERROR ||
|
|
|
|
!mResult) {
|
|
|
|
// Default to "desktop" directory for each platform
|
|
|
|
nsCOMPtr<nsIFile> homeDir;
|
|
|
|
NS_GetSpecialDirectory(NS_OS_DESKTOP_DIR, getter_AddRefs(homeDir));
|
|
|
|
localFile = do_QueryInterface(homeDir);
|
|
|
|
} else {
|
|
|
|
nsAutoString prefStr;
|
|
|
|
nsCOMPtr<nsIVariant> pref;
|
|
|
|
mResult->GetValue(getter_AddRefs(pref));
|
|
|
|
pref->GetAsAString(prefStr);
|
|
|
|
localFile->InitWithPath(prefStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
mFilePicker->SetDisplayDirectory(localFile);
|
|
|
|
mFilePicker->Open(mFpCallback);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
UploadLastDir::ContentPrefCallback::HandleResult(nsIContentPref* pref)
|
|
|
|
{
|
|
|
|
mResult = pref;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
UploadLastDir::ContentPrefCallback::HandleError(nsresult error)
|
|
|
|
{
|
|
|
|
// HandleCompletion is always called (even with HandleError was called),
|
|
|
|
// so we don't need to do anything special here.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
/**
|
2014-10-08 16:15:23 +00:00
|
|
|
* This enumerator returns File objects after wrapping a single
|
2013-08-22 09:43:26 +00:00
|
|
|
* nsIFile representing a directory. It enumerates the files under that
|
|
|
|
* directory and its subdirectories as a flat list of files, ignoring/skipping
|
|
|
|
* over symbolic links.
|
|
|
|
*
|
|
|
|
* The enumeration involves I/O, so this class must NOT be used on the main
|
|
|
|
* thread or else the main thread could be blocked for a very long time.
|
|
|
|
*
|
|
|
|
* This enumerator does not walk the directory tree breadth-first, but it also
|
|
|
|
* is not guaranteed to walk it depth-first either (since it uses
|
|
|
|
* nsIFile::GetDirectoryEntries, which is not guaranteed to group a directory's
|
|
|
|
* subdirectories at the beginning of the list that it returns).
|
|
|
|
*/
|
|
|
|
class DirPickerRecursiveFileEnumerator MOZ_FINAL
|
|
|
|
: public nsISimpleEnumerator
|
|
|
|
{
|
2014-06-25 02:09:15 +00:00
|
|
|
~DirPickerRecursiveFileEnumerator() {}
|
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
2014-09-02 00:49:25 +00:00
|
|
|
explicit DirPickerRecursiveFileEnumerator(nsIFile* aTopDir)
|
2013-08-22 09:43:26 +00:00
|
|
|
: mTopDir(aTopDir)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!NS_IsMainThread(), "This class blocks on I/O!");
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
|
|
|
bool isDir;
|
|
|
|
aTopDir->IsDirectory(&isDir);
|
|
|
|
MOZ_ASSERT(isDir);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-10-01 23:26:40 +00:00
|
|
|
if (NS_FAILED(aTopDir->GetParent(getter_AddRefs(mTopDirsParent)))) {
|
|
|
|
// This just means that the name of the picked directory won't be
|
|
|
|
// included in the File.path string.
|
|
|
|
mTopDirsParent = aTopDir;
|
|
|
|
}
|
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
nsCOMPtr<nsISimpleEnumerator> entries;
|
|
|
|
if (NS_SUCCEEDED(mTopDir->GetDirectoryEntries(getter_AddRefs(entries))) &&
|
|
|
|
entries) {
|
|
|
|
mDirEnumeratorStack.AppendElement(entries);
|
|
|
|
LookupAndCacheNext();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD
|
2015-01-06 20:13:36 +00:00
|
|
|
GetNext(nsISupports** aResult) MOZ_OVERRIDE
|
2013-08-22 09:43:26 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(!NS_IsMainThread(),
|
|
|
|
"Walking the directory tree involves I/O, so using this "
|
|
|
|
"enumerator can block a thread for a long time!");
|
|
|
|
|
|
|
|
if (!mNextFile) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2014-10-08 16:15:22 +00:00
|
|
|
|
|
|
|
// The parent for this object will be set on the main thread.
|
2014-10-08 16:15:23 +00:00
|
|
|
nsRefPtr<File> domFile = File::CreateFromFile(nullptr, mNextFile);
|
2013-08-23 07:41:17 +00:00
|
|
|
nsCString relDescriptor;
|
2013-10-01 23:26:40 +00:00
|
|
|
nsresult rv =
|
|
|
|
mNextFile->GetRelativeDescriptor(mTopDirsParent, relDescriptor);
|
2013-08-23 07:41:17 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
NS_ConvertUTF8toUTF16 path(relDescriptor);
|
|
|
|
nsAutoString leafName;
|
|
|
|
mNextFile->GetLeafName(leafName);
|
|
|
|
MOZ_ASSERT(leafName.Length() <= path.Length());
|
2013-08-27 08:30:28 +00:00
|
|
|
int32_t length = path.Length() - leafName.Length();
|
|
|
|
MOZ_ASSERT(length >= 0);
|
2013-08-23 07:41:17 +00:00
|
|
|
if (length > 0) {
|
2013-08-27 08:30:28 +00:00
|
|
|
// Note that we leave the trailing "/" on the path.
|
2014-10-08 16:15:23 +00:00
|
|
|
FileImplFile* fileImpl = static_cast<FileImplFile*>(domFile->Impl());
|
2014-06-26 16:47:44 +00:00
|
|
|
MOZ_ASSERT(fileImpl);
|
|
|
|
fileImpl->SetPath(Substring(path, 0, uint32_t(length)));
|
2013-08-23 07:41:17 +00:00
|
|
|
}
|
2014-03-15 19:00:15 +00:00
|
|
|
*aResult = domFile.forget().downcast<nsIDOMFile>().take();
|
2013-08-22 09:43:26 +00:00
|
|
|
LookupAndCacheNext();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHOD
|
2015-01-06 20:13:36 +00:00
|
|
|
HasMoreElements(bool* aResult) MOZ_OVERRIDE
|
2013-08-22 09:43:26 +00:00
|
|
|
{
|
|
|
|
*aResult = !!mNextFile;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
void
|
|
|
|
LookupAndCacheNext()
|
|
|
|
{
|
|
|
|
for (;;) {
|
|
|
|
if (mDirEnumeratorStack.IsEmpty()) {
|
|
|
|
mNextFile = nullptr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsISimpleEnumerator* currentDirEntries =
|
|
|
|
mDirEnumeratorStack.LastElement();
|
|
|
|
|
|
|
|
bool hasMore;
|
|
|
|
DebugOnly<nsresult> rv = currentDirEntries->HasMoreElements(&hasMore);
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
|
|
|
|
if (!hasMore) {
|
|
|
|
mDirEnumeratorStack.RemoveElementAt(mDirEnumeratorStack.Length() - 1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupports> entry;
|
|
|
|
rv = currentDirEntries->GetNext(getter_AddRefs(entry));
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
|
|
|
|
MOZ_ASSERT(file);
|
|
|
|
|
|
|
|
bool isLink, isSpecial;
|
|
|
|
file->IsSymlink(&isLink);
|
|
|
|
file->IsSpecial(&isSpecial);
|
|
|
|
if (isLink || isSpecial) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDir;
|
|
|
|
file->IsDirectory(&isDir);
|
|
|
|
if (isDir) {
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> subDirEntries;
|
|
|
|
rv = file->GetDirectoryEntries(getter_AddRefs(subDirEntries));
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv) && subDirEntries);
|
|
|
|
mDirEnumeratorStack.AppendElement(subDirEntries);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
|
|
|
bool isFile;
|
|
|
|
file->IsFile(&isFile);
|
|
|
|
MOZ_ASSERT(isFile);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
mNextFile.swap(file);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIFile> mTopDir;
|
2013-10-01 23:26:40 +00:00
|
|
|
nsCOMPtr<nsIFile> mTopDirsParent; // May be mTopDir if no parent
|
2013-08-22 09:43:26 +00:00
|
|
|
nsCOMPtr<nsIFile> mNextFile;
|
|
|
|
nsTArray<nsCOMPtr<nsISimpleEnumerator> > mDirEnumeratorStack;
|
|
|
|
};
|
|
|
|
|
2014-04-27 07:06:00 +00:00
|
|
|
NS_IMPL_ISUPPORTS(DirPickerRecursiveFileEnumerator, nsISimpleEnumerator)
|
2013-08-22 09:43:26 +00:00
|
|
|
|
2013-10-08 17:47:08 +00:00
|
|
|
/**
|
|
|
|
* This may return nullptr if aDomFile's implementation of
|
|
|
|
* nsIDOMFile::mozFullPathInternal does not successfully return a non-empty
|
|
|
|
* string that is a valid path. This can happen on Firefox OS, for example,
|
|
|
|
* where the file picker can create Blobs.
|
|
|
|
*/
|
|
|
|
static already_AddRefed<nsIFile>
|
|
|
|
DOMFileToLocalFile(nsIDOMFile* aDomFile)
|
|
|
|
{
|
|
|
|
nsString path;
|
|
|
|
nsresult rv = aDomFile->GetMozFullPathInternal(path);
|
|
|
|
if (NS_FAILED(rv) || path.IsEmpty()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIFile> localFile;
|
|
|
|
rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
|
|
|
|
getter_AddRefs(localFile));
|
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
|
|
|
|
|
|
|
return localFile.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
2013-10-06 09:01:38 +00:00
|
|
|
class DirPickerFileListBuilderTask MOZ_FINAL
|
2013-08-22 09:43:26 +00:00
|
|
|
: public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
2013-10-06 09:01:38 +00:00
|
|
|
DirPickerFileListBuilderTask(HTMLInputElement* aInput, nsIFile* aTopDir)
|
2013-10-08 17:47:08 +00:00
|
|
|
: mPreviousFileListLength(0)
|
|
|
|
, mInput(aInput)
|
2013-08-22 09:43:26 +00:00
|
|
|
, mTopDir(aTopDir)
|
2013-10-08 17:47:08 +00:00
|
|
|
, mFileListLength(0)
|
2014-02-07 06:17:07 +00:00
|
|
|
, mCanceled(false)
|
2013-08-22 09:43:26 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
NS_IMETHOD Run() {
|
|
|
|
if (!NS_IsMainThread()) {
|
2014-10-08 16:15:23 +00:00
|
|
|
// Build up list of File objects on this dedicated thread:
|
2013-08-22 09:43:26 +00:00
|
|
|
nsCOMPtr<nsISimpleEnumerator> iter =
|
|
|
|
new DirPickerRecursiveFileEnumerator(mTopDir);
|
|
|
|
bool hasMore = true;
|
|
|
|
nsCOMPtr<nsISupports> tmp;
|
|
|
|
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
|
|
|
|
iter->GetNext(getter_AddRefs(tmp));
|
|
|
|
nsCOMPtr<nsIDOMFile> domFile = do_QueryInterface(tmp);
|
|
|
|
MOZ_ASSERT(domFile);
|
2014-10-08 16:15:23 +00:00
|
|
|
mFileList.AppendElement(static_cast<File*>(domFile.get()));
|
2013-10-08 17:47:08 +00:00
|
|
|
mFileListLength = mFileList.Length();
|
|
|
|
if (mCanceled) {
|
2013-10-15 00:18:40 +00:00
|
|
|
MOZ_ASSERT(!mInput, "This is bad - how did this happen?");
|
2013-10-08 17:47:08 +00:00
|
|
|
// There's no point dispatching to the main thread (that doesn't
|
|
|
|
// guarantee that we'll be destroyed there).
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2013-08-22 09:43:26 +00:00
|
|
|
}
|
|
|
|
return NS_DispatchToMainThread(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now back on the main thread, set the list on our HTMLInputElement:
|
2013-10-08 17:47:08 +00:00
|
|
|
if (mCanceled || mFileList.IsEmpty()) {
|
2013-08-22 09:43:26 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2013-10-08 17:47:08 +00:00
|
|
|
MOZ_ASSERT(mInput->mDirPickerFileListBuilderTask,
|
|
|
|
"But we aren't canceled!");
|
|
|
|
if (mInput->mProgressTimer) {
|
|
|
|
mInput->mProgressTimerIsActive = false;
|
|
|
|
mInput->mProgressTimer->Cancel();
|
|
|
|
}
|
|
|
|
|
2013-10-08 17:47:49 +00:00
|
|
|
mInput->MaybeDispatchProgressEvent(true); // Last progress event.
|
|
|
|
mInput->mDirPickerFileListBuilderTask = nullptr; // Now null out.
|
|
|
|
|
|
|
|
if (mCanceled) { // The last progress event may have canceled us
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-10-08 16:15:23 +00:00
|
|
|
// Recreate File with the correct parent object.
|
2014-10-08 16:15:22 +00:00
|
|
|
nsCOMPtr<nsIGlobalObject> global = mInput->OwnerDoc()->GetScopeObject();
|
|
|
|
for (uint32_t i = 0; i < mFileList.Length(); ++i) {
|
|
|
|
MOZ_ASSERT(!mFileList[i]->GetParentObject());
|
2014-10-08 16:15:23 +00:00
|
|
|
mFileList[i] = new File(global, mFileList[i]->Impl());
|
2014-10-08 16:15:22 +00:00
|
|
|
}
|
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
// The text control frame (if there is one) isn't going to send a change
|
|
|
|
// event because it will think this is done by a script.
|
|
|
|
// So, we can safely send one by ourself.
|
|
|
|
mInput->SetFiles(mFileList, true);
|
|
|
|
nsresult rv =
|
|
|
|
nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
|
|
|
|
static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
|
|
|
|
NS_LITERAL_STRING("change"), true,
|
|
|
|
false);
|
|
|
|
// Clear mInput to make sure that it can't lose its last strong ref off the
|
|
|
|
// main thread (which may happen if our dtor runs off the main thread)!
|
|
|
|
mInput = nullptr;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2013-10-08 17:47:08 +00:00
|
|
|
void Cancel()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread() && !mCanceled);
|
|
|
|
// Clear mInput to make sure that it can't lose its last strong ref off the
|
|
|
|
// main thread (which may happen if our dtor runs off the main thread)!
|
|
|
|
mInput = nullptr;
|
2014-02-07 06:17:07 +00:00
|
|
|
mCanceled = true;
|
2013-10-08 17:47:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t GetFileListLength() const
|
|
|
|
{
|
|
|
|
return mFileListLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The number of files added to the FileList at the time the last progress
|
|
|
|
* event was fired.
|
|
|
|
*
|
|
|
|
* This is only read/set by HTMLInputElement on the main thread. The reason
|
|
|
|
* that this member is stored here rather than on HTMLInputElement is so that
|
|
|
|
* we don't increase the size of HTMLInputElement for something that's rarely
|
|
|
|
* used.
|
|
|
|
*/
|
|
|
|
uint32_t mPreviousFileListLength;
|
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
private:
|
|
|
|
nsRefPtr<HTMLInputElement> mInput;
|
|
|
|
nsCOMPtr<nsIFile> mTopDir;
|
2014-10-08 16:15:23 +00:00
|
|
|
nsTArray<nsRefPtr<File>> mFileList;
|
2013-08-22 09:43:26 +00:00
|
|
|
|
2013-10-08 17:47:08 +00:00
|
|
|
// We access the list length on both threads, so we need the indirection of
|
|
|
|
// this atomic member to make the access thread safe:
|
|
|
|
mozilla::Atomic<uint32_t> mFileListLength;
|
2013-08-22 09:43:26 +00:00
|
|
|
|
2014-02-07 06:17:07 +00:00
|
|
|
mozilla::Atomic<bool> mCanceled;
|
2013-10-08 17:47:08 +00:00
|
|
|
};
|
2013-08-22 09:43:26 +00:00
|
|
|
|
|
|
|
|
2012-08-17 15:35:01 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
|
2012-08-17 15:35:01 +00:00
|
|
|
{
|
2013-12-07 12:09:14 +00:00
|
|
|
mInput->PickerClosed();
|
|
|
|
|
2012-08-17 15:35:01 +00:00
|
|
|
if (aResult == nsIFilePicker::returnCancel) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-10-08 17:47:08 +00:00
|
|
|
mInput->CancelDirectoryPickerScanIfRunning();
|
|
|
|
|
2013-07-22 12:46:27 +00:00
|
|
|
int16_t mode;
|
|
|
|
mFilePicker->GetMode(&mode);
|
2013-08-22 09:43:26 +00:00
|
|
|
|
|
|
|
if (mode == static_cast<int16_t>(nsIFilePicker::modeGetFolder)) {
|
|
|
|
// Directory picking is different, since we still need to do more I/O to
|
2014-10-08 16:15:23 +00:00
|
|
|
// build up the list of File objects. Since this may block for a
|
2013-08-22 09:43:26 +00:00
|
|
|
// long time, we need to build the list off on another dedicated thread to
|
|
|
|
// avoid blocking any other activities that the browser is carrying out.
|
|
|
|
|
|
|
|
// The user selected this directory, so we always save this dir, even if
|
|
|
|
// no files are found under it.
|
|
|
|
nsCOMPtr<nsIFile> pickedDir;
|
|
|
|
mFilePicker->GetFile(getter_AddRefs(pickedDir));
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
|
|
|
bool isDir;
|
|
|
|
pickedDir->IsDirectory(&isDir);
|
|
|
|
MOZ_ASSERT(isDir);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
HTMLInputElement::gUploadLastDir->StoreLastUsedDirectory(
|
|
|
|
mInput->OwnerDoc(), pickedDir);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIEventTarget> target
|
|
|
|
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
|
|
|
NS_ASSERTION(target, "Must have stream transport service");
|
|
|
|
|
2013-09-04 14:21:32 +00:00
|
|
|
mInput->StartProgressEventTimer();
|
|
|
|
|
2013-10-06 09:01:38 +00:00
|
|
|
// DirPickerFileListBuilderTask takes care of calling SetFiles() and
|
2013-08-22 09:43:26 +00:00
|
|
|
// dispatching the "change" event.
|
2013-10-08 17:47:08 +00:00
|
|
|
mInput->mDirPickerFileListBuilderTask =
|
2013-10-06 09:01:38 +00:00
|
|
|
new DirPickerFileListBuilderTask(mInput.get(), pickedDir.get());
|
2013-10-08 17:47:08 +00:00
|
|
|
return target->Dispatch(mInput->mDirPickerFileListBuilderTask,
|
|
|
|
NS_DISPATCH_NORMAL);
|
2013-08-22 09:43:26 +00:00
|
|
|
}
|
2013-07-22 12:46:27 +00:00
|
|
|
|
2012-08-17 15:35:01 +00:00
|
|
|
// Collect new selected filenames
|
2014-10-08 16:15:23 +00:00
|
|
|
nsTArray<nsRefPtr<File>> newFiles;
|
2013-08-22 09:43:26 +00:00
|
|
|
if (mode == static_cast<int16_t>(nsIFilePicker::modeOpenMultiple)) {
|
2012-08-17 15:35:01 +00:00
|
|
|
nsCOMPtr<nsISimpleEnumerator> iter;
|
2013-03-19 17:49:16 +00:00
|
|
|
nsresult rv = mFilePicker->GetDomfiles(getter_AddRefs(iter));
|
2012-08-17 15:35:01 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2013-06-11 19:09:49 +00:00
|
|
|
if (!iter) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-08-17 15:35:01 +00:00
|
|
|
nsCOMPtr<nsISupports> tmp;
|
2013-08-22 09:43:26 +00:00
|
|
|
bool hasMore = true;
|
2013-03-19 17:49:16 +00:00
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
|
2012-08-17 15:35:01 +00:00
|
|
|
iter->GetNext(getter_AddRefs(tmp));
|
2013-03-19 17:49:16 +00:00
|
|
|
nsCOMPtr<nsIDOMFile> domFile = do_QueryInterface(tmp);
|
2014-10-28 16:54:57 +00:00
|
|
|
NS_WARN_IF_FALSE(domFile,
|
|
|
|
"Null file object from FilePicker's file enumerator?");
|
|
|
|
if (domFile) {
|
|
|
|
newFiles.AppendElement(static_cast<File*>(domFile.get()));
|
|
|
|
}
|
2012-08-17 15:35:01 +00:00
|
|
|
}
|
2013-08-22 09:43:26 +00:00
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(mode == static_cast<int16_t>(nsIFilePicker::modeOpen));
|
2013-03-19 17:49:16 +00:00
|
|
|
nsCOMPtr<nsIDOMFile> domFile;
|
|
|
|
nsresult rv = mFilePicker->GetDomfile(getter_AddRefs(domFile));
|
2012-08-17 15:35:01 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2013-03-19 17:49:16 +00:00
|
|
|
if (domFile) {
|
2014-10-08 16:15:23 +00:00
|
|
|
newFiles.AppendElement(static_cast<File*>(domFile.get()));
|
2010-08-27 15:49:06 +00:00
|
|
|
}
|
2012-08-17 15:35:01 +00:00
|
|
|
}
|
2010-08-27 15:49:06 +00:00
|
|
|
|
2013-08-16 10:11:29 +00:00
|
|
|
if (newFiles.IsEmpty()) {
|
2012-08-17 15:35:01 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2010-08-27 15:49:06 +00:00
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
// Store the last used directory using the content pref service:
|
|
|
|
nsCOMPtr<nsIFile> file = DOMFileToLocalFile(newFiles[0]);
|
2013-10-09 11:15:14 +00:00
|
|
|
if (file) {
|
|
|
|
nsCOMPtr<nsIFile> lastUsedDir;
|
|
|
|
file->GetParent(getter_AddRefs(lastUsedDir));
|
|
|
|
HTMLInputElement::gUploadLastDir->StoreLastUsedDirectory(
|
|
|
|
mInput->OwnerDoc(), lastUsedDir);
|
|
|
|
}
|
2013-08-22 09:43:26 +00:00
|
|
|
|
2012-08-17 15:35:01 +00:00
|
|
|
// The text control frame (if there is one) isn't going to send a change
|
|
|
|
// event because it will think this is done by a script.
|
|
|
|
// So, we can safely send one by ourself.
|
|
|
|
mInput->SetFiles(newFiles, true);
|
|
|
|
return nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
|
|
|
|
static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
|
|
|
|
NS_LITERAL_STRING("change"), true,
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
2014-04-27 07:06:00 +00:00
|
|
|
NS_IMPL_ISUPPORTS(HTMLInputElement::nsFilePickerShownCallback,
|
|
|
|
nsIFilePickerShownCallback)
|
2012-08-17 15:35:01 +00:00
|
|
|
|
2013-07-08 19:12:18 +00:00
|
|
|
class nsColorPickerShownCallback MOZ_FINAL
|
|
|
|
: public nsIColorPickerShownCallback
|
|
|
|
{
|
2014-06-25 02:09:15 +00:00
|
|
|
~nsColorPickerShownCallback() {}
|
|
|
|
|
2013-07-08 19:12:18 +00:00
|
|
|
public:
|
|
|
|
nsColorPickerShownCallback(HTMLInputElement* aInput,
|
|
|
|
nsIColorPicker* aColorPicker)
|
|
|
|
: mInput(aInput)
|
|
|
|
, mColorPicker(aColorPicker)
|
|
|
|
, mValueChanged(false)
|
|
|
|
{}
|
|
|
|
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
|
|
|
NS_IMETHOD Update(const nsAString& aColor) MOZ_OVERRIDE;
|
|
|
|
NS_IMETHOD Done(const nsAString& aColor) MOZ_OVERRIDE;
|
|
|
|
|
|
|
|
private:
|
|
|
|
/**
|
|
|
|
* Updates the internals of the object using aColor as the new value.
|
|
|
|
* If aTrustedUpdate is true, it will consider that aColor is a new value.
|
|
|
|
* Otherwise, it will check that aColor is different from the current value.
|
|
|
|
*/
|
|
|
|
nsresult UpdateInternal(const nsAString& aColor, bool aTrustedUpdate);
|
|
|
|
|
|
|
|
nsRefPtr<HTMLInputElement> mInput;
|
|
|
|
nsCOMPtr<nsIColorPicker> mColorPicker;
|
|
|
|
bool mValueChanged;
|
|
|
|
};
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsColorPickerShownCallback::UpdateInternal(const nsAString& aColor,
|
|
|
|
bool aTrustedUpdate)
|
|
|
|
{
|
|
|
|
bool valueChanged = false;
|
|
|
|
|
|
|
|
nsAutoString oldValue;
|
|
|
|
if (aTrustedUpdate) {
|
|
|
|
valueChanged = true;
|
|
|
|
} else {
|
|
|
|
mInput->GetValue(oldValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
mInput->SetValue(aColor);
|
|
|
|
|
|
|
|
if (!aTrustedUpdate) {
|
|
|
|
nsAutoString newValue;
|
|
|
|
mInput->GetValue(newValue);
|
|
|
|
if (!oldValue.Equals(newValue)) {
|
|
|
|
valueChanged = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (valueChanged) {
|
|
|
|
mValueChanged = true;
|
|
|
|
return nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
|
|
|
|
static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
|
|
|
|
NS_LITERAL_STRING("input"), true,
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsColorPickerShownCallback::Update(const nsAString& aColor)
|
|
|
|
{
|
|
|
|
return UpdateInternal(aColor, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsColorPickerShownCallback::Done(const nsAString& aColor)
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* When Done() is called, we might be at the end of a serie of Update() calls
|
|
|
|
* in which case mValueChanged is set to true and a change event will have to
|
|
|
|
* be fired but we might also be in a one shot Done() call situation in which
|
|
|
|
* case we should fire a change event iif the value actually changed.
|
|
|
|
* UpdateInternal(bool) is taking care of that logic for us.
|
|
|
|
*/
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
2013-12-07 12:09:14 +00:00
|
|
|
mInput->PickerClosed();
|
|
|
|
|
2013-07-08 19:12:18 +00:00
|
|
|
if (!aColor.IsEmpty()) {
|
|
|
|
UpdateInternal(aColor, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mValueChanged) {
|
|
|
|
rv = nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
|
|
|
|
static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
|
|
|
|
NS_LITERAL_STRING("change"), true,
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2014-04-27 07:06:00 +00:00
|
|
|
NS_IMPL_ISUPPORTS(nsColorPickerShownCallback, nsIColorPickerShownCallback)
|
2013-07-08 19:12:18 +00:00
|
|
|
|
2013-08-02 11:40:49 +00:00
|
|
|
bool
|
|
|
|
HTMLInputElement::IsPopupBlocked() const
|
2012-08-17 15:35:01 +00:00
|
|
|
{
|
2013-08-02 11:40:49 +00:00
|
|
|
nsCOMPtr<nsPIDOMWindow> win = OwnerDoc()->GetWindow();
|
|
|
|
MOZ_ASSERT(win, "window should not be null");
|
|
|
|
if (!win) {
|
|
|
|
return true;
|
2012-08-17 15:35:01 +00:00
|
|
|
}
|
2010-08-27 15:49:06 +00:00
|
|
|
|
2013-08-02 11:40:49 +00:00
|
|
|
// Check if page is allowed to open the popup
|
|
|
|
if (win->GetPopupControlState() <= openControlled) {
|
|
|
|
return false;
|
2013-05-23 13:02:23 +00:00
|
|
|
}
|
2013-08-02 11:40:49 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIPopupWindowManager> pm = do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
|
|
|
|
if (!pm) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t permission;
|
|
|
|
pm->TestPermission(OwnerDoc()->NodePrincipal(), &permission);
|
|
|
|
return permission == nsIPopupWindowManager::DENY_POPUP;
|
2013-05-23 13:02:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2013-08-02 11:40:49 +00:00
|
|
|
HTMLInputElement::InitColorPicker()
|
2013-05-23 13:02:23 +00:00
|
|
|
{
|
2013-12-07 12:09:14 +00:00
|
|
|
if (mPickerRunning) {
|
|
|
|
NS_WARNING("Just one nsIColorPicker is allowed");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2013-08-02 11:40:49 +00:00
|
|
|
nsCOMPtr<nsIDocument> doc = OwnerDoc();
|
2013-07-08 19:12:18 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindow> win = doc->GetWindow();
|
|
|
|
if (!win) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2013-08-02 11:40:49 +00:00
|
|
|
if (IsPopupBlocked()) {
|
2014-06-30 23:02:01 +00:00
|
|
|
win->FirePopupBlockedEvent(doc, nullptr, EmptyString(), EmptyString());
|
2013-08-02 11:40:49 +00:00
|
|
|
return NS_OK;
|
2013-07-08 19:12:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get Loc title
|
|
|
|
nsXPIDLString title;
|
|
|
|
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
|
|
|
"ColorPicker", title);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIColorPicker> colorPicker = do_CreateInstance("@mozilla.org/colorpicker;1");
|
|
|
|
if (!colorPicker) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString initialValue;
|
2013-08-02 11:40:49 +00:00
|
|
|
GetValueInternal(initialValue);
|
2013-07-08 19:12:18 +00:00
|
|
|
nsresult rv = colorPicker->Init(win, title, initialValue);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIColorPickerShownCallback> callback =
|
2013-08-02 11:40:49 +00:00
|
|
|
new nsColorPickerShownCallback(this, colorPicker);
|
2013-07-08 19:12:18 +00:00
|
|
|
|
2013-12-07 12:09:14 +00:00
|
|
|
rv = colorPicker->Open(callback);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
mPickerRunning = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
2013-05-23 13:02:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2013-08-22 09:43:26 +00:00
|
|
|
HTMLInputElement::InitFilePicker(FilePickerType aType)
|
2010-08-27 15:49:06 +00:00
|
|
|
{
|
2013-12-07 12:09:14 +00:00
|
|
|
if (mPickerRunning) {
|
|
|
|
NS_WARNING("Just one nsIFilePicker is allowed");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2011-07-15 10:31:34 +00:00
|
|
|
// Get parent nsPIDOMWindow object.
|
2013-08-02 11:40:49 +00:00
|
|
|
nsCOMPtr<nsIDocument> doc = OwnerDoc();
|
2010-08-27 15:49:06 +00:00
|
|
|
|
2013-08-02 11:40:49 +00:00
|
|
|
nsCOMPtr<nsPIDOMWindow> win = doc->GetWindow();
|
2010-08-27 15:49:06 +00:00
|
|
|
if (!win) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2013-08-02 11:40:49 +00:00
|
|
|
if (IsPopupBlocked()) {
|
2014-06-30 23:02:01 +00:00
|
|
|
win->FirePopupBlockedEvent(doc, nullptr, EmptyString(), EmptyString());
|
2013-08-02 11:40:49 +00:00
|
|
|
return NS_OK;
|
2010-09-05 18:00:05 +00:00
|
|
|
}
|
2010-08-27 15:49:06 +00:00
|
|
|
|
|
|
|
// Get Loc title
|
|
|
|
nsXPIDLString title;
|
|
|
|
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
|
|
|
"FileUpload", title);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIFilePicker> filePicker = do_CreateInstance("@mozilla.org/filepicker;1");
|
|
|
|
if (!filePicker)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
int16_t mode;
|
|
|
|
|
|
|
|
if (aType == FILE_PICKER_DIRECTORY) {
|
|
|
|
mode = static_cast<int16_t>(nsIFilePicker::modeGetFolder);
|
|
|
|
} else if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
|
|
|
|
mode = static_cast<int16_t>(nsIFilePicker::modeOpenMultiple);
|
|
|
|
} else {
|
|
|
|
mode = static_cast<int16_t>(nsIFilePicker::modeOpen);
|
|
|
|
}
|
2010-08-27 15:49:06 +00:00
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
nsresult rv = filePicker->Init(win, title, mode);
|
2010-08-27 15:49:06 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
// Native directory pickers ignore file type filters, so we don't spend
|
|
|
|
// cycles adding them for FILE_PICKER_DIRECTORY.
|
|
|
|
if (HasAttr(kNameSpaceID_None, nsGkAtoms::accept) &&
|
|
|
|
aType != FILE_PICKER_DIRECTORY) {
|
2013-08-02 11:40:49 +00:00
|
|
|
SetFilePickerFiltersFromAccept(filePicker);
|
2010-10-08 10:07:20 +00:00
|
|
|
} else {
|
|
|
|
filePicker->AppendFilters(nsIFilePicker::filterAll);
|
2010-08-27 15:49:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set default directry and filename
|
|
|
|
nsAutoString defaultName;
|
|
|
|
|
2014-10-08 16:15:23 +00:00
|
|
|
const nsTArray<nsRefPtr<File>>& oldFiles = GetFilesInternal();
|
2010-08-27 15:49:06 +00:00
|
|
|
|
2013-03-30 02:08:57 +00:00
|
|
|
nsCOMPtr<nsIFilePickerShownCallback> callback =
|
2013-07-22 12:46:27 +00:00
|
|
|
new HTMLInputElement::nsFilePickerShownCallback(this, filePicker);
|
2013-03-30 02:08:57 +00:00
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
if (!oldFiles.IsEmpty() &&
|
|
|
|
aType != FILE_PICKER_DIRECTORY) {
|
2010-09-05 18:00:05 +00:00
|
|
|
nsString path;
|
|
|
|
|
|
|
|
oldFiles[0]->GetMozFullPathInternal(path);
|
|
|
|
|
2012-06-06 02:08:30 +00:00
|
|
|
nsCOMPtr<nsIFile> localFile;
|
2011-10-17 14:59:28 +00:00
|
|
|
rv = NS_NewLocalFile(path, false, getter_AddRefs(localFile));
|
2010-09-05 18:00:05 +00:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsCOMPtr<nsIFile> parentFile;
|
|
|
|
rv = localFile->GetParent(getter_AddRefs(parentFile));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2012-06-06 02:08:30 +00:00
|
|
|
filePicker->SetDisplayDirectory(parentFile);
|
2010-08-27 15:49:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unfortunately nsIFilePicker doesn't allow multiple files to be
|
|
|
|
// default-selected, so only select something by default if exactly
|
|
|
|
// one file was selected before.
|
2013-08-16 10:11:29 +00:00
|
|
|
if (oldFiles.Length() == 1) {
|
2010-08-27 15:49:06 +00:00
|
|
|
nsAutoString leafName;
|
2010-09-05 18:00:05 +00:00
|
|
|
oldFiles[0]->GetName(leafName);
|
2010-08-27 15:49:06 +00:00
|
|
|
if (!leafName.IsEmpty()) {
|
|
|
|
filePicker->SetDefaultString(leafName);
|
|
|
|
}
|
|
|
|
}
|
2013-03-30 02:08:57 +00:00
|
|
|
|
2013-12-07 12:09:14 +00:00
|
|
|
rv = filePicker->Open(callback);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
mPickerRunning = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
2010-08-27 15:49:06 +00:00
|
|
|
}
|
|
|
|
|
2013-03-30 02:08:57 +00:00
|
|
|
HTMLInputElement::gUploadLastDir->FetchDirectoryAndDisplayPicker(doc, filePicker, callback);
|
2013-12-07 12:09:14 +00:00
|
|
|
mPickerRunning = true;
|
2013-03-30 02:08:57 +00:00
|
|
|
return NS_OK;
|
2010-08-27 15:49:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define CPS_PREF_NAME NS_LITERAL_STRING("browser.upload.lastDir")
|
|
|
|
|
2014-04-27 07:06:00 +00:00
|
|
|
NS_IMPL_ISUPPORTS(UploadLastDir, nsIObserver, nsISupportsWeakReference)
|
2010-08-27 15:49:06 +00:00
|
|
|
|
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::InitUploadLastDir() {
|
2010-08-27 15:49:06 +00:00
|
|
|
gUploadLastDir = new UploadLastDir();
|
|
|
|
NS_ADDREF(gUploadLastDir);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
|
|
mozilla::services::GetObserverService();
|
|
|
|
if (observerService && gUploadLastDir) {
|
2011-10-17 14:59:28 +00:00
|
|
|
observerService->AddObserver(gUploadLastDir, "browser:purge-session-history", true);
|
2010-08-27 15:49:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::DestroyUploadLastDir() {
|
2010-08-27 15:49:06 +00:00
|
|
|
NS_IF_RELEASE(gUploadLastDir);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2013-03-30 02:08:57 +00:00
|
|
|
UploadLastDir::FetchDirectoryAndDisplayPicker(nsIDocument* aDoc,
|
|
|
|
nsIFilePicker* aFilePicker,
|
|
|
|
nsIFilePickerShownCallback* aFpCallback)
|
2010-08-27 15:49:06 +00:00
|
|
|
{
|
2012-06-30 14:50:07 +00:00
|
|
|
NS_PRECONDITION(aDoc, "aDoc is null");
|
2013-03-30 02:08:57 +00:00
|
|
|
NS_PRECONDITION(aFilePicker, "aFilePicker is null");
|
|
|
|
NS_PRECONDITION(aFpCallback, "aFpCallback is null");
|
2012-06-30 14:50:07 +00:00
|
|
|
|
|
|
|
nsIURI* docURI = aDoc->GetDocumentURI();
|
|
|
|
NS_PRECONDITION(docURI, "docURI is null");
|
|
|
|
|
2013-11-15 16:32:12 +00:00
|
|
|
nsCOMPtr<nsILoadContext> loadContext = aDoc->GetLoadContext();
|
2013-03-30 02:08:57 +00:00
|
|
|
nsCOMPtr<nsIContentPrefCallback2> prefCallback =
|
|
|
|
new UploadLastDir::ContentPrefCallback(aFilePicker, aFpCallback);
|
|
|
|
|
2014-11-09 19:26:14 +00:00
|
|
|
#ifdef MOZ_B2G
|
2014-11-10 07:10:30 +00:00
|
|
|
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
|
|
|
prefCallback->HandleCompletion(nsIContentPrefCallback2::COMPLETE_ERROR);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2014-11-09 19:26:14 +00:00
|
|
|
#endif
|
2014-11-10 07:10:30 +00:00
|
|
|
|
2013-03-30 02:08:57 +00:00
|
|
|
// Attempt to get the CPS, if it's not present we'll fallback to use the Desktop folder
|
|
|
|
nsCOMPtr<nsIContentPrefService2> contentPrefService =
|
2010-08-27 15:49:06 +00:00
|
|
|
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
|
2013-03-30 02:08:57 +00:00
|
|
|
if (!contentPrefService) {
|
|
|
|
prefCallback->HandleCompletion(nsIContentPrefCallback2::COMPLETE_ERROR);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2010-08-27 15:49:06 +00:00
|
|
|
|
2013-03-30 02:08:57 +00:00
|
|
|
nsAutoCString cstrSpec;
|
|
|
|
docURI->GetSpec(cstrSpec);
|
|
|
|
NS_ConvertUTF8toUTF16 spec(cstrSpec);
|
2010-08-27 15:49:06 +00:00
|
|
|
|
2013-03-30 02:08:57 +00:00
|
|
|
contentPrefService->GetByDomainAndName(spec, CPS_PREF_NAME, loadContext, prefCallback);
|
2010-08-27 15:49:06 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2013-08-22 09:43:26 +00:00
|
|
|
UploadLastDir::StoreLastUsedDirectory(nsIDocument* aDoc, nsIFile* aDir)
|
2010-08-27 15:49:06 +00:00
|
|
|
{
|
2012-06-30 14:50:07 +00:00
|
|
|
NS_PRECONDITION(aDoc, "aDoc is null");
|
2013-08-22 09:43:26 +00:00
|
|
|
if (!aDir) {
|
2013-03-19 17:49:16 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-11-09 19:26:14 +00:00
|
|
|
#ifdef MOZ_B2G
|
2014-11-10 07:10:30 +00:00
|
|
|
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2014-11-09 19:26:14 +00:00
|
|
|
#endif
|
2014-11-10 07:10:30 +00:00
|
|
|
|
2012-06-30 14:50:07 +00:00
|
|
|
nsCOMPtr<nsIURI> docURI = aDoc->GetDocumentURI();
|
|
|
|
NS_PRECONDITION(docURI, "docURI is null");
|
|
|
|
|
2010-08-27 15:49:06 +00:00
|
|
|
// Attempt to get the CPS, if it's not present we'll just return
|
2013-03-30 02:08:57 +00:00
|
|
|
nsCOMPtr<nsIContentPrefService2> contentPrefService =
|
2010-08-27 15:49:06 +00:00
|
|
|
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
|
|
|
|
if (!contentPrefService)
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
2013-03-30 02:08:57 +00:00
|
|
|
|
|
|
|
nsAutoCString cstrSpec;
|
|
|
|
docURI->GetSpec(cstrSpec);
|
|
|
|
NS_ConvertUTF8toUTF16 spec(cstrSpec);
|
2013-03-28 19:41:32 +00:00
|
|
|
|
2010-08-27 15:49:06 +00:00
|
|
|
// Find the parent of aFile, and store it
|
|
|
|
nsString unicodePath;
|
2013-08-22 09:43:26 +00:00
|
|
|
aDir->GetPath(unicodePath);
|
2010-08-27 15:49:06 +00:00
|
|
|
if (unicodePath.IsEmpty()) // nothing to do
|
|
|
|
return NS_OK;
|
|
|
|
nsCOMPtr<nsIWritableVariant> prefValue = do_CreateInstance(NS_VARIANT_CONTRACTID);
|
|
|
|
if (!prefValue)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
prefValue->SetAsAString(unicodePath);
|
2012-06-30 14:50:07 +00:00
|
|
|
|
2013-11-15 16:32:12 +00:00
|
|
|
nsCOMPtr<nsILoadContext> loadContext = aDoc->GetLoadContext();
|
2013-03-30 02:08:57 +00:00
|
|
|
return contentPrefService->Set(spec, CPS_PREF_NAME, prefValue, loadContext, nullptr);
|
2010-08-27 15:49:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2014-01-04 15:02:17 +00:00
|
|
|
UploadLastDir::Observe(nsISupports* aSubject, char const* aTopic, char16_t const* aData)
|
2010-08-27 15:49:06 +00:00
|
|
|
{
|
bug 679784: let nsIContentPrefService handle private browsing mode; r=ehsan
Manage private browsing mode in content pref service. CPS should be available
in private browsing mode, but should not store informations on disk, and should
clear all informations once the private session ends.
When setting a pref in private mode, it is stored in an in-memory hash table.
When getting a pref, it is retrieved from that hash table if available.
Otherwise, it is retrieved using the standard mechanism. When removing a pref,
it is retrieved from the hash table. The rationale is that in private mode,
it's ok to read a pref from normal database, but not ok to set it.
The in-memory hash table is cleared when leaving the private browsing mode.
When removing a set of preferences (with removeGroupedPrefs or
removePrefsByName), preferences are removed from the in-memory hashtable, *and*
from normal mode database. The rationale is that visiting a website may trigger
setting/getting/removing for a specific preference only. But removing many
prefs at once is the result of an action not associated with a website. For
example, user may wish to delete all its informations. In that case, user
probably expects to not have those informations restored once it leaves private
browsing mode.
2011-09-01 18:13:03 +00:00
|
|
|
if (strcmp(aTopic, "browser:purge-session-history") == 0) {
|
2013-03-30 02:08:57 +00:00
|
|
|
nsCOMPtr<nsIContentPrefService2> contentPrefService =
|
2010-08-27 15:49:06 +00:00
|
|
|
do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
|
|
|
|
if (contentPrefService)
|
2013-03-30 02:08:57 +00:00
|
|
|
contentPrefService->RemoveByName(CPS_PREF_NAME, nullptr, nullptr);
|
2010-08-27 15:49:06 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-05-16 03:54:46 +00:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
//Helper method
|
|
|
|
static nsresult FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget,
|
|
|
|
nsPresContext* aPresContext,
|
|
|
|
const nsAString& aEventType);
|
|
|
|
#endif
|
|
|
|
|
2002-02-08 18:23:47 +00:00
|
|
|
//
|
1998-09-23 17:16:51 +00:00
|
|
|
// construction, destruction
|
2002-02-08 18:23:47 +00:00
|
|
|
//
|
1998-09-23 17:16:51 +00:00
|
|
|
|
2014-06-20 02:01:40 +00:00
|
|
|
HTMLInputElement::HTMLInputElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
2013-03-28 19:41:32 +00:00
|
|
|
FromParser aFromParser)
|
2013-08-02 01:21:31 +00:00
|
|
|
: nsGenericHTMLFormElementWithState(aNodeInfo)
|
2011-11-16 07:50:19 +00:00
|
|
|
, mType(kInputDefaultType->value)
|
2014-06-06 07:25:02 +00:00
|
|
|
, mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown)
|
2011-11-16 07:50:19 +00:00
|
|
|
, mDisabledChanged(false)
|
|
|
|
, mValueChanged(false)
|
|
|
|
, mCheckedChanged(false)
|
|
|
|
, mChecked(false)
|
|
|
|
, mHandlingSelectEvent(false)
|
|
|
|
, mShouldInitChecked(false)
|
|
|
|
, mParserCreating(aFromParser != NOT_FROM_PARSER)
|
|
|
|
, mInInternalActivate(false)
|
|
|
|
, mCheckedIsToggled(false)
|
|
|
|
, mIndeterminate(false)
|
|
|
|
, mInhibitRestoration(aFromParser & FROM_PARSER_FRAGMENT)
|
|
|
|
, mCanShowValidUI(true)
|
|
|
|
, mCanShowInvalidUI(true)
|
2012-06-22 09:41:32 +00:00
|
|
|
, mHasRange(false)
|
2013-03-08 09:40:12 +00:00
|
|
|
, mIsDraggingRange(false)
|
2013-09-04 14:21:32 +00:00
|
|
|
, mProgressTimerIsActive(false)
|
2013-12-01 13:49:10 +00:00
|
|
|
, mNumberControlSpinnerIsSpinning(false)
|
2013-12-07 12:09:14 +00:00
|
|
|
, mNumberControlSpinnerSpinsUp(false)
|
|
|
|
, mPickerRunning(false)
|
2014-08-01 00:25:31 +00:00
|
|
|
, mSelectionCached(true)
|
2011-11-16 07:50:19 +00:00
|
|
|
{
|
2013-02-12 20:16:58 +00:00
|
|
|
// We are in a type=text so we now we currenty need a nsTextEditorState.
|
2010-04-21 20:17:41 +00:00
|
|
|
mInputData.mState = new nsTextEditorState(this);
|
2012-04-24 04:19:26 +00:00
|
|
|
|
2010-08-27 15:49:06 +00:00
|
|
|
if (!gUploadLastDir)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::InitUploadLastDir();
|
2011-06-01 01:46:57 +00:00
|
|
|
|
|
|
|
// Set up our default state. By default we're enabled (since we're
|
|
|
|
// a control type that can be disabled but not actually disabled
|
|
|
|
// right now), optional, and valid. We are NOT readwrite by default
|
|
|
|
// until someone calls UpdateEditableState on us, apparently! Also
|
|
|
|
// by default we don't have to show validity UI and so forth.
|
|
|
|
AddStatesSilently(NS_EVENT_STATE_ENABLED |
|
|
|
|
NS_EVENT_STATE_OPTIONAL |
|
|
|
|
NS_EVENT_STATE_VALID);
|
1998-09-01 01:27:08 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::~HTMLInputElement()
|
1998-09-01 01:27:08 +00:00
|
|
|
{
|
2011-08-22 09:14:13 +00:00
|
|
|
if (mFileList) {
|
|
|
|
mFileList->Disconnect();
|
|
|
|
}
|
2013-12-01 13:49:10 +00:00
|
|
|
if (mNumberControlSpinnerIsSpinning) {
|
|
|
|
StopNumberControlSpinnerSpin();
|
|
|
|
}
|
2006-06-01 18:35:21 +00:00
|
|
|
DestroyImageLoadingContent();
|
2010-04-21 20:17:41 +00:00
|
|
|
FreeData();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::FreeData()
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
if (!IsSingleLineTextControl(false)) {
|
2010-04-21 20:17:41 +00:00
|
|
|
nsMemory::Free(mInputData.mValue);
|
2012-07-30 14:20:58 +00:00
|
|
|
mInputData.mValue = nullptr;
|
2010-04-21 20:17:41 +00:00
|
|
|
} else {
|
2012-07-30 14:20:58 +00:00
|
|
|
UnbindFromFrame(nullptr);
|
2012-04-24 04:19:26 +00:00
|
|
|
delete mInputData.mState;
|
2012-07-30 14:20:58 +00:00
|
|
|
mInputData.mState = nullptr;
|
2010-04-21 20:17:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsTextEditorState*
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetEditorState() const
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
if (!IsSingleLineTextControl(false)) {
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2001-11-02 07:40:01 +00:00
|
|
|
}
|
2010-04-21 20:17:41 +00:00
|
|
|
|
2013-02-12 20:16:58 +00:00
|
|
|
MOZ_ASSERT(mInputData.mState, "Single line text controls need to have a state"
|
|
|
|
" associated with them");
|
2010-04-21 20:17:41 +00:00
|
|
|
|
|
|
|
return mInputData.mState;
|
1998-09-01 01:27:08 +00:00
|
|
|
}
|
|
|
|
|
2000-12-23 10:56:31 +00:00
|
|
|
|
1998-09-23 17:16:51 +00:00
|
|
|
// nsISupports
|
1998-09-01 01:27:08 +00:00
|
|
|
|
2013-08-02 01:29:05 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLInputElement)
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLInputElement,
|
2013-08-02 01:21:31 +00:00
|
|
|
nsGenericHTMLFormElementWithState)
|
2013-01-16 18:01:01 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
|
2012-11-15 07:32:40 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
|
2011-10-17 14:59:28 +00:00
|
|
|
if (tmp->IsSingleLineTextControl(false)) {
|
2012-04-24 04:19:26 +00:00
|
|
|
tmp->mInputData.mState->Traverse(cb);
|
2010-04-21 20:17:41 +00:00
|
|
|
}
|
2012-11-15 07:32:40 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFiles)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
|
2007-03-08 11:17:16 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement,
|
2013-08-02 01:21:31 +00:00
|
|
|
nsGenericHTMLFormElementWithState)
|
2013-01-16 18:01:01 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
|
2012-11-15 07:32:40 +00:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFiles)
|
2011-08-22 09:14:13 +00:00
|
|
|
if (tmp->mFileList) {
|
|
|
|
tmp->mFileList->Disconnect();
|
2012-07-30 14:20:58 +00:00
|
|
|
tmp->mFileList = nullptr;
|
2011-08-22 09:14:13 +00:00
|
|
|
}
|
2012-04-24 04:19:26 +00:00
|
|
|
if (tmp->IsSingleLineTextControl(false)) {
|
|
|
|
tmp->mInputData.mState->Unlink();
|
|
|
|
}
|
2011-06-21 21:12:50 +00:00
|
|
|
//XXX should unlink more?
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
2013-03-28 19:41:32 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMPL_ADDREF_INHERITED(HTMLInputElement, Element)
|
|
|
|
NS_IMPL_RELEASE_INHERITED(HTMLInputElement, Element)
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
// QueryInterface implementation for HTMLInputElement
|
|
|
|
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLInputElement)
|
2014-04-27 07:06:00 +00:00
|
|
|
NS_INTERFACE_TABLE_INHERITED(HTMLInputElement,
|
|
|
|
nsIDOMHTMLInputElement,
|
|
|
|
nsITextControlElement,
|
|
|
|
nsIPhonetic,
|
|
|
|
imgINotificationObserver,
|
|
|
|
nsIImageLoadingContent,
|
|
|
|
imgIOnloadBlocker,
|
|
|
|
nsIDOMNSEditableElement,
|
|
|
|
nsITimerCallback,
|
|
|
|
nsIConstraintValidation)
|
2013-08-07 20:23:08 +00:00
|
|
|
NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElementWithState)
|
1998-09-01 01:27:08 +00:00
|
|
|
|
2010-08-21 18:52:49 +00:00
|
|
|
// nsIConstraintValidation
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(HTMLInputElement)
|
1998-09-23 17:16:51 +00:00
|
|
|
|
1999-07-28 05:26:55 +00:00
|
|
|
// nsIDOMNode
|
1998-09-23 17:16:51 +00:00
|
|
|
|
1998-09-01 01:27:08 +00:00
|
|
|
nsresult
|
2014-06-20 02:01:40 +00:00
|
|
|
HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const
|
1998-09-01 01:27:08 +00:00
|
|
|
{
|
2012-07-30 14:20:58 +00:00
|
|
|
*aResult = nullptr;
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2014-06-20 02:01:40 +00:00
|
|
|
already_AddRefed<mozilla::dom::NodeInfo> ni = nsRefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
|
2014-03-15 19:00:17 +00:00
|
|
|
nsRefPtr<HTMLInputElement> it = new HTMLInputElement(ni, NOT_FROM_PARSER);
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
nsresult rv = const_cast<HTMLInputElement*>(this)->CopyInnerTo(it);
|
2005-09-11 17:15:08 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2013-05-03 17:17:09 +00:00
|
|
|
switch (GetValueMode()) {
|
|
|
|
case VALUE_MODE_VALUE:
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mValueChanged) {
|
2003-11-10 23:46:29 +00:00
|
|
|
// We don't have our default value anymore. Set our value on
|
|
|
|
// the clone.
|
|
|
|
nsAutoString value;
|
2011-03-09 18:25:20 +00:00
|
|
|
GetValueInternal(value);
|
2003-11-10 23:46:29 +00:00
|
|
|
// SetValueInternal handles setting the VALUE_CHANGED bit for us
|
2015-01-08 01:14:01 +00:00
|
|
|
rv = it->SetValueInternal(value, false, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2003-11-10 23:46:29 +00:00
|
|
|
}
|
|
|
|
break;
|
2013-05-03 17:17:09 +00:00
|
|
|
case VALUE_MODE_FILENAME:
|
2011-10-18 10:53:36 +00:00
|
|
|
if (it->OwnerDoc()->IsStaticDocument()) {
|
2010-09-05 18:00:05 +00:00
|
|
|
// We're going to be used in print preview. Since the doc is static
|
|
|
|
// we can just grab the pretty string and use it as wallpaper
|
|
|
|
GetDisplayFileName(it->mStaticDocFileList);
|
|
|
|
} else {
|
|
|
|
it->mFiles.Clear();
|
2013-08-16 10:11:29 +00:00
|
|
|
it->mFiles.AppendElements(mFiles);
|
2010-09-05 18:00:05 +00:00
|
|
|
}
|
2006-04-25 09:18:42 +00:00
|
|
|
break;
|
2013-05-03 17:17:09 +00:00
|
|
|
case VALUE_MODE_DEFAULT_ON:
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mCheckedChanged) {
|
2003-11-10 23:46:29 +00:00
|
|
|
// We no longer have our original checked state. Set our
|
|
|
|
// checked state on the clone.
|
2011-11-16 07:50:19 +00:00
|
|
|
it->DoSetChecked(mChecked, false, true);
|
2003-11-10 23:46:29 +00:00
|
|
|
}
|
|
|
|
break;
|
2013-05-03 17:17:09 +00:00
|
|
|
case VALUE_MODE_DEFAULT:
|
|
|
|
if (mType == NS_FORM_INPUT_IMAGE && it->OwnerDoc()->IsStaticDocument()) {
|
2009-12-11 04:02:13 +00:00
|
|
|
CreateStaticImageClone(it);
|
|
|
|
}
|
|
|
|
break;
|
2003-11-10 23:46:29 +00:00
|
|
|
}
|
2005-09-11 17:15:08 +00:00
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
it.forget(aResult);
|
2000-12-23 10:56:31 +00:00
|
|
|
return NS_OK;
|
1999-07-28 05:26:55 +00:00
|
|
|
}
|
|
|
|
|
2005-10-28 02:59:38 +00:00
|
|
|
nsresult
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|
|
|
const nsAttrValueOrString* aValue,
|
|
|
|
bool aNotify)
|
2002-03-07 20:53:40 +00:00
|
|
|
{
|
2005-10-28 02:59:38 +00:00
|
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
|
|
|
//
|
|
|
|
// When name or type changes, radio should be removed from radio group.
|
|
|
|
// (type changes are handled in the form itself currently)
|
|
|
|
// If the parser is not done creating the radio, we also should not do it.
|
|
|
|
//
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aName == nsGkAtoms::name ||
|
|
|
|
(aName == nsGkAtoms::type && !mForm)) &&
|
2005-10-28 02:59:38 +00:00
|
|
|
mType == NS_FORM_INPUT_RADIO &&
|
2011-11-16 07:50:19 +00:00
|
|
|
(mForm || !mParserCreating)) {
|
2010-11-11 12:34:27 +00:00
|
|
|
WillRemoveFromRadioGroup();
|
2006-12-26 17:47:52 +00:00
|
|
|
} else if (aNotify && aName == nsGkAtoms::src &&
|
2008-12-12 19:41:11 +00:00
|
|
|
mType == NS_FORM_INPUT_IMAGE) {
|
|
|
|
if (aValue) {
|
2014-08-19 21:49:38 +00:00
|
|
|
LoadImage(aValue->String(), true, aNotify, eImageLoadType_Normal);
|
2008-12-12 19:41:11 +00:00
|
|
|
} else {
|
|
|
|
// Null value means the attr got unset; drop the image
|
|
|
|
CancelImageRequests(aNotify);
|
|
|
|
}
|
2006-12-26 17:47:52 +00:00
|
|
|
} else if (aNotify && aName == nsGkAtoms::disabled) {
|
2011-11-16 07:50:19 +00:00
|
|
|
mDisabledChanged = true;
|
2012-11-21 10:13:57 +00:00
|
|
|
} else if (aName == nsGkAtoms::dir &&
|
|
|
|
AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
|
|
|
|
nsGkAtoms::_auto, eIgnoreCase)) {
|
|
|
|
SetDirectionIfAuto(false, aNotify);
|
2014-11-28 01:40:00 +00:00
|
|
|
} else if (mType == NS_FORM_INPUT_RADIO && aName == nsGkAtoms::required) {
|
|
|
|
nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
|
|
|
|
|
|
|
|
if (container &&
|
|
|
|
((aValue && !HasAttr(aNameSpaceID, aName)) ||
|
|
|
|
(!aValue && HasAttr(aNameSpaceID, aName)))) {
|
|
|
|
nsAutoString name;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
|
|
|
container->RadioRequiredWillChange(name, !!aValue);
|
|
|
|
}
|
2005-10-28 02:59:38 +00:00
|
|
|
}
|
2004-02-24 23:55:18 +00:00
|
|
|
}
|
|
|
|
|
2013-08-02 01:21:31 +00:00
|
|
|
return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
|
|
|
|
aValue, aNotify);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2005-10-28 02:59:38 +00:00
|
|
|
nsresult
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|
|
|
const nsAttrValue* aValue, bool aNotify)
|
2002-03-07 20:53:40 +00:00
|
|
|
{
|
2005-10-28 02:59:38 +00:00
|
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
|
|
|
//
|
|
|
|
// When name or type changes, radio should be added to radio group.
|
|
|
|
// (type changes are handled in the form itself currently)
|
|
|
|
// If the parser is not done creating the radio, we also should not do it.
|
|
|
|
//
|
2006-12-26 17:47:52 +00:00
|
|
|
if ((aName == nsGkAtoms::name ||
|
|
|
|
(aName == nsGkAtoms::type && !mForm)) &&
|
2005-10-28 02:59:38 +00:00
|
|
|
mType == NS_FORM_INPUT_RADIO &&
|
2011-11-16 07:50:19 +00:00
|
|
|
(mForm || !mParserCreating)) {
|
2005-10-28 02:59:38 +00:00
|
|
|
AddedToRadioGroup();
|
2011-02-25 18:16:04 +00:00
|
|
|
UpdateValueMissingValidityStateForRadio(false);
|
2002-03-31 10:14:01 +00:00
|
|
|
}
|
2002-12-17 13:29:39 +00:00
|
|
|
|
2010-07-21 00:11:19 +00:00
|
|
|
// If @value is changed and BF_VALUE_CHANGED is false, @value is the value
|
2010-09-08 17:42:35 +00:00
|
|
|
// of the element so, if the value of the element is different than @value,
|
|
|
|
// we have to re-set it. This is only the case when GetValueMode() returns
|
|
|
|
// VALUE_MODE_VALUE.
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aName == nsGkAtoms::value &&
|
2011-11-16 07:50:19 +00:00
|
|
|
!mValueChanged && GetValueMode() == VALUE_MODE_VALUE) {
|
2010-07-22 15:10:27 +00:00
|
|
|
SetDefaultValueAsValue();
|
2005-04-05 03:46:12 +00:00
|
|
|
}
|
2010-07-21 00:11:19 +00:00
|
|
|
|
2005-10-28 02:59:38 +00:00
|
|
|
//
|
|
|
|
// Checked must be set no matter what type of control it is, since
|
2011-11-16 07:50:19 +00:00
|
|
|
// mChecked must reflect the new value
|
|
|
|
if (aName == nsGkAtoms::checked && !mCheckedChanged) {
|
2007-07-12 20:05:45 +00:00
|
|
|
// Delay setting checked if the parser is creating this element (wait
|
|
|
|
// until everything is set)
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mParserCreating) {
|
|
|
|
mShouldInitChecked = true;
|
2007-07-12 20:05:45 +00:00
|
|
|
} else {
|
2011-11-16 07:50:19 +00:00
|
|
|
DoSetChecked(DefaultChecked(), true, true);
|
2011-10-17 14:59:28 +00:00
|
|
|
SetCheckedChanged(false);
|
2002-12-17 13:29:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aName == nsGkAtoms::type) {
|
2005-10-28 02:59:38 +00:00
|
|
|
if (!aValue) {
|
|
|
|
// We're now a text input. Note that we have to handle this manually,
|
|
|
|
// since removing an attribute (which is what happened, since aValue is
|
|
|
|
// null) doesn't call ParseAttribute.
|
2010-06-09 18:13:56 +00:00
|
|
|
HandleTypeChange(kInputDefaultType->value);
|
2005-10-28 02:59:38 +00:00
|
|
|
}
|
2010-09-10 05:08:56 +00:00
|
|
|
|
|
|
|
UpdateBarredFromConstraintValidation();
|
|
|
|
|
2005-10-28 02:59:38 +00:00
|
|
|
if (mType != NS_FORM_INPUT_IMAGE) {
|
|
|
|
// We're no longer an image input. Cancel our image requests, if we have
|
|
|
|
// any. Note that doing this when we already weren't an image is ok --
|
|
|
|
// just does nothing.
|
|
|
|
CancelImageRequests(aNotify);
|
|
|
|
} else if (aNotify) {
|
|
|
|
// We just got switched to be an image input; we should see
|
|
|
|
// whether we have an image to load;
|
|
|
|
nsAutoString src;
|
2006-12-26 17:47:52 +00:00
|
|
|
if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
|
2014-08-19 21:49:38 +00:00
|
|
|
LoadImage(src, false, aNotify, eImageLoadType_Normal);
|
2005-10-28 02:59:38 +00:00
|
|
|
}
|
2003-07-24 17:10:14 +00:00
|
|
|
}
|
2010-08-21 17:52:57 +00:00
|
|
|
}
|
2011-02-25 18:12:47 +00:00
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
|
|
|
|
aName == nsGkAtoms::readonly) {
|
|
|
|
UpdateValueMissingValidityState();
|
2010-09-10 05:08:56 +00:00
|
|
|
|
|
|
|
// This *has* to be called *after* validity has changed.
|
|
|
|
if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
|
|
|
|
UpdateBarredFromConstraintValidation();
|
|
|
|
}
|
2010-10-07 10:01:53 +00:00
|
|
|
} else if (MaxLengthApplies() && aName == nsGkAtoms::maxlength) {
|
2010-08-21 17:52:57 +00:00
|
|
|
UpdateTooLongValidityState();
|
|
|
|
} else if (aName == nsGkAtoms::pattern) {
|
|
|
|
UpdatePatternMismatchValidityState();
|
2011-07-05 22:31:23 +00:00
|
|
|
} else if (aName == nsGkAtoms::multiple) {
|
|
|
|
UpdateTypeMismatchValidityState();
|
2012-06-22 09:36:24 +00:00
|
|
|
} else if (aName == nsGkAtoms::max) {
|
2012-06-22 09:41:32 +00:00
|
|
|
UpdateHasRange();
|
2012-06-22 09:36:24 +00:00
|
|
|
UpdateRangeOverflowValidityState();
|
2013-02-16 12:35:57 +00:00
|
|
|
if (mType == NS_FORM_INPUT_RANGE) {
|
|
|
|
// The value may need to change when @max changes since the value may
|
|
|
|
// have been invalid and can now change to a valid value, or vice
|
|
|
|
// versa. For example, consider:
|
|
|
|
// <input type=range value=-1 max=1 step=3>. The valid range is 0 to 1
|
|
|
|
// while the nearest valid steps are -1 and 2 (the max value having
|
|
|
|
// prevented there being a valid step in range). Changing @max to/from
|
|
|
|
// 1 and a number greater than on equal to 3 should change whether we
|
|
|
|
// have a step mismatch or not.
|
|
|
|
// The value may also need to change between a value that results in
|
|
|
|
// a step mismatch and a value that results in overflow. For example,
|
|
|
|
// if @max in the example above were to change from 1 to -1.
|
|
|
|
nsAutoString value;
|
|
|
|
GetValue(value);
|
2015-01-08 01:14:01 +00:00
|
|
|
nsresult rv = SetValueInternal(value, false, false);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2013-02-16 12:35:57 +00:00
|
|
|
MOZ_ASSERT(!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
|
|
|
"HTML5 spec does not allow this");
|
|
|
|
}
|
2012-06-22 09:38:20 +00:00
|
|
|
} else if (aName == nsGkAtoms::min) {
|
2012-06-22 09:41:32 +00:00
|
|
|
UpdateHasRange();
|
2012-06-22 09:38:20 +00:00
|
|
|
UpdateRangeUnderflowValidityState();
|
2012-06-22 19:02:20 +00:00
|
|
|
UpdateStepMismatchValidityState();
|
2013-02-16 12:35:57 +00:00
|
|
|
if (mType == NS_FORM_INPUT_RANGE) {
|
|
|
|
// See @max comment
|
|
|
|
nsAutoString value;
|
|
|
|
GetValue(value);
|
2015-01-08 01:14:01 +00:00
|
|
|
nsresult rv = SetValueInternal(value, false, false);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2013-02-16 12:35:57 +00:00
|
|
|
MOZ_ASSERT(!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
|
|
|
"HTML5 spec does not allow this");
|
|
|
|
}
|
2012-06-22 19:02:20 +00:00
|
|
|
} else if (aName == nsGkAtoms::step) {
|
|
|
|
UpdateStepMismatchValidityState();
|
2013-02-16 12:35:57 +00:00
|
|
|
if (mType == NS_FORM_INPUT_RANGE) {
|
|
|
|
// See @max comment
|
|
|
|
nsAutoString value;
|
|
|
|
GetValue(value);
|
2015-01-08 01:14:01 +00:00
|
|
|
nsresult rv = SetValueInternal(value, false, false);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2013-02-16 12:35:57 +00:00
|
|
|
MOZ_ASSERT(!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
|
|
|
|
"HTML5 spec does not allow this");
|
|
|
|
}
|
2012-11-21 10:13:57 +00:00
|
|
|
} else if (aName == nsGkAtoms::dir &&
|
|
|
|
aValue && aValue->Equals(nsGkAtoms::_auto, eIgnoreCase)) {
|
|
|
|
SetDirectionIfAuto(true, aNotify);
|
2014-01-23 15:43:12 +00:00
|
|
|
} else if (aName == nsGkAtoms::lang) {
|
|
|
|
if (mType == NS_FORM_INPUT_NUMBER) {
|
|
|
|
// Update the value that is displayed to the user to the new locale:
|
|
|
|
nsAutoString value;
|
|
|
|
GetValueInternal(value);
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
|
|
|
numberControlFrame->SetValueOfAnonTextControl(value);
|
|
|
|
}
|
|
|
|
}
|
2014-06-06 07:25:02 +00:00
|
|
|
} else if (aName == nsGkAtoms::autocomplete) {
|
|
|
|
// Clear the cached @autocomplete attribute state.
|
|
|
|
mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
|
2010-08-21 17:52:57 +00:00
|
|
|
}
|
|
|
|
|
2011-06-01 01:46:57 +00:00
|
|
|
UpdateState(aNotify);
|
2002-12-16 23:49:16 +00:00
|
|
|
}
|
2005-10-28 02:59:38 +00:00
|
|
|
|
2013-08-02 01:21:31 +00:00
|
|
|
return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName,
|
|
|
|
aValue, aNotify);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2002-08-06 23:50:08 +00:00
|
|
|
// nsIDOMHTMLInputElement
|
|
|
|
|
1998-09-01 01:27:08 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
1998-09-01 01:27:08 +00:00
|
|
|
{
|
2013-08-02 01:21:31 +00:00
|
|
|
return nsGenericHTMLFormElementWithState::GetForm(aForm);
|
1998-09-01 01:27:08 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, DefaultValue, value)
|
|
|
|
NS_IMPL_BOOL_ATTR(HTMLInputElement, DefaultChecked, checked)
|
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, Accept, accept)
|
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, Align, align)
|
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, Alt, alt)
|
|
|
|
NS_IMPL_BOOL_ATTR(HTMLInputElement, Autofocus, autofocus)
|
|
|
|
//NS_IMPL_BOOL_ATTR(HTMLInputElement, Checked, checked)
|
|
|
|
NS_IMPL_BOOL_ATTR(HTMLInputElement, Disabled, disabled)
|
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, Max, max)
|
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, Min, min)
|
|
|
|
NS_IMPL_ACTION_ATTR(HTMLInputElement, FormAction, formaction)
|
|
|
|
NS_IMPL_ENUM_ATTR_DEFAULT_MISSING_INVALID_VALUES(HTMLInputElement, FormEnctype, formenctype,
|
2013-01-23 01:35:57 +00:00
|
|
|
"", kFormDefaultEnctype->tag)
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMPL_ENUM_ATTR_DEFAULT_MISSING_INVALID_VALUES(HTMLInputElement, FormMethod, formmethod,
|
2013-01-23 01:35:57 +00:00
|
|
|
"", kFormDefaultMethod->tag)
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMPL_BOOL_ATTR(HTMLInputElement, FormNoValidate, formnovalidate)
|
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, FormTarget, formtarget)
|
|
|
|
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLInputElement, InputMode, inputmode,
|
2012-08-17 09:53:44 +00:00
|
|
|
kInputDefaultInputmode->tag)
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMPL_BOOL_ATTR(HTMLInputElement, Multiple, multiple)
|
|
|
|
NS_IMPL_NON_NEGATIVE_INT_ATTR(HTMLInputElement, MaxLength, maxlength)
|
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, Name, name)
|
|
|
|
NS_IMPL_BOOL_ATTR(HTMLInputElement, ReadOnly, readonly)
|
|
|
|
NS_IMPL_BOOL_ATTR(HTMLInputElement, Required, required)
|
|
|
|
NS_IMPL_URI_ATTR(HTMLInputElement, Src, src)
|
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, Step, step)
|
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, UseMap, usemap)
|
|
|
|
//NS_IMPL_STRING_ATTR(HTMLInputElement, Value, value)
|
|
|
|
NS_IMPL_UINT_ATTR_NON_ZERO_DEFAULT_VALUE(HTMLInputElement, Size, size, DEFAULT_COLS)
|
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, Pattern, pattern)
|
|
|
|
NS_IMPL_STRING_ATTR(HTMLInputElement, Placeholder, placeholder)
|
|
|
|
NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLInputElement, Type, type,
|
2010-04-15 11:03:00 +00:00
|
|
|
kInputDefaultType->tag)
|
2003-11-10 05:52:29 +00:00
|
|
|
|
2014-06-06 07:25:02 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
HTMLInputElement::GetAutocomplete(nsAString& aValue)
|
|
|
|
{
|
2014-09-16 00:56:00 +00:00
|
|
|
if (!DoesAutocompleteApply()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-06-06 07:25:02 +00:00
|
|
|
aValue.Truncate(0);
|
|
|
|
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
|
|
|
|
|
2014-07-09 07:01:00 +00:00
|
|
|
mAutocompleteAttrState =
|
|
|
|
nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
|
|
|
|
mAutocompleteAttrState);
|
2014-06-06 07:25:02 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
HTMLInputElement::SetAutocomplete(const nsAString& aValue)
|
|
|
|
{
|
|
|
|
return SetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete, nullptr, aValue, true);
|
|
|
|
}
|
|
|
|
|
2014-07-09 07:01:00 +00:00
|
|
|
void
|
2014-09-16 00:56:00 +00:00
|
|
|
HTMLInputElement::GetAutocompleteInfo(Nullable<AutocompleteInfo>& aInfo)
|
2014-07-09 07:01:00 +00:00
|
|
|
{
|
2014-09-16 00:56:00 +00:00
|
|
|
if (!DoesAutocompleteApply()) {
|
|
|
|
aInfo.SetNull();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-09 07:01:00 +00:00
|
|
|
const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
|
|
|
|
mAutocompleteAttrState =
|
2014-09-16 00:56:00 +00:00
|
|
|
nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aInfo.SetValue(),
|
2014-07-09 07:01:00 +00:00
|
|
|
mAutocompleteAttrState);
|
|
|
|
}
|
|
|
|
|
2012-10-06 07:19:51 +00:00
|
|
|
int32_t
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::TabIndexDefault()
|
2012-10-06 07:19:51 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
uint32_t
|
|
|
|
HTMLInputElement::Height()
|
|
|
|
{
|
2013-08-23 23:31:39 +00:00
|
|
|
if (mType != NS_FORM_INPUT_IMAGE) {
|
|
|
|
return 0;
|
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
return GetWidthHeightForImage(mCurrentRequest).height;
|
|
|
|
}
|
|
|
|
|
2012-06-27 05:17:31 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetHeight(uint32_t* aHeight)
|
2012-06-27 05:17:31 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
*aHeight = Height();
|
2012-06-27 05:17:31 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetHeight(uint32_t aHeight)
|
2012-06-27 05:17:31 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
ErrorResult rv;
|
|
|
|
SetHeight(aHeight, rv);
|
|
|
|
return rv.ErrorCode();
|
2012-06-27 05:17:31 +00:00
|
|
|
}
|
|
|
|
|
2009-01-22 00:07:44 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetIndeterminate(bool* aValue)
|
2009-01-22 00:07:44 +00:00
|
|
|
{
|
2012-06-03 11:36:51 +00:00
|
|
|
*aValue = Indeterminate();
|
2009-01-22 00:07:44 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetIndeterminateInternal(bool aValue,
|
|
|
|
bool aShouldInvalidate)
|
2009-01-22 00:07:44 +00:00
|
|
|
{
|
2011-11-16 07:50:19 +00:00
|
|
|
mIndeterminate = aValue;
|
2009-01-22 00:07:44 +00:00
|
|
|
|
2009-02-11 01:19:37 +00:00
|
|
|
if (aShouldInvalidate) {
|
|
|
|
// Repaint the frame
|
|
|
|
nsIFrame* frame = GetPrimaryFrame();
|
|
|
|
if (frame)
|
2010-08-31 00:49:12 +00:00
|
|
|
frame->InvalidateFrameSubtree();
|
2009-02-11 01:19:37 +00:00
|
|
|
}
|
|
|
|
|
2011-06-01 01:46:57 +00:00
|
|
|
UpdateState(true);
|
2009-01-22 00:07:44 +00:00
|
|
|
}
|
|
|
|
|
2009-02-11 01:19:37 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetIndeterminate(bool aValue)
|
2009-02-11 01:19:37 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
SetIndeterminateInternal(aValue, true);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
HTMLInputElement::Width()
|
|
|
|
{
|
2013-08-23 23:31:39 +00:00
|
|
|
if (mType != NS_FORM_INPUT_IMAGE) {
|
|
|
|
return 0;
|
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
return GetWidthHeightForImage(mCurrentRequest).width;
|
2009-02-11 01:19:37 +00:00
|
|
|
}
|
|
|
|
|
2012-06-27 05:17:31 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetWidth(uint32_t* aWidth)
|
2012-06-27 05:17:31 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
*aWidth = Width();
|
2012-06-27 05:17:31 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetWidth(uint32_t aWidth)
|
2012-06-27 05:17:31 +00:00
|
|
|
{
|
2013-04-04 07:03:50 +00:00
|
|
|
ErrorResult rv;
|
|
|
|
SetWidth(aWidth, rv);
|
|
|
|
return rv.ErrorCode();
|
2012-06-27 05:17:31 +00:00
|
|
|
}
|
|
|
|
|
2011-03-09 18:25:20 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetValue(nsAString& aValue)
|
2011-03-09 18:25:20 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
GetValueInternal(aValue);
|
2012-07-05 16:15:46 +00:00
|
|
|
|
2013-01-31 23:05:48 +00:00
|
|
|
// Don't return non-sanitized value for types that are experimental on mobile.
|
|
|
|
if (IsExperimentalMobileType(mType)) {
|
2012-07-05 16:15:46 +00:00
|
|
|
SanitizeValue(aValue);
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
return NS_OK;
|
2011-03-09 18:25:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetValueInternal(nsAString& aValue) const
|
1998-10-30 20:41:01 +00:00
|
|
|
{
|
2011-06-22 10:41:00 +00:00
|
|
|
switch (GetValueMode()) {
|
|
|
|
case VALUE_MODE_VALUE:
|
2013-02-12 20:16:58 +00:00
|
|
|
if (IsSingleLineTextControl(false)) {
|
|
|
|
mInputData.mState->GetValue(aValue, true);
|
|
|
|
} else {
|
|
|
|
aValue.Assign(mInputData.mValue);
|
|
|
|
}
|
2011-06-22 10:41:00 +00:00
|
|
|
return NS_OK;
|
2001-02-09 23:45:41 +00:00
|
|
|
|
2011-06-22 10:41:00 +00:00
|
|
|
case VALUE_MODE_FILENAME:
|
2012-10-25 23:10:53 +00:00
|
|
|
if (nsContentUtils::IsCallerChrome()) {
|
2013-08-16 10:11:29 +00:00
|
|
|
if (!mFiles.IsEmpty()) {
|
2011-06-22 10:41:00 +00:00
|
|
|
return mFiles[0]->GetMozFullPath(aValue);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aValue.Truncate();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Just return the leaf name
|
2013-08-16 10:11:29 +00:00
|
|
|
if (mFiles.IsEmpty() || NS_FAILED(mFiles[0]->GetName(aValue))) {
|
2011-06-22 10:41:00 +00:00
|
|
|
aValue.Truncate();
|
|
|
|
}
|
2007-11-15 06:16:06 +00:00
|
|
|
}
|
2006-04-25 09:18:42 +00:00
|
|
|
|
2011-06-22 10:41:00 +00:00
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
case VALUE_MODE_DEFAULT:
|
|
|
|
// Treat defaultValue as value.
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue);
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
case VALUE_MODE_DEFAULT_ON:
|
|
|
|
// Treat default value as value and returns "on" if no value.
|
|
|
|
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue)) {
|
|
|
|
aValue.AssignLiteral("on");
|
|
|
|
}
|
|
|
|
return NS_OK;
|
1999-01-28 18:58:11 +00:00
|
|
|
}
|
2001-01-30 04:22:24 +00:00
|
|
|
|
2011-06-22 10:41:00 +00:00
|
|
|
// This return statement is required for some compilers.
|
2005-10-28 11:25:24 +00:00
|
|
|
return NS_OK;
|
1998-10-30 20:41:01 +00:00
|
|
|
}
|
|
|
|
|
2011-03-12 01:07:34 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsValueEmpty() const
|
2011-03-12 01:07:34 +00:00
|
|
|
{
|
|
|
|
nsAutoString value;
|
|
|
|
GetValueInternal(value);
|
|
|
|
|
|
|
|
return value.IsEmpty();
|
|
|
|
}
|
|
|
|
|
2013-09-06 06:40:45 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::ClearFiles(bool aSetValueChanged)
|
|
|
|
{
|
2014-10-08 16:15:23 +00:00
|
|
|
nsTArray<nsRefPtr<File>> files;
|
2013-09-06 06:40:45 +00:00
|
|
|
SetFiles(files, aSetValueChanged);
|
|
|
|
}
|
|
|
|
|
2014-01-23 15:43:12 +00:00
|
|
|
/* static */ Decimal
|
|
|
|
HTMLInputElement::StringToDecimal(const nsAString& aValue)
|
2013-05-05 23:23:18 +00:00
|
|
|
{
|
|
|
|
if (!IsASCII(aValue)) {
|
|
|
|
return Decimal::nan();
|
|
|
|
}
|
|
|
|
NS_LossyConvertUTF16toASCII asciiString(aValue);
|
|
|
|
std::string stdString = asciiString.get();
|
|
|
|
return Decimal::fromString(stdString);
|
|
|
|
}
|
|
|
|
|
2012-12-27 18:55:31 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::ConvertStringToNumber(nsAString& aValue,
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal& aResultValue) const
|
2012-12-27 18:55:31 +00:00
|
|
|
{
|
2013-01-22 18:22:33 +00:00
|
|
|
MOZ_ASSERT(DoesValueAsNumberApply(),
|
|
|
|
"ConvertStringToNumber only applies if .valueAsNumber applies");
|
|
|
|
|
2012-12-27 18:55:31 +00:00
|
|
|
switch (mType) {
|
|
|
|
case NS_FORM_INPUT_NUMBER:
|
2013-02-16 12:35:57 +00:00
|
|
|
case NS_FORM_INPUT_RANGE:
|
2012-12-27 18:55:31 +00:00
|
|
|
{
|
2013-05-05 23:23:18 +00:00
|
|
|
aResultValue = StringToDecimal(aValue);
|
|
|
|
if (!aResultValue.isFinite()) {
|
2012-12-27 18:55:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-01-07 15:20:53 +00:00
|
|
|
return true;
|
2012-12-27 18:55:31 +00:00
|
|
|
}
|
|
|
|
case NS_FORM_INPUT_DATE:
|
|
|
|
{
|
|
|
|
uint32_t year, month, day;
|
2013-01-11 15:02:58 +00:00
|
|
|
if (!GetValueAsDate(aValue, &year, &month, &day)) {
|
2012-12-27 18:55:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-05-02 03:44:11 +00:00
|
|
|
double date = JS::MakeDate(year, month - 1, day);
|
2013-05-01 20:55:13 +00:00
|
|
|
if (IsNaN(date)) {
|
2012-12-27 18:55:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
aResultValue = Decimal::fromDouble(date);
|
2013-01-07 15:20:53 +00:00
|
|
|
return true;
|
2012-12-27 18:55:31 +00:00
|
|
|
}
|
2013-01-22 18:22:33 +00:00
|
|
|
case NS_FORM_INPUT_TIME:
|
|
|
|
uint32_t milliseconds;
|
|
|
|
if (!ParseTime(aValue, &milliseconds)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-06-07 03:17:06 +00:00
|
|
|
aResultValue = Decimal(int32_t(milliseconds));
|
2013-01-22 18:22:33 +00:00
|
|
|
return true;
|
2012-12-27 18:55:31 +00:00
|
|
|
default:
|
2013-04-18 20:33:14 +00:00
|
|
|
MOZ_ASSERT(false, "Unrecognized input type");
|
2012-12-27 18:55:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal
|
|
|
|
HTMLInputElement::GetValueAsDecimal() const
|
2012-06-22 09:36:24 +00:00
|
|
|
{
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal decimalValue;
|
2012-06-22 09:36:24 +00:00
|
|
|
nsAutoString stringValue;
|
|
|
|
|
|
|
|
GetValueInternal(stringValue);
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
return !ConvertStringToNumber(stringValue, decimalValue) ? Decimal::nan()
|
|
|
|
: decimalValue;
|
2012-06-22 09:36:24 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::SetValue(const nsAString& aValue, ErrorResult& aRv)
|
2001-11-02 07:40:01 +00:00
|
|
|
{
|
2004-10-30 18:11:25 +00:00
|
|
|
// check security. Note that setting the value to the empty string is always
|
|
|
|
// OK and gives pages a way to clear a file input if necessary.
|
2006-04-25 09:18:42 +00:00
|
|
|
if (mType == NS_FORM_INPUT_FILE) {
|
|
|
|
if (!aValue.IsEmpty()) {
|
2012-10-25 23:10:53 +00:00
|
|
|
if (!nsContentUtils::IsCallerChrome()) {
|
|
|
|
// setting the value of a "FILE" input widget requires
|
|
|
|
// chrome privilege
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
|
|
|
return;
|
2006-04-25 09:18:42 +00:00
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
Sequence<nsString> list;
|
|
|
|
list.AppendElement(aValue);
|
|
|
|
MozSetFileNameArray(list);
|
|
|
|
return;
|
2009-10-27 18:14:34 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-11-23 23:45:53 +00:00
|
|
|
ClearFiles(true);
|
2002-12-16 23:49:16 +00:00
|
|
|
}
|
2006-04-25 09:18:42 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-16 05:49:41 +00:00
|
|
|
if (MayFireChangeOnBlur()) {
|
2012-09-05 12:39:33 +00:00
|
|
|
// If the value has been set by a script, we basically want to keep the
|
|
|
|
// current change event state. If the element is ready to fire a change
|
|
|
|
// event, we should keep it that way. Otherwise, we should make sure the
|
|
|
|
// element will not fire any event because of the script interaction.
|
|
|
|
//
|
|
|
|
// NOTE: this is currently quite expensive work (too much string
|
|
|
|
// manipulation). We should probably optimize that.
|
|
|
|
nsAutoString currentValue;
|
2014-01-30 10:45:46 +00:00
|
|
|
GetValue(currentValue);
|
2012-09-05 12:39:33 +00:00
|
|
|
|
2015-01-08 01:14:01 +00:00
|
|
|
nsresult rv = SetValueInternal(aValue, false, true);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return;
|
|
|
|
}
|
2012-09-05 12:39:33 +00:00
|
|
|
|
|
|
|
if (mFocusedValue.Equals(currentValue)) {
|
2014-01-30 10:45:46 +00:00
|
|
|
GetValue(mFocusedValue);
|
2012-09-05 12:39:33 +00:00
|
|
|
}
|
|
|
|
} else {
|
2015-01-08 01:14:01 +00:00
|
|
|
nsresult rv = SetValueInternal(aValue, false, true);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return;
|
|
|
|
}
|
2012-05-07 16:27:24 +00:00
|
|
|
}
|
2002-12-16 23:49:16 +00:00
|
|
|
}
|
2001-11-02 07:40:01 +00:00
|
|
|
}
|
|
|
|
|
2010-09-10 05:18:10 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetValue(const nsAString& aValue)
|
2010-09-10 05:18:10 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
ErrorResult rv;
|
|
|
|
SetValue(aValue, rv);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
2011-11-16 07:50:19 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
nsGenericHTMLElement*
|
|
|
|
HTMLInputElement::GetList() const
|
|
|
|
{
|
2010-09-10 05:18:10 +00:00
|
|
|
nsAutoString dataListId;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::list, dataListId);
|
2011-11-16 07:50:19 +00:00
|
|
|
if (dataListId.IsEmpty()) {
|
2013-03-28 19:41:32 +00:00
|
|
|
return nullptr;
|
2011-11-16 07:50:19 +00:00
|
|
|
}
|
2010-09-10 05:18:10 +00:00
|
|
|
|
2014-10-02 19:07:24 +00:00
|
|
|
//XXXsmaug How should this all work in case input element is in Shadow DOM.
|
|
|
|
nsIDocument* doc = GetUncomposedDoc();
|
2011-11-16 07:50:19 +00:00
|
|
|
if (!doc) {
|
2013-03-28 19:41:32 +00:00
|
|
|
return nullptr;
|
2011-11-16 07:50:19 +00:00
|
|
|
}
|
2010-09-10 05:18:10 +00:00
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
Element* element = doc->GetElementById(dataListId);
|
|
|
|
if (!element || !element->IsHTML(nsGkAtoms::datalist)) {
|
2013-03-28 19:41:32 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return static_cast<nsGenericHTMLElement*>(element);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
HTMLInputElement::GetList(nsIDOMHTMLElement** aValue)
|
|
|
|
{
|
|
|
|
*aValue = nullptr;
|
|
|
|
|
|
|
|
nsRefPtr<nsGenericHTMLElement> element = GetList();
|
|
|
|
if (!element) {
|
2011-11-16 07:50:19 +00:00
|
|
|
return NS_OK;
|
2010-09-10 05:18:10 +00:00
|
|
|
}
|
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
CallQueryInterface(element, aValue);
|
2010-09-10 05:18:10 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:33:47 +00:00
|
|
|
void
|
2013-05-05 23:23:18 +00:00
|
|
|
HTMLInputElement::SetValue(Decimal aValue)
|
2012-07-05 14:33:47 +00:00
|
|
|
{
|
2013-05-05 23:23:18 +00:00
|
|
|
MOZ_ASSERT(!aValue.isInfinity(), "aValue must not be Infinity!");
|
2012-12-28 12:48:41 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
if (aValue.isNaN()) {
|
2012-12-28 12:48:41 +00:00
|
|
|
SetValue(EmptyString());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:33:47 +00:00
|
|
|
nsAutoString value;
|
2012-12-22 14:46:19 +00:00
|
|
|
ConvertNumberToString(aValue, value);
|
|
|
|
SetValue(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2013-05-05 23:23:18 +00:00
|
|
|
HTMLInputElement::ConvertNumberToString(Decimal aValue,
|
2013-03-28 19:41:32 +00:00
|
|
|
nsAString& aResultString) const
|
2012-12-22 14:46:19 +00:00
|
|
|
{
|
2013-01-22 18:22:33 +00:00
|
|
|
MOZ_ASSERT(DoesValueAsNumberApply(),
|
|
|
|
"ConvertNumberToString is only implemented for types implementing .valueAsNumber");
|
2013-05-05 23:23:18 +00:00
|
|
|
MOZ_ASSERT(aValue.isFinite(),
|
2012-12-28 12:48:41 +00:00
|
|
|
"aValue must be a valid non-Infinite number.");
|
2012-12-22 14:46:19 +00:00
|
|
|
|
|
|
|
aResultString.Truncate();
|
|
|
|
|
2012-12-27 18:55:31 +00:00
|
|
|
switch (mType) {
|
|
|
|
case NS_FORM_INPUT_NUMBER:
|
2013-02-16 12:35:57 +00:00
|
|
|
case NS_FORM_INPUT_RANGE:
|
2013-05-05 23:23:18 +00:00
|
|
|
{
|
|
|
|
char buf[32];
|
|
|
|
bool ok = aValue.toString(buf, ArrayLength(buf));
|
|
|
|
aResultString.AssignASCII(buf);
|
|
|
|
MOZ_ASSERT(ok, "buf not big enough");
|
|
|
|
return ok;
|
|
|
|
}
|
2012-12-27 18:55:31 +00:00
|
|
|
case NS_FORM_INPUT_DATE:
|
2012-12-22 14:46:19 +00:00
|
|
|
{
|
2013-05-02 03:44:11 +00:00
|
|
|
// The specs (and our JS APIs) require |aValue| to be truncated.
|
2013-05-05 23:23:18 +00:00
|
|
|
aValue = aValue.floor();
|
2012-12-27 18:55:31 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
double year = JS::YearFromTime(aValue.toDouble());
|
|
|
|
double month = JS::MonthFromTime(aValue.toDouble());
|
|
|
|
double day = JS::DayFromTime(aValue.toDouble());
|
2013-01-07 15:20:53 +00:00
|
|
|
|
2013-05-01 20:55:13 +00:00
|
|
|
if (IsNaN(year) || IsNaN(month) || IsNaN(day)) {
|
2012-12-22 14:46:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-12-27 18:55:31 +00:00
|
|
|
|
2013-05-02 03:44:11 +00:00
|
|
|
aResultString.AppendPrintf("%04.0f-%02.0f-%02.0f", year,
|
|
|
|
month + 1, day);
|
2012-12-27 18:55:31 +00:00
|
|
|
|
2013-01-31 23:00:08 +00:00
|
|
|
return true;
|
2012-12-22 14:46:19 +00:00
|
|
|
}
|
2013-01-22 18:22:33 +00:00
|
|
|
case NS_FORM_INPUT_TIME:
|
|
|
|
{
|
|
|
|
// Per spec, we need to truncate |aValue| and we should only represent
|
|
|
|
// times inside a day [00:00, 24:00[, which means that we should do a
|
|
|
|
// modulo on |aValue| using the number of milliseconds in a day (86400000).
|
2014-06-07 03:17:06 +00:00
|
|
|
uint32_t value = NS_floorModulo(aValue.floor(), Decimal(86400000)).toDouble();
|
2013-01-22 18:22:33 +00:00
|
|
|
|
|
|
|
uint16_t milliseconds = value % 1000;
|
|
|
|
value /= 1000;
|
|
|
|
|
|
|
|
uint8_t seconds = value % 60;
|
|
|
|
value /= 60;
|
|
|
|
|
|
|
|
uint8_t minutes = value % 60;
|
|
|
|
value /= 60;
|
|
|
|
|
|
|
|
uint8_t hours = value;
|
|
|
|
|
|
|
|
if (milliseconds != 0) {
|
|
|
|
aResultString.AppendPrintf("%02d:%02d:%02d.%03d",
|
|
|
|
hours, minutes, seconds, milliseconds);
|
|
|
|
} else if (seconds != 0) {
|
|
|
|
aResultString.AppendPrintf("%02d:%02d:%02d",
|
|
|
|
hours, minutes, seconds);
|
|
|
|
} else {
|
|
|
|
aResultString.AppendPrintf("%02d:%02d", hours, minutes);
|
|
|
|
}
|
2013-01-31 23:00:08 +00:00
|
|
|
|
2013-01-22 18:22:33 +00:00
|
|
|
return true;
|
|
|
|
}
|
2012-12-22 14:46:19 +00:00
|
|
|
default:
|
2013-04-18 20:33:14 +00:00
|
|
|
MOZ_ASSERT(false, "Unrecognized input type");
|
2012-12-22 14:46:19 +00:00
|
|
|
return false;
|
2012-12-27 18:55:31 +00:00
|
|
|
}
|
2012-07-05 14:33:47 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 18:38:20 +00:00
|
|
|
|
|
|
|
Nullable<Date>
|
|
|
|
HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
|
2012-12-27 18:55:31 +00:00
|
|
|
{
|
2013-01-21 16:44:42 +00:00
|
|
|
if (mType != NS_FORM_INPUT_DATE && mType != NS_FORM_INPUT_TIME) {
|
2013-05-02 18:38:20 +00:00
|
|
|
return Nullable<Date>();
|
2012-12-27 18:55:31 +00:00
|
|
|
}
|
|
|
|
|
2013-01-21 16:44:42 +00:00
|
|
|
switch (mType) {
|
|
|
|
case NS_FORM_INPUT_DATE:
|
|
|
|
{
|
|
|
|
uint32_t year, month, day;
|
|
|
|
nsAutoString value;
|
|
|
|
GetValueInternal(value);
|
|
|
|
if (!GetValueAsDate(value, &year, &month, &day)) {
|
2013-05-02 18:38:20 +00:00
|
|
|
return Nullable<Date>();
|
2013-01-21 16:44:42 +00:00
|
|
|
}
|
2013-01-21 16:44:42 +00:00
|
|
|
|
2013-05-02 18:38:20 +00:00
|
|
|
return Nullable<Date>(Date(JS::MakeDate(year, month - 1, day)));
|
2013-01-21 16:44:42 +00:00
|
|
|
}
|
|
|
|
case NS_FORM_INPUT_TIME:
|
|
|
|
{
|
|
|
|
uint32_t millisecond;
|
|
|
|
nsAutoString value;
|
|
|
|
GetValueInternal(value);
|
|
|
|
if (!ParseTime(value, &millisecond)) {
|
2013-05-02 18:38:20 +00:00
|
|
|
return Nullable<Date>();
|
2013-01-21 16:44:42 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 18:38:20 +00:00
|
|
|
return Nullable<Date>(Date(millisecond));
|
2013-01-21 16:44:42 +00:00
|
|
|
}
|
2012-12-27 18:55:31 +00:00
|
|
|
}
|
|
|
|
|
2013-04-18 20:33:14 +00:00
|
|
|
MOZ_ASSERT(false, "Unrecognized input type");
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv.Throw(NS_ERROR_UNEXPECTED);
|
2013-05-02 18:38:20 +00:00
|
|
|
return Nullable<Date>();
|
2013-03-28 19:41:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-05-02 18:38:20 +00:00
|
|
|
HTMLInputElement::SetValueAsDate(Nullable<Date> aDate, ErrorResult& aRv)
|
2012-12-27 18:55:31 +00:00
|
|
|
{
|
2013-01-21 16:44:42 +00:00
|
|
|
if (mType != NS_FORM_INPUT_DATE && mType != NS_FORM_INPUT_TIME) {
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
2012-12-27 18:55:31 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 18:38:20 +00:00
|
|
|
if (aDate.IsNull() || aDate.Value().IsUndefined()) {
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv = SetValue(EmptyString());
|
|
|
|
return;
|
2013-01-07 15:20:18 +00:00
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
SetValue(Decimal::fromDouble(aDate.Value().TimeStamp()));
|
2012-12-27 18:55:31 +00:00
|
|
|
}
|
|
|
|
|
2012-07-05 10:13:41 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetValueAsNumber(double* aValueAsNumber)
|
2012-07-05 10:13:41 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
*aValueAsNumber = ValueAsNumber();
|
2012-07-05 10:13:41 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::SetValueAsNumber(double aValueAsNumber, ErrorResult& aRv)
|
2012-07-05 10:13:41 +00:00
|
|
|
{
|
2012-12-28 12:48:41 +00:00
|
|
|
// TODO: return TypeError when HTMLInputElement is converted to WebIDL, see
|
|
|
|
// bug 825197.
|
2013-05-01 20:55:13 +00:00
|
|
|
if (IsInfinite(aValueAsNumber)) {
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
|
|
return;
|
2012-12-28 12:48:41 +00:00
|
|
|
}
|
|
|
|
|
2012-07-05 10:13:41 +00:00
|
|
|
if (!DoesValueAsNumberApply()) {
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
return;
|
2012-07-05 10:13:41 +00:00
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
SetValue(Decimal::fromDouble(aValueAsNumber));
|
2013-03-28 19:41:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
HTMLInputElement::SetValueAsNumber(double aValueAsNumber)
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
|
|
|
SetValueAsNumber(aValueAsNumber, rv);
|
|
|
|
return rv.ErrorCode();
|
2012-07-05 10:13:41 +00:00
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetMinimum() const
|
2012-07-05 14:33:47 +00:00
|
|
|
{
|
2013-01-31 23:00:08 +00:00
|
|
|
MOZ_ASSERT(DoesValueAsNumberApply(),
|
2013-05-05 23:23:18 +00:00
|
|
|
"GetMinimum() should only be used for types that allow .valueAsNumber");
|
2012-07-06 12:40:18 +00:00
|
|
|
|
2013-02-16 12:35:57 +00:00
|
|
|
// Only type=range has a default minimum
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal defaultMinimum =
|
2014-06-07 03:17:06 +00:00
|
|
|
mType == NS_FORM_INPUT_RANGE ? Decimal(0) : Decimal::nan();
|
2013-01-25 23:51:57 +00:00
|
|
|
|
2012-07-05 14:33:47 +00:00
|
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::min)) {
|
2013-02-16 12:35:57 +00:00
|
|
|
return defaultMinimum;
|
2012-07-05 14:33:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString minStr;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr);
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal min;
|
2013-02-16 12:35:57 +00:00
|
|
|
return ConvertStringToNumber(minStr, min) ? min : defaultMinimum;
|
2012-07-06 12:40:18 +00:00
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetMaximum() const
|
2012-07-06 12:40:18 +00:00
|
|
|
{
|
2013-01-31 23:00:08 +00:00
|
|
|
MOZ_ASSERT(DoesValueAsNumberApply(),
|
2013-05-05 23:23:18 +00:00
|
|
|
"GetMaximum() should only be used for types that allow .valueAsNumber");
|
2012-07-06 12:40:18 +00:00
|
|
|
|
2013-02-16 12:35:57 +00:00
|
|
|
// Only type=range has a default maximum
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal defaultMaximum =
|
2014-06-07 03:17:06 +00:00
|
|
|
mType == NS_FORM_INPUT_RANGE ? Decimal(100) : Decimal::nan();
|
2013-01-25 23:51:57 +00:00
|
|
|
|
2012-07-06 12:40:18 +00:00
|
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::max)) {
|
2013-02-16 12:35:57 +00:00
|
|
|
return defaultMaximum;
|
2012-07-06 12:40:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString maxStr;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr);
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal max;
|
2013-02-16 12:35:57 +00:00
|
|
|
return ConvertStringToNumber(maxStr, max) ? max : defaultMaximum;
|
2012-07-06 12:40:18 +00:00
|
|
|
}
|
2012-07-05 14:33:47 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetStepBase() const
|
2012-07-06 12:40:18 +00:00
|
|
|
{
|
2013-01-25 23:51:57 +00:00
|
|
|
MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER ||
|
2013-02-06 22:56:49 +00:00
|
|
|
mType == NS_FORM_INPUT_DATE ||
|
2013-02-16 12:35:57 +00:00
|
|
|
mType == NS_FORM_INPUT_TIME ||
|
|
|
|
mType == NS_FORM_INPUT_RANGE,
|
2013-01-25 23:51:57 +00:00
|
|
|
"Check that kDefaultStepBase is correct for this new type");
|
2012-07-06 12:40:18 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal stepBase;
|
2012-11-26 11:35:26 +00:00
|
|
|
|
2013-01-25 23:51:57 +00:00
|
|
|
// Do NOT use GetMinimum here - the spec says to use "the min content
|
|
|
|
// attribute", not "the minimum".
|
|
|
|
nsAutoString minStr;
|
|
|
|
if (GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr) &&
|
|
|
|
ConvertStringToNumber(minStr, stepBase)) {
|
|
|
|
return stepBase;
|
|
|
|
}
|
2012-11-26 11:35:26 +00:00
|
|
|
|
2013-01-25 23:51:57 +00:00
|
|
|
// If @min is not a double, we should use @value.
|
|
|
|
nsAutoString valueStr;
|
2013-02-06 18:11:31 +00:00
|
|
|
if (GetAttr(kNameSpaceID_None, nsGkAtoms::value, valueStr) &&
|
|
|
|
ConvertStringToNumber(valueStr, stepBase)) {
|
|
|
|
return stepBase;
|
2012-11-26 11:35:26 +00:00
|
|
|
}
|
|
|
|
|
2013-01-25 23:51:57 +00:00
|
|
|
return kDefaultStepBase;
|
2012-07-05 14:33:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2014-01-15 17:22:16 +00:00
|
|
|
HTMLInputElement::GetValueIfStepped(int32_t aStep,
|
|
|
|
StepCallerType aCallerType,
|
|
|
|
Decimal* aNextStep)
|
2012-07-05 14:33:47 +00:00
|
|
|
{
|
|
|
|
if (!DoStepDownStepUpApply()) {
|
|
|
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
|
|
|
}
|
|
|
|
|
2014-11-26 09:54:32 +00:00
|
|
|
Decimal stepBase = GetStepBase();
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal step = GetStep();
|
2012-07-05 14:33:47 +00:00
|
|
|
if (step == kStepAny) {
|
2014-01-15 17:22:16 +00:00
|
|
|
if (aCallerType != CALLED_FOR_USER_EVENT) {
|
|
|
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
|
|
|
}
|
|
|
|
// Allow the spin buttons and up/down arrow keys to do something sensible:
|
|
|
|
step = GetDefaultStep();
|
2012-07-05 14:33:47 +00:00
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal minimum = GetMinimum();
|
|
|
|
Decimal maximum = GetMaximum();
|
2014-11-26 09:54:32 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
if (!maximum.isNaN()) {
|
2012-07-06 12:40:18 +00:00
|
|
|
// "max - (max - stepBase) % step" is the nearest valid value to max.
|
2014-11-26 09:54:32 +00:00
|
|
|
maximum = maximum - NS_floorModulo(maximum - stepBase, step);
|
|
|
|
if (!minimum.isNaN()) {
|
|
|
|
if (minimum > maximum) {
|
|
|
|
// Either the minimum was greater than the maximum prior to our
|
|
|
|
// adjustment to align maximum on a step, or else (if we adjusted
|
|
|
|
// maximum) there is no valid step between minimum and the unadjusted
|
|
|
|
// maximum.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
2012-07-05 14:33:47 +00:00
|
|
|
}
|
|
|
|
|
2014-11-26 09:54:32 +00:00
|
|
|
Decimal value = GetValueAsDecimal();
|
|
|
|
bool valueWasNaN = false;
|
|
|
|
if (value.isNaN()) {
|
|
|
|
value = Decimal(0);
|
|
|
|
valueWasNaN = true;
|
2012-07-05 14:33:47 +00:00
|
|
|
}
|
2014-11-26 09:54:32 +00:00
|
|
|
Decimal valueBeforeStepping = value;
|
|
|
|
|
|
|
|
Decimal deltaFromStep = NS_floorModulo(value - stepBase, step);
|
2012-07-05 14:33:47 +00:00
|
|
|
|
2014-11-26 09:54:32 +00:00
|
|
|
if (deltaFromStep != Decimal(0)) {
|
2012-07-05 14:33:47 +00:00
|
|
|
if (aStep > 0) {
|
2014-11-26 09:54:32 +00:00
|
|
|
value += step - deltaFromStep; // partial step
|
|
|
|
value += step * Decimal(aStep - 1); // then remaining steps
|
2012-07-05 14:33:47 +00:00
|
|
|
} else if (aStep < 0) {
|
2014-11-26 09:54:32 +00:00
|
|
|
value -= deltaFromStep; // partial step
|
|
|
|
value += step * Decimal(aStep + 1); // then remaining steps
|
2012-07-05 14:33:47 +00:00
|
|
|
}
|
2014-11-26 09:54:32 +00:00
|
|
|
} else {
|
|
|
|
value += step * Decimal(aStep);
|
2012-07-05 14:33:47 +00:00
|
|
|
}
|
|
|
|
|
2012-12-22 14:46:19 +00:00
|
|
|
// For date inputs, the value can hold a string that is not a day. We do not
|
|
|
|
// want to round it, as it might result in a step mismatch. Instead we want to
|
|
|
|
// clamp to the next valid value.
|
|
|
|
if (mType == NS_FORM_INPUT_DATE &&
|
2014-06-07 03:17:06 +00:00
|
|
|
NS_floorModulo(Decimal(value - GetStepBase()), GetStepScaleFactor()) != Decimal(0)) {
|
|
|
|
MOZ_ASSERT(GetStep() > Decimal(0));
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal validStep = EuclidLCM<Decimal>(GetStep().floor(),
|
|
|
|
GetStepScaleFactor().floor());
|
2012-12-22 14:46:19 +00:00
|
|
|
if (aStep > 0) {
|
|
|
|
value -= NS_floorModulo(value - GetStepBase(), validStep);
|
|
|
|
value += validStep;
|
|
|
|
} else if (aStep < 0) {
|
|
|
|
value -= NS_floorModulo(value - GetStepBase(), validStep);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-26 09:54:32 +00:00
|
|
|
if (value < minimum) {
|
2013-01-25 23:51:57 +00:00
|
|
|
value = minimum;
|
2014-11-26 09:54:32 +00:00
|
|
|
deltaFromStep = NS_floorModulo(value - stepBase, step);
|
|
|
|
if (deltaFromStep != Decimal(0)) {
|
|
|
|
value += step - deltaFromStep;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (value > maximum) {
|
2013-01-25 23:51:57 +00:00
|
|
|
value = maximum;
|
2014-11-26 09:54:32 +00:00
|
|
|
deltaFromStep = NS_floorModulo(value - stepBase, step);
|
|
|
|
if (deltaFromStep != Decimal(0)) {
|
|
|
|
value -= deltaFromStep;
|
|
|
|
}
|
2012-07-05 14:33:47 +00:00
|
|
|
}
|
|
|
|
|
2014-11-26 09:54:32 +00:00
|
|
|
if (!valueWasNaN && // value="", resulting in us using "0"
|
|
|
|
((aStep > 0 && value < valueBeforeStepping) ||
|
|
|
|
(aStep < 0 && value > valueBeforeStepping))) {
|
|
|
|
// We don't want step-up to effectively step down, or step-down to
|
|
|
|
// effectively step up, so return;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-07-05 14:33:47 +00:00
|
|
|
|
2014-11-26 09:54:32 +00:00
|
|
|
*aNextStep = value;
|
2012-07-05 14:33:47 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-12-05 16:20:33 +00:00
|
|
|
nsresult
|
|
|
|
HTMLInputElement::ApplyStep(int32_t aStep)
|
|
|
|
{
|
|
|
|
Decimal nextStep = Decimal::nan(); // unchanged if value will not change
|
|
|
|
|
2014-01-15 17:22:16 +00:00
|
|
|
nsresult rv = GetValueIfStepped(aStep, CALLED_FOR_SCRIPT, &nextStep);
|
2013-12-05 16:20:33 +00:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && nextStep.isFinite()) {
|
|
|
|
SetValue(nextStep);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2012-07-05 14:33:47 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::StepDown(int32_t n, uint8_t optional_argc)
|
2012-07-05 14:33:47 +00:00
|
|
|
{
|
|
|
|
return ApplyStep(optional_argc ? -n : -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::StepUp(int32_t n, uint8_t optional_argc)
|
2012-07-05 14:33:47 +00:00
|
|
|
{
|
|
|
|
return ApplyStep(optional_argc ? n : 1);
|
|
|
|
}
|
|
|
|
|
2013-09-04 10:30:36 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::FlushFrames()
|
|
|
|
{
|
2014-10-02 19:07:24 +00:00
|
|
|
if (GetComposedDoc()) {
|
|
|
|
GetComposedDoc()->FlushPendingNotifications(Flush_Frames);
|
2013-09-04 10:30:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::MozGetFileNameArray(nsTArray< nsString >& aArray)
|
|
|
|
{
|
2013-08-16 10:11:29 +00:00
|
|
|
for (uint32_t i = 0; i < mFiles.Length(); i++) {
|
2013-03-28 19:41:32 +00:00
|
|
|
nsString str;
|
|
|
|
mFiles[i]->GetMozFullPathInternal(str);
|
|
|
|
aArray.AppendElement(str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2014-01-04 15:02:17 +00:00
|
|
|
HTMLInputElement::MozGetFileNameArray(uint32_t* aLength, char16_t*** aFileNames)
|
2009-10-25 04:13:30 +00:00
|
|
|
{
|
2012-10-25 23:10:53 +00:00
|
|
|
if (!nsContentUtils::IsCallerChrome()) {
|
2009-10-25 04:13:30 +00:00
|
|
|
// Since this function returns full paths it's important that normal pages
|
|
|
|
// can't call it.
|
|
|
|
return NS_ERROR_DOM_SECURITY_ERR;
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTArray<nsString> array;
|
|
|
|
MozGetFileNameArray(array);
|
|
|
|
|
|
|
|
*aLength = array.Length();
|
2014-01-04 15:02:17 +00:00
|
|
|
char16_t** ret =
|
|
|
|
static_cast<char16_t**>(NS_Alloc(*aLength * sizeof(char16_t*)));
|
2011-11-16 07:50:19 +00:00
|
|
|
if (!ret) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
for (uint32_t i = 0; i < *aLength; ++i) {
|
|
|
|
ret[i] = NS_strdup(array[i].get());
|
2009-10-25 04:13:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*aFileNames = ret;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-01-27 00:22:59 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles)
|
|
|
|
{
|
|
|
|
nsTArray<nsRefPtr<File>> files;
|
|
|
|
for (uint32_t i = 0; i < aFiles.Length(); ++i) {
|
|
|
|
files.AppendElement(aFiles[i]);
|
|
|
|
}
|
|
|
|
SetFiles(files, true);
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::MozSetFileNameArray(const Sequence< nsString >& aFileNames)
|
2009-10-25 04:13:30 +00:00
|
|
|
{
|
2014-10-08 16:15:23 +00:00
|
|
|
nsTArray<nsRefPtr<File>> files;
|
2013-03-28 19:41:32 +00:00
|
|
|
for (uint32_t i = 0; i < aFileNames.Length(); ++i) {
|
2010-09-05 18:00:05 +00:00
|
|
|
nsCOMPtr<nsIFile> file;
|
2013-03-28 19:41:32 +00:00
|
|
|
|
|
|
|
if (StringBeginsWith(aFileNames[i], NS_LITERAL_STRING("file:"),
|
2010-09-05 18:00:05 +00:00
|
|
|
nsASCIICaseInsensitiveStringComparator())) {
|
|
|
|
// Converts the URL string into the corresponding nsIFile if possible
|
|
|
|
// A local file will be created if the URL string begins with file://
|
|
|
|
NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(aFileNames[i]),
|
|
|
|
getter_AddRefs(file));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!file) {
|
|
|
|
// this is no "file://", try as local file
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_NewLocalFile(aFileNames[i], false, getter_AddRefs(file));
|
2010-09-05 18:00:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (file) {
|
2014-10-08 16:15:22 +00:00
|
|
|
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
2014-10-08 16:15:23 +00:00
|
|
|
nsRefPtr<File> domFile = File::CreateFromFile(global, file);
|
2013-08-16 10:11:29 +00:00
|
|
|
files.AppendElement(domFile);
|
2010-09-05 18:00:05 +00:00
|
|
|
} else {
|
|
|
|
continue; // Not much we can do if the file doesn't exist
|
|
|
|
}
|
|
|
|
|
2009-10-25 04:13:30 +00:00
|
|
|
}
|
|
|
|
|
2010-11-23 23:45:53 +00:00
|
|
|
SetFiles(files, true);
|
2013-03-28 19:41:32 +00:00
|
|
|
}
|
2009-10-25 04:13:30 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMETHODIMP
|
2014-01-04 15:02:17 +00:00
|
|
|
HTMLInputElement::MozSetFileNameArray(const char16_t** aFileNames, uint32_t aLength)
|
2013-03-28 19:41:32 +00:00
|
|
|
{
|
|
|
|
if (!nsContentUtils::IsCallerChrome()) {
|
|
|
|
// setting the value of a "FILE" input widget requires chrome privilege
|
|
|
|
return NS_ERROR_DOM_SECURITY_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sequence<nsString> list;
|
|
|
|
for (uint32_t i = 0; i < aLength; ++i) {
|
|
|
|
list.AppendElement(nsDependentString(aFileNames[i]));
|
|
|
|
}
|
|
|
|
|
|
|
|
MozSetFileNameArray(list);
|
2009-10-25 04:13:30 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
bool
|
|
|
|
HTMLInputElement::MozIsTextField(bool aExcludePassword)
|
2010-05-12 07:17:07 +00:00
|
|
|
{
|
2013-09-04 10:30:36 +00:00
|
|
|
// TODO: temporary until bug 773205 is fixed.
|
2013-01-31 23:01:50 +00:00
|
|
|
if (IsExperimentalMobileType(mType)) {
|
2013-03-28 19:41:32 +00:00
|
|
|
return false;
|
2012-06-10 20:23:17 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
return IsSingleLineTextControl(aExcludePassword);
|
|
|
|
}
|
2010-05-12 07:17:07 +00:00
|
|
|
|
2013-11-20 09:32:45 +00:00
|
|
|
HTMLInputElement*
|
|
|
|
HTMLInputElement::GetOwnerNumberControl()
|
|
|
|
{
|
|
|
|
if (IsInNativeAnonymousSubtree() &&
|
|
|
|
mType == NS_FORM_INPUT_TEXT &&
|
|
|
|
GetParent() && GetParent()->GetParent()) {
|
|
|
|
HTMLInputElement* grandparent =
|
|
|
|
HTMLInputElement::FromContentOrNull(GetParent()->GetParent());
|
|
|
|
if (grandparent && grandparent->mType == NS_FORM_INPUT_NUMBER) {
|
|
|
|
return grandparent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
HTMLInputElement::MozIsTextField(bool aExcludePassword, bool* aResult)
|
|
|
|
{
|
|
|
|
*aResult = MozIsTextField(aExcludePassword);
|
2010-05-12 07:17:07 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetUserInput(const nsAString& aValue)
|
2007-10-02 16:56:07 +00:00
|
|
|
{
|
2012-10-25 23:10:54 +00:00
|
|
|
if (!nsContentUtils::IsCallerChrome()) {
|
2007-10-02 16:56:07 +00:00
|
|
|
return NS_ERROR_DOM_SECURITY_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mType == NS_FORM_INPUT_FILE)
|
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
Sequence<nsString> list;
|
|
|
|
list.AppendElement(aValue);
|
|
|
|
MozSetFileNameArray(list);
|
|
|
|
return NS_OK;
|
2007-10-02 16:56:07 +00:00
|
|
|
} else {
|
2015-01-08 01:14:01 +00:00
|
|
|
nsresult rv = SetValueInternal(aValue, true, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-10-02 16:56:07 +00:00
|
|
|
}
|
2011-01-21 23:06:27 +00:00
|
|
|
|
2014-10-07 08:54:51 +00:00
|
|
|
nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
|
|
|
|
static_cast<nsIDOMHTMLInputElement*>(this),
|
|
|
|
NS_LITERAL_STRING("input"), true,
|
|
|
|
true);
|
|
|
|
|
|
|
|
// If this element is not currently focused, it won't receive a change event for this
|
|
|
|
// update through the normal channels. So fire a change event immediately, instead.
|
|
|
|
if (!ShouldBlur(this)) {
|
|
|
|
FireChangeEventIfNeeded();
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
2007-10-02 16:56:07 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
nsIEditor*
|
|
|
|
HTMLInputElement::GetEditor()
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-04-21 20:17:41 +00:00
|
|
|
if (state) {
|
|
|
|
return state->GetEditor();
|
2010-06-05 20:17:42 +00:00
|
|
|
}
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2010-04-21 20:17:41 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMETHODIMP_(nsIEditor*)
|
|
|
|
HTMLInputElement::GetTextEditor()
|
|
|
|
{
|
|
|
|
return GetEditor();
|
|
|
|
}
|
|
|
|
|
2010-04-21 20:17:41 +00:00
|
|
|
NS_IMETHODIMP_(nsISelectionController*)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetSelectionController()
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-04-21 20:17:41 +00:00
|
|
|
if (state) {
|
|
|
|
return state->GetSelectionController();
|
2010-06-05 20:17:42 +00:00
|
|
|
}
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2010-04-21 20:17:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsFrameSelection*
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetConstFrameSelection()
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-04-21 20:17:41 +00:00
|
|
|
if (state) {
|
|
|
|
return state->GetConstFrameSelection();
|
2010-06-05 20:17:42 +00:00
|
|
|
}
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2010-04-21 20:17:41 +00:00
|
|
|
}
|
|
|
|
|
2001-11-19 10:35:52 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::BindToFrame(nsTextControlFrame* aFrame)
|
2001-11-19 10:35:52 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-04-21 20:17:41 +00:00
|
|
|
if (state) {
|
|
|
|
return state->BindToFrame(aFrame);
|
2010-06-05 20:17:42 +00:00
|
|
|
}
|
2010-04-21 20:17:41 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(void)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UnbindFromFrame(nsTextControlFrame* aFrame)
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-07-22 00:59:25 +00:00
|
|
|
if (state && aFrame) {
|
2010-04-21 20:17:41 +00:00
|
|
|
state->UnbindFromFrame(aFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::CreateEditor()
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-04-21 20:17:41 +00:00
|
|
|
if (state) {
|
|
|
|
return state->PrepareEditor();
|
2010-06-05 20:17:42 +00:00
|
|
|
}
|
2010-04-21 20:17:41 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(nsIContent*)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetRootEditorNode()
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-04-21 20:17:41 +00:00
|
|
|
if (state) {
|
|
|
|
return state->GetRootNode();
|
2010-06-05 20:17:42 +00:00
|
|
|
}
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2010-04-21 20:17:41 +00:00
|
|
|
}
|
|
|
|
|
2013-12-03 14:40:12 +00:00
|
|
|
NS_IMETHODIMP_(Element*)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::CreatePlaceholderNode()
|
2010-10-19 13:11:07 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-10-19 13:11:07 +00:00
|
|
|
if (state) {
|
2012-07-30 14:20:58 +00:00
|
|
|
NS_ENSURE_SUCCESS(state->CreatePlaceholderNode(), nullptr);
|
2010-10-19 13:11:07 +00:00
|
|
|
return state->GetPlaceholderNode();
|
|
|
|
}
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2010-10-19 13:11:07 +00:00
|
|
|
}
|
|
|
|
|
2013-12-03 14:40:12 +00:00
|
|
|
NS_IMETHODIMP_(Element*)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetPlaceholderNode()
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-04-21 20:17:41 +00:00
|
|
|
if (state) {
|
|
|
|
return state->GetPlaceholderNode();
|
2010-06-05 20:17:42 +00:00
|
|
|
}
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2010-04-21 20:17:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(void)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdatePlaceholderVisibility(bool aNotify)
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-04-21 20:17:41 +00:00
|
|
|
if (state) {
|
2012-11-09 10:31:34 +00:00
|
|
|
state->UpdatePlaceholderVisibility(aNotify);
|
2002-12-16 23:49:16 +00:00
|
|
|
}
|
2001-11-19 10:35:52 +00:00
|
|
|
}
|
|
|
|
|
2012-11-09 10:22:29 +00:00
|
|
|
NS_IMETHODIMP_(bool)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetPlaceholderVisibility()
|
2012-11-09 10:22:29 +00:00
|
|
|
{
|
|
|
|
nsTextEditorState* state = GetEditorState();
|
|
|
|
if (!state) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return state->GetPlaceholderVisibility();
|
|
|
|
}
|
|
|
|
|
2006-04-25 09:18:42 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
|
2006-04-25 09:18:42 +00:00
|
|
|
{
|
2011-10-18 10:53:36 +00:00
|
|
|
if (OwnerDoc()->IsStaticDocument()) {
|
2010-09-05 18:00:05 +00:00
|
|
|
aValue = mStaticDocFileList;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-16 10:11:29 +00:00
|
|
|
if (mFiles.Length() == 1) {
|
2013-02-07 13:58:05 +00:00
|
|
|
mFiles[0]->GetName(aValue);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsXPIDLString value;
|
|
|
|
|
2013-08-16 10:11:29 +00:00
|
|
|
if (mFiles.IsEmpty()) {
|
2013-02-07 13:58:05 +00:00
|
|
|
if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
|
|
|
|
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
|
|
|
"NoFilesSelected", value);
|
|
|
|
} else {
|
|
|
|
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
|
|
|
"NoFileSelected", value);
|
2009-10-25 04:13:30 +00:00
|
|
|
}
|
2013-02-07 13:58:05 +00:00
|
|
|
} else {
|
|
|
|
nsString count;
|
2014-05-09 01:03:35 +00:00
|
|
|
count.AppendInt(int(mFiles.Length()));
|
2013-02-07 13:58:05 +00:00
|
|
|
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t* params[] = { count.get() };
|
2013-02-07 13:58:05 +00:00
|
|
|
nsContentUtils::FormatLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
|
|
|
"XFilesSelected", params, value);
|
2006-04-25 09:18:42 +00:00
|
|
|
}
|
2013-02-07 13:58:05 +00:00
|
|
|
|
|
|
|
aValue = value;
|
2006-04-25 09:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-10-08 16:15:23 +00:00
|
|
|
HTMLInputElement::SetFiles(const nsTArray<nsRefPtr<File>>& aFiles,
|
2013-03-28 19:41:32 +00:00
|
|
|
bool aSetValueChanged)
|
2006-04-25 09:18:42 +00:00
|
|
|
{
|
2010-09-05 18:00:05 +00:00
|
|
|
mFiles.Clear();
|
2013-08-16 10:11:29 +00:00
|
|
|
mFiles.AppendElements(aFiles);
|
2010-09-05 18:00:05 +00:00
|
|
|
|
2011-06-01 06:06:38 +00:00
|
|
|
AfterSetFiles(aSetValueChanged);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
|
|
|
|
bool aSetValueChanged)
|
2011-06-01 06:06:38 +00:00
|
|
|
{
|
2014-10-08 16:15:23 +00:00
|
|
|
nsRefPtr<FileList> files = static_cast<FileList*>(aFiles);
|
2011-06-01 06:06:38 +00:00
|
|
|
mFiles.Clear();
|
|
|
|
|
|
|
|
if (aFiles) {
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t listLength;
|
2011-06-01 06:06:38 +00:00
|
|
|
aFiles->GetLength(&listLength);
|
2012-08-22 15:56:38 +00:00
|
|
|
for (uint32_t i = 0; i < listLength; i++) {
|
2014-10-08 16:15:23 +00:00
|
|
|
nsRefPtr<File> file = files->Item(i);
|
2013-08-16 10:11:29 +00:00
|
|
|
mFiles.AppendElement(file);
|
2011-06-01 06:06:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AfterSetFiles(aSetValueChanged);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::AfterSetFiles(bool aSetValueChanged)
|
2011-06-01 06:06:38 +00:00
|
|
|
{
|
2007-07-14 04:46:09 +00:00
|
|
|
// No need to flush here, if there's no frame at this point we
|
|
|
|
// don't need to force creation of one just to tell it about this
|
|
|
|
// new value. We just want the display to update as needed.
|
2011-10-17 14:59:28 +00:00
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
|
2007-07-14 04:46:09 +00:00
|
|
|
if (formControlFrame) {
|
2009-10-25 04:13:30 +00:00
|
|
|
nsAutoString readableValue;
|
|
|
|
GetDisplayFileName(readableValue);
|
|
|
|
formControlFrame->SetFormProperty(nsGkAtoms::value, readableValue);
|
2007-07-14 04:46:09 +00:00
|
|
|
}
|
2007-07-25 04:29:47 +00:00
|
|
|
|
|
|
|
UpdateFileList();
|
2010-08-21 17:52:57 +00:00
|
|
|
|
2010-11-23 23:45:53 +00:00
|
|
|
if (aSetValueChanged) {
|
2011-10-17 14:59:28 +00:00
|
|
|
SetValueChanged(true);
|
2010-11-23 23:45:53 +00:00
|
|
|
}
|
|
|
|
|
2011-10-17 14:59:28 +00:00
|
|
|
UpdateAllValidityStates(true);
|
2006-04-25 09:18:42 +00:00
|
|
|
}
|
|
|
|
|
2012-05-24 13:12:19 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::FireChangeEventIfNeeded()
|
2012-05-24 13:12:19 +00:00
|
|
|
{
|
2014-01-30 10:45:46 +00:00
|
|
|
nsAutoString value;
|
|
|
|
GetValue(value);
|
2012-05-24 13:12:19 +00:00
|
|
|
|
2013-03-16 05:49:41 +00:00
|
|
|
if (!MayFireChangeOnBlur() || mFocusedValue.Equals(value)) {
|
2012-05-24 13:12:19 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dispatch the change event.
|
|
|
|
mFocusedValue = value;
|
|
|
|
nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
|
2013-03-28 19:41:32 +00:00
|
|
|
static_cast<nsIContent*>(this),
|
2012-05-24 13:12:19 +00:00
|
|
|
NS_LITERAL_STRING("change"), true,
|
|
|
|
false);
|
2012-05-07 16:27:24 +00:00
|
|
|
}
|
|
|
|
|
2014-10-08 16:15:23 +00:00
|
|
|
FileList*
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetFiles()
|
2007-07-25 04:29:47 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
if (mType != NS_FORM_INPUT_FILE) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mFileList) {
|
2014-10-08 16:15:23 +00:00
|
|
|
mFileList = new FileList(static_cast<nsIContent*>(this));
|
2013-03-28 19:41:32 +00:00
|
|
|
UpdateFileList();
|
|
|
|
}
|
|
|
|
|
|
|
|
return mFileList;
|
2007-07-25 04:29:47 +00:00
|
|
|
}
|
|
|
|
|
2013-08-22 09:43:26 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::OpenDirectoryPicker(ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
if (mType != NS_FORM_INPUT_FILE) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
}
|
|
|
|
InitFilePicker(FILE_PICKER_DIRECTORY);
|
|
|
|
}
|
|
|
|
|
2013-10-08 17:47:08 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::CancelDirectoryPickerScanIfRunning()
|
|
|
|
{
|
|
|
|
if (!mDirPickerFileListBuilderTask) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (mProgressTimer) {
|
|
|
|
mProgressTimerIsActive = false;
|
|
|
|
mProgressTimer->Cancel();
|
|
|
|
}
|
|
|
|
mDirPickerFileListBuilderTask->Cancel();
|
|
|
|
mDirPickerFileListBuilderTask = nullptr;
|
|
|
|
}
|
|
|
|
|
2013-09-04 14:21:32 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::StartProgressEventTimer()
|
|
|
|
{
|
|
|
|
if (!mProgressTimer) {
|
|
|
|
mProgressTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
|
|
|
}
|
|
|
|
if (mProgressTimer) {
|
|
|
|
mProgressTimerIsActive = true;
|
|
|
|
mProgressTimer->Cancel();
|
|
|
|
mProgressTimer->InitWithCallback(this, kProgressEventInterval,
|
|
|
|
nsITimer::TYPE_ONE_SHOT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// nsITimerCallback's only method
|
|
|
|
NS_IMETHODIMP
|
|
|
|
HTMLInputElement::Notify(nsITimer* aTimer)
|
|
|
|
{
|
|
|
|
if (mProgressTimer == aTimer) {
|
|
|
|
mProgressTimerIsActive = false;
|
|
|
|
MaybeDispatchProgressEvent(false);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Just in case some JS user wants to QI to nsITimerCallback and play with us...
|
|
|
|
NS_WARNING("Unexpected timer!");
|
|
|
|
return NS_ERROR_INVALID_POINTER;
|
|
|
|
}
|
|
|
|
|
2013-12-01 13:49:10 +00:00
|
|
|
/* static */ void
|
|
|
|
HTMLInputElement::HandleNumberControlSpin(void* aData)
|
|
|
|
{
|
|
|
|
HTMLInputElement* input = static_cast<HTMLInputElement*>(aData);
|
|
|
|
|
|
|
|
NS_ASSERTION(input->mNumberControlSpinnerIsSpinning,
|
|
|
|
"Should have called nsRepeatService::Stop()");
|
|
|
|
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(input->GetPrimaryFrame());
|
|
|
|
if (input->mType != NS_FORM_INPUT_NUMBER || !numberControlFrame) {
|
|
|
|
// Type has changed (and possibly our frame type hasn't been updated yet)
|
|
|
|
// or else we've lost our frame. Either way, stop the timer and don't do
|
|
|
|
// anything else.
|
|
|
|
input->StopNumberControlSpinnerSpin();
|
|
|
|
} else {
|
2013-12-05 16:20:33 +00:00
|
|
|
input->StepNumberControlForUserEvent(input->mNumberControlSpinnerSpinsUp ? 1 : -1);
|
2013-12-01 13:49:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-04 14:21:32 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::MaybeDispatchProgressEvent(bool aFinalProgress)
|
|
|
|
{
|
|
|
|
nsRefPtr<HTMLInputElement> kungFuDeathGrip;
|
|
|
|
|
|
|
|
if (aFinalProgress && mProgressTimerIsActive) {
|
|
|
|
// mProgressTimer may hold the last reference to us, so take another strong
|
|
|
|
// ref to make sure we don't die under Cancel() and leave this method
|
|
|
|
// running on deleted memory.
|
|
|
|
kungFuDeathGrip = this;
|
|
|
|
|
|
|
|
mProgressTimerIsActive = false;
|
|
|
|
mProgressTimer->Cancel();
|
|
|
|
}
|
|
|
|
|
2013-10-08 17:47:08 +00:00
|
|
|
uint32_t fileListLength = mDirPickerFileListBuilderTask->GetFileListLength();
|
|
|
|
|
2013-09-04 14:21:32 +00:00
|
|
|
if (mProgressTimerIsActive ||
|
2013-10-08 17:47:08 +00:00
|
|
|
fileListLength == mDirPickerFileListBuilderTask->mPreviousFileListLength) {
|
2013-09-04 14:21:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!aFinalProgress) {
|
|
|
|
StartProgressEventTimer();
|
|
|
|
}
|
|
|
|
|
2013-10-08 17:47:08 +00:00
|
|
|
mDirPickerFileListBuilderTask->mPreviousFileListLength = fileListLength;
|
2013-09-04 14:21:32 +00:00
|
|
|
|
|
|
|
DispatchProgressEvent(NS_LITERAL_STRING(PROGRESS_STR),
|
2013-10-08 17:47:08 +00:00
|
|
|
false,
|
|
|
|
mDirPickerFileListBuilderTask->mPreviousFileListLength,
|
2013-09-04 14:21:32 +00:00
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HTMLInputElement::DispatchProgressEvent(const nsAString& aType,
|
|
|
|
bool aLengthComputable,
|
|
|
|
uint64_t aLoaded, uint64_t aTotal)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aType.IsEmpty(), "missing event type");
|
|
|
|
|
2014-06-03 22:52:36 +00:00
|
|
|
ProgressEventInit init;
|
|
|
|
init.mBubbles = false;
|
|
|
|
init.mCancelable = true; // XXXkhuey why?
|
|
|
|
init.mLengthComputable = aLengthComputable;
|
|
|
|
init.mLoaded = aLoaded;
|
|
|
|
init.mTotal = (aTotal == UINT64_MAX) ? 0 : aTotal;
|
2013-09-04 14:21:32 +00:00
|
|
|
|
2014-06-03 22:52:36 +00:00
|
|
|
nsRefPtr<ProgressEvent> event =
|
|
|
|
ProgressEvent::Constructor(this, aType, init);
|
2013-09-04 14:21:32 +00:00
|
|
|
event->SetTrusted(true);
|
|
|
|
|
2013-10-08 17:47:49 +00:00
|
|
|
bool doDefaultAction;
|
2014-06-03 22:52:36 +00:00
|
|
|
nsresult rv = DispatchEvent(event, &doDefaultAction);
|
2013-10-08 17:47:49 +00:00
|
|
|
if (NS_SUCCEEDED(rv) && !doDefaultAction) {
|
|
|
|
CancelDirectoryPickerScanIfRunning();
|
|
|
|
}
|
2013-09-04 14:21:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-25 04:29:47 +00:00
|
|
|
nsresult
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateFileList()
|
2007-07-25 04:29:47 +00:00
|
|
|
{
|
|
|
|
if (mFileList) {
|
|
|
|
mFileList->Clear();
|
|
|
|
|
2014-10-08 16:15:23 +00:00
|
|
|
const nsTArray<nsRefPtr<File>>& files = GetFilesInternal();
|
2013-08-16 10:11:29 +00:00
|
|
|
for (uint32_t i = 0; i < files.Length(); ++i) {
|
2010-09-05 18:00:05 +00:00
|
|
|
if (!mFileList->Append(files[i])) {
|
|
|
|
return NS_ERROR_FAILURE;
|
2007-07-25 04:29:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2002-12-16 23:49:16 +00:00
|
|
|
nsresult
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetValueInternal(const nsAString& aValue,
|
|
|
|
bool aUserInput,
|
|
|
|
bool aSetValueChanged)
|
1998-10-30 20:41:01 +00:00
|
|
|
{
|
2011-06-22 10:41:00 +00:00
|
|
|
NS_PRECONDITION(GetValueMode() != VALUE_MODE_FILENAME,
|
2006-04-25 09:18:42 +00:00
|
|
|
"Don't call SetValueInternal for file inputs");
|
|
|
|
|
2011-06-22 10:41:00 +00:00
|
|
|
switch (GetValueMode()) {
|
|
|
|
case VALUE_MODE_VALUE:
|
|
|
|
{
|
|
|
|
// At the moment, only single line text control have to sanitize their value
|
|
|
|
// Because we have to create a new string for that, we should prevent doing
|
|
|
|
// it if it's useless.
|
|
|
|
nsAutoString value(aValue);
|
2010-07-21 00:11:19 +00:00
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
if (!mParserCreating) {
|
2011-06-22 10:41:00 +00:00
|
|
|
SanitizeValue(value);
|
|
|
|
}
|
2014-02-27 08:41:46 +00:00
|
|
|
// else DoneCreatingElement calls us again once mParserCreating is false
|
2010-07-21 00:11:19 +00:00
|
|
|
|
2011-06-22 10:41:00 +00:00
|
|
|
if (aSetValueChanged) {
|
2011-10-17 14:59:28 +00:00
|
|
|
SetValueChanged(true);
|
2011-06-22 10:41:00 +00:00
|
|
|
}
|
|
|
|
|
2013-02-12 20:16:58 +00:00
|
|
|
if (IsSingleLineTextControl(false)) {
|
2015-01-08 01:14:01 +00:00
|
|
|
if (!mInputData.mState->SetValue(value, aUserInput, aSetValueChanged)) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2014-01-30 12:54:12 +00:00
|
|
|
if (mType == NS_FORM_INPUT_EMAIL) {
|
|
|
|
UpdateAllValidityStates(mParserCreating);
|
|
|
|
}
|
2013-02-12 20:16:58 +00:00
|
|
|
} else {
|
2014-03-07 04:27:52 +00:00
|
|
|
nsMemory::Free(mInputData.mValue);
|
2013-02-12 20:16:58 +00:00
|
|
|
mInputData.mValue = ToNewUnicode(value);
|
|
|
|
if (aSetValueChanged) {
|
|
|
|
SetValueChanged(true);
|
|
|
|
}
|
2011-06-21 14:17:10 +00:00
|
|
|
if (mType == NS_FORM_INPUT_NUMBER) {
|
2014-02-12 17:13:32 +00:00
|
|
|
// This has to happen before OnValueChanged is called because that
|
|
|
|
// method needs the new value of our frame's anon text control.
|
2011-06-21 14:17:10 +00:00
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
2014-01-23 15:43:12 +00:00
|
|
|
numberControlFrame->SetValueOfAnonTextControl(value);
|
2011-06-21 14:17:10 +00:00
|
|
|
}
|
2014-10-13 11:48:33 +00:00
|
|
|
} else if (mType == NS_FORM_INPUT_RANGE) {
|
|
|
|
nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (frame) {
|
|
|
|
frame->UpdateForValueChange();
|
|
|
|
}
|
2011-06-21 14:17:10 +00:00
|
|
|
}
|
2014-02-27 08:41:46 +00:00
|
|
|
if (!mParserCreating) {
|
|
|
|
OnValueChanged(true);
|
|
|
|
}
|
|
|
|
// else DoneCreatingElement calls us again once mParserCreating is false
|
2013-02-12 20:16:58 +00:00
|
|
|
}
|
2011-06-22 10:41:00 +00:00
|
|
|
|
2013-07-09 22:25:27 +00:00
|
|
|
if (mType == NS_FORM_INPUT_COLOR) {
|
2014-02-28 19:52:42 +00:00
|
|
|
// Update color frame, to reflect color changes
|
|
|
|
nsColorControlFrame* colorControlFrame = do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (colorControlFrame) {
|
|
|
|
colorControlFrame->UpdateColor();
|
|
|
|
}
|
2013-07-09 22:25:27 +00:00
|
|
|
}
|
|
|
|
|
2011-06-22 10:41:00 +00:00
|
|
|
return NS_OK;
|
2010-08-25 04:39:10 +00:00
|
|
|
}
|
|
|
|
|
2011-06-22 10:41:00 +00:00
|
|
|
case VALUE_MODE_DEFAULT:
|
|
|
|
case VALUE_MODE_DEFAULT_ON:
|
|
|
|
// If the value of a hidden input was changed, we mark it changed so that we
|
|
|
|
// will know we need to save / restore the value. Yes, we are overloading
|
|
|
|
// the meaning of ValueChanged just a teensy bit to save a measly byte of
|
2013-03-28 19:41:32 +00:00
|
|
|
// storage space in HTMLInputElement. Yes, you are free to make a new flag,
|
2011-06-22 10:41:00 +00:00
|
|
|
// NEED_TO_SAVE_VALUE, at such time as mBitField becomes a 16-bit value.
|
|
|
|
if (mType == NS_FORM_INPUT_HIDDEN) {
|
2011-10-17 14:59:28 +00:00
|
|
|
SetValueChanged(true);
|
2011-06-22 10:41:00 +00:00
|
|
|
}
|
2002-06-12 06:35:11 +00:00
|
|
|
|
2011-06-22 10:41:00 +00:00
|
|
|
// Treat value == defaultValue for other input elements.
|
2013-08-02 01:21:31 +00:00
|
|
|
return nsGenericHTMLFormElementWithState::SetAttr(kNameSpaceID_None,
|
|
|
|
nsGkAtoms::value, aValue,
|
|
|
|
true);
|
2011-06-22 10:41:00 +00:00
|
|
|
|
|
|
|
case VALUE_MODE_FILENAME:
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
1999-03-03 02:54:25 +00:00
|
|
|
}
|
2000-01-14 09:28:54 +00:00
|
|
|
|
2011-06-22 10:41:00 +00:00
|
|
|
// This return statement is required for some compilers.
|
|
|
|
return NS_OK;
|
1998-10-30 20:41:01 +00:00
|
|
|
}
|
|
|
|
|
2001-11-05 06:50:21 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetValueChanged(bool aValueChanged)
|
2001-11-05 06:50:21 +00:00
|
|
|
{
|
2011-11-16 07:50:19 +00:00
|
|
|
bool valueChangedBefore = mValueChanged;
|
2010-11-23 23:49:50 +00:00
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
mValueChanged = aValueChanged;
|
2010-11-23 23:49:50 +00:00
|
|
|
|
|
|
|
if (valueChangedBefore != aValueChanged) {
|
2011-06-01 01:46:57 +00:00
|
|
|
UpdateState(true);
|
2010-11-23 23:49:50 +00:00
|
|
|
}
|
|
|
|
|
2001-11-05 06:50:21 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetChecked(bool* aChecked)
|
1998-10-30 20:41:01 +00:00
|
|
|
{
|
2012-06-03 11:36:51 +00:00
|
|
|
*aChecked = Checked();
|
2002-01-24 19:04:55 +00:00
|
|
|
return NS_OK;
|
1998-10-30 20:41:01 +00:00
|
|
|
}
|
|
|
|
|
2010-07-14 06:39:48 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetCheckedChanged(bool aCheckedChanged)
|
2006-02-08 05:56:13 +00:00
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
DoSetCheckedChanged(aCheckedChanged, true);
|
2006-02-08 05:56:13 +00:00
|
|
|
}
|
|
|
|
|
2010-07-14 06:39:48 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::DoSetCheckedChanged(bool aCheckedChanged,
|
|
|
|
bool aNotify)
|
2002-03-07 20:53:40 +00:00
|
|
|
{
|
|
|
|
if (mType == NS_FORM_INPUT_RADIO) {
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mCheckedChanged != aCheckedChanged) {
|
2011-04-11 18:31:00 +00:00
|
|
|
nsCOMPtr<nsIRadioVisitor> visitor =
|
|
|
|
new nsRadioSetCheckedChangedVisitor(aCheckedChanged);
|
2006-02-08 05:56:13 +00:00
|
|
|
VisitGroup(visitor, aNotify);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
} else {
|
2010-11-23 23:53:39 +00:00
|
|
|
SetCheckedChangedInternal(aCheckedChanged);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-14 06:39:48 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetCheckedChangedInternal(bool aCheckedChanged)
|
2002-03-07 20:53:40 +00:00
|
|
|
{
|
2011-11-16 07:50:19 +00:00
|
|
|
bool checkedChangedBefore = mCheckedChanged;
|
2010-11-23 23:49:50 +00:00
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
mCheckedChanged = aCheckedChanged;
|
2010-11-23 23:49:50 +00:00
|
|
|
|
2010-11-23 23:53:39 +00:00
|
|
|
// This method can't be called when we are not authorized to notify
|
|
|
|
// so we do not need a aNotify parameter.
|
|
|
|
if (checkedChangedBefore != aCheckedChanged) {
|
2011-06-01 01:46:57 +00:00
|
|
|
UpdateState(true);
|
2010-11-23 23:49:50 +00:00
|
|
|
}
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetChecked(bool aChecked)
|
2004-01-21 04:28:57 +00:00
|
|
|
{
|
2012-08-03 10:38:52 +00:00
|
|
|
DoSetChecked(aChecked, true, true);
|
|
|
|
return NS_OK;
|
2004-01-21 04:28:57 +00:00
|
|
|
}
|
|
|
|
|
2012-08-03 10:38:52 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::DoSetChecked(bool aChecked, bool aNotify,
|
|
|
|
bool aSetValueChanged)
|
2002-03-07 20:53:40 +00:00
|
|
|
{
|
|
|
|
// If the user or JS attempts to set checked, whether it actually changes the
|
|
|
|
// value or not, we say the value was changed so that defaultValue don't
|
|
|
|
// affect it no more.
|
2010-07-22 18:27:33 +00:00
|
|
|
if (aSetValueChanged) {
|
2011-10-17 14:59:28 +00:00
|
|
|
DoSetCheckedChanged(true, aNotify);
|
2010-07-22 18:27:33 +00:00
|
|
|
}
|
2002-03-07 20:53:40 +00:00
|
|
|
|
|
|
|
// Don't do anything if we're not changing whether it's checked (it would
|
|
|
|
// screw up state actually, especially when you are setting radio button to
|
|
|
|
// false)
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mChecked == aChecked) {
|
2012-08-03 10:38:52 +00:00
|
|
|
return;
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set checked
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mType != NS_FORM_INPUT_RADIO) {
|
2010-08-21 17:52:57 +00:00
|
|
|
SetCheckedInternal(aChecked, aNotify);
|
2012-08-03 10:38:52 +00:00
|
|
|
return;
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
// For radio button, we need to do some extra fun stuff
|
|
|
|
if (aChecked) {
|
2012-08-03 10:38:52 +00:00
|
|
|
RadioSetChecked(aNotify);
|
|
|
|
return;
|
2011-11-16 07:50:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsIRadioGroupContainer* container = GetRadioGroupContainer();
|
|
|
|
if (container) {
|
|
|
|
nsAutoString name;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
2012-07-30 14:20:58 +00:00
|
|
|
container->SetCurrentRadioButton(name, nullptr);
|
2011-11-16 07:50:19 +00:00
|
|
|
}
|
|
|
|
// SetCheckedInternal is going to ask all radios to update their
|
|
|
|
// validity state. We have to be sure the radio group container knows
|
|
|
|
// the currently selected radio.
|
|
|
|
SetCheckedInternal(false, aNotify);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2012-08-03 10:38:52 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::RadioSetChecked(bool aNotify)
|
1998-10-30 20:41:01 +00:00
|
|
|
{
|
2002-03-07 20:53:40 +00:00
|
|
|
// Find the selected radio button so we can deselect it
|
2010-08-18 18:30:41 +00:00
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> currentlySelected = GetSelectedRadioButton();
|
2002-03-07 20:53:40 +00:00
|
|
|
|
|
|
|
// Deselect the currently selected radio button
|
|
|
|
if (currentlySelected) {
|
2011-10-17 14:59:28 +00:00
|
|
|
// Pass true for the aNotify parameter since the currently selected
|
2004-01-21 04:28:57 +00:00
|
|
|
// button is already in the document.
|
2013-03-28 19:41:32 +00:00
|
|
|
static_cast<HTMLInputElement*>(currentlySelected.get())
|
2011-11-16 07:50:19 +00:00
|
|
|
->SetCheckedInternal(false, true);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2002-07-20 23:09:24 +00:00
|
|
|
// Let the group know that we are now the One True Radio Button
|
2011-05-04 12:49:59 +00:00
|
|
|
nsIRadioGroupContainer* container = GetRadioGroupContainer();
|
|
|
|
if (container) {
|
|
|
|
nsAutoString name;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
2012-08-03 10:38:52 +00:00
|
|
|
container->SetCurrentRadioButton(name, this);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
// SetCheckedInternal is going to ask all radios to update their
|
2013-03-28 19:41:32 +00:00
|
|
|
// validity state.
|
2012-08-03 10:38:52 +00:00
|
|
|
SetCheckedInternal(true, aNotify);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2011-05-04 12:49:59 +00:00
|
|
|
nsIRadioGroupContainer*
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetRadioGroupContainer() const
|
2002-07-20 23:09:24 +00:00
|
|
|
{
|
2011-05-04 12:49:59 +00:00
|
|
|
NS_ASSERTION(mType == NS_FORM_INPUT_RADIO,
|
|
|
|
"GetRadioGroupContainer should only be called when type='radio'");
|
|
|
|
|
|
|
|
nsAutoString name;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
|
|
|
|
|
|
|
if (name.IsEmpty()) {
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2011-05-04 12:49:59 +00:00
|
|
|
}
|
|
|
|
|
2002-07-20 23:09:24 +00:00
|
|
|
if (mForm) {
|
2011-05-04 12:49:59 +00:00
|
|
|
return mForm;
|
2002-07-20 23:09:24 +00:00
|
|
|
}
|
2011-05-04 12:49:59 +00:00
|
|
|
|
2014-10-02 19:07:24 +00:00
|
|
|
//XXXsmaug It isn't clear how this should work in Shadow DOM.
|
|
|
|
return static_cast<nsDocument*>(GetUncomposedDoc());
|
2002-07-20 23:09:24 +00:00
|
|
|
}
|
|
|
|
|
2010-08-18 18:30:41 +00:00
|
|
|
already_AddRefed<nsIDOMHTMLInputElement>
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetSelectedRadioButton()
|
2010-08-18 18:30:41 +00:00
|
|
|
{
|
2011-05-04 12:49:59 +00:00
|
|
|
nsIRadioGroupContainer* container = GetRadioGroupContainer();
|
2010-08-18 18:30:41 +00:00
|
|
|
if (!container) {
|
2012-07-30 14:20:58 +00:00
|
|
|
return nullptr;
|
2010-08-18 18:30:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString name;
|
2011-05-04 12:49:59 +00:00
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
2010-08-18 18:30:41 +00:00
|
|
|
|
2012-08-03 10:38:52 +00:00
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> selected = container->GetCurrentRadioButton(name);
|
2011-11-16 07:50:19 +00:00
|
|
|
return selected.forget();
|
2010-08-18 18:30:41 +00:00
|
|
|
}
|
|
|
|
|
2004-01-05 23:39:50 +00:00
|
|
|
nsresult
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::MaybeSubmitForm(nsPresContext* aPresContext)
|
2004-01-05 23:39:50 +00:00
|
|
|
{
|
|
|
|
if (!mForm) {
|
|
|
|
// Nothing to do here.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
|
2007-03-26 05:38:22 +00:00
|
|
|
nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
|
2006-08-16 03:20:19 +00:00
|
|
|
if (!shell) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2004-01-05 23:39:50 +00:00
|
|
|
|
2006-08-16 03:20:19 +00:00
|
|
|
// Get the default submit element
|
|
|
|
nsIFormControl* submitControl = mForm->GetDefaultSubmitElement();
|
|
|
|
if (submitControl) {
|
2011-11-16 07:50:19 +00:00
|
|
|
nsCOMPtr<nsIContent> submitContent = do_QueryInterface(submitControl);
|
2006-08-16 03:20:19 +00:00
|
|
|
NS_ASSERTION(submitContent, "Form control not implementing nsIContent?!");
|
|
|
|
// Fire the button's onclick handler and let the button handle
|
|
|
|
// submitting the form.
|
2013-10-02 06:38:27 +00:00
|
|
|
WidgetMouseEvent event(true, NS_MOUSE_CLICK, nullptr,
|
|
|
|
WidgetMouseEvent::eReal);
|
2006-08-16 03:20:19 +00:00
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
shell->HandleDOMEventWithTarget(submitContent, &event, &status);
|
2013-10-16 14:39:45 +00:00
|
|
|
} else if (!mForm->ImplicitSubmissionIsDisabled() &&
|
2010-09-11 04:11:58 +00:00
|
|
|
(mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) ||
|
|
|
|
mForm->CheckValidFormSubmission())) {
|
2010-09-11 04:07:41 +00:00
|
|
|
// TODO: removing this code and have the submit event sent by the form,
|
|
|
|
// bug 592124.
|
2006-09-18 04:53:54 +00:00
|
|
|
// If there's only one text control, just submit the form
|
2009-10-30 01:49:11 +00:00
|
|
|
// Hold strong ref across the event
|
2013-06-19 14:24:37 +00:00
|
|
|
nsRefPtr<mozilla::dom::HTMLFormElement> form = mForm;
|
2013-09-27 06:20:55 +00:00
|
|
|
InternalFormEvent event(true, NS_FORM_SUBMIT);
|
2011-11-16 07:50:19 +00:00
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
2009-10-30 01:49:11 +00:00
|
|
|
shell->HandleDOMEventWithTarget(mForm, &event, &status);
|
2004-01-05 23:39:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetCheckedInternal(bool aChecked, bool aNotify)
|
2002-03-07 20:53:40 +00:00
|
|
|
{
|
2002-01-24 19:04:55 +00:00
|
|
|
// Set the value
|
2011-11-16 07:50:19 +00:00
|
|
|
mChecked = aChecked;
|
2000-06-22 02:46:53 +00:00
|
|
|
|
2002-01-24 19:04:55 +00:00
|
|
|
// Notify the frame
|
2010-02-09 22:06:37 +00:00
|
|
|
if (mType == NS_FORM_INPUT_CHECKBOX || mType == NS_FORM_INPUT_RADIO) {
|
|
|
|
nsIFrame* frame = GetPrimaryFrame();
|
|
|
|
if (frame) {
|
2010-08-31 00:49:12 +00:00
|
|
|
frame->InvalidateFrameSubtree();
|
2000-01-14 09:57:31 +00:00
|
|
|
}
|
|
|
|
}
|
2002-03-13 10:12:33 +00:00
|
|
|
|
2011-06-01 01:46:57 +00:00
|
|
|
UpdateAllValidityStates(aNotify);
|
|
|
|
|
2002-03-13 10:12:33 +00:00
|
|
|
// Notify the document that the CSS :checked pseudoclass for this element
|
|
|
|
// has changed state.
|
2011-06-01 01:46:57 +00:00
|
|
|
UpdateState(aNotify);
|
2002-01-24 19:04:55 +00:00
|
|
|
}
|
|
|
|
|
2011-06-21 14:13:12 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::Blur(ErrorResult& aError)
|
|
|
|
{
|
|
|
|
if (mType == NS_FORM_INPUT_NUMBER) {
|
|
|
|
// Blur our anonymous text control, if we have one. (DOM 'change' event
|
|
|
|
// firing and other things depend on this.)
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
|
|
|
HTMLInputElement* textControl = numberControlFrame->GetAnonTextControl();
|
|
|
|
if (textControl) {
|
|
|
|
textControl->Blur(aError);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nsGenericHTMLElement::Blur(aError);
|
|
|
|
}
|
|
|
|
|
2012-10-06 07:19:52 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::Focus(ErrorResult& aError)
|
1998-09-01 01:27:08 +00:00
|
|
|
{
|
2011-06-21 14:13:12 +00:00
|
|
|
if (mType == NS_FORM_INPUT_NUMBER) {
|
|
|
|
// Focus our anonymous text control, if we have one.
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
|
|
|
HTMLInputElement* textControl = numberControlFrame->GetAnonTextControl();
|
|
|
|
if (textControl) {
|
|
|
|
textControl->Focus(aError);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mType != NS_FORM_INPUT_FILE) {
|
2012-10-06 07:19:52 +00:00
|
|
|
nsGenericHTMLElement::Focus(aError);
|
|
|
|
return;
|
2011-11-16 07:50:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// For file inputs, focus the button instead.
|
|
|
|
nsIFrame* frame = GetPrimaryFrame();
|
|
|
|
if (frame) {
|
|
|
|
for (nsIFrame* childFrame = frame->GetFirstPrincipalChild();
|
|
|
|
childFrame;
|
|
|
|
childFrame = childFrame->GetNextSibling()) {
|
|
|
|
// See if the child is a button control.
|
|
|
|
nsCOMPtr<nsIFormControl> formCtrl =
|
|
|
|
do_QueryInterface(childFrame->GetContent());
|
2013-03-29 12:32:47 +00:00
|
|
|
if (formCtrl && formCtrl->GetType() == NS_FORM_BUTTON_BUTTON) {
|
2011-11-16 07:50:19 +00:00
|
|
|
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(formCtrl);
|
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
if (fm && element) {
|
|
|
|
fm->SetFocus(element, 0);
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
}
|
2011-11-16 07:50:19 +00:00
|
|
|
break;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-06 07:19:52 +00:00
|
|
|
return;
|
1999-03-02 19:19:24 +00:00
|
|
|
}
|
|
|
|
|
2015-01-20 20:39:28 +00:00
|
|
|
bool
|
|
|
|
HTMLInputElement::IsInteractiveHTMLContent() const
|
|
|
|
{
|
|
|
|
return mType != NS_FORM_INPUT_HIDDEN;
|
|
|
|
}
|
|
|
|
|
1998-09-01 01:27:08 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::Select()
|
2000-05-30 02:45:55 +00:00
|
|
|
{
|
2013-12-11 11:41:51 +00:00
|
|
|
if (mType == NS_FORM_INPUT_NUMBER) {
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
|
|
|
return numberControlFrame->HandleSelectCall();
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-10-17 14:59:28 +00:00
|
|
|
if (!IsSingleLineTextControl(false)) {
|
2002-03-16 03:28:23 +00:00
|
|
|
return NS_OK;
|
2008-10-07 18:53:23 +00:00
|
|
|
}
|
2000-05-30 02:45:55 +00:00
|
|
|
|
2008-10-07 18:53:23 +00:00
|
|
|
// XXX Bug? We have to give the input focus before contents can be
|
|
|
|
// selected
|
|
|
|
|
|
|
|
FocusTristate state = FocusState();
|
|
|
|
if (state == eUnfocusable) {
|
2005-10-28 11:25:24 +00:00
|
|
|
return NS_OK;
|
2000-05-30 02:45:55 +00:00
|
|
|
}
|
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
|
2014-08-22 20:11:27 +00:00
|
|
|
nsRefPtr<nsPresContext> presContext = GetPresContext(eForComposedDoc);
|
2008-10-07 18:53:23 +00:00
|
|
|
if (state == eInactiveWindow) {
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
if (fm)
|
|
|
|
fm->SetFocus(this, nsIFocusManager::FLAG_NOSCROLL);
|
2008-10-07 18:53:23 +00:00
|
|
|
SelectAll(presContext);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-08-18 23:55:01 +00:00
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
if (DispatchSelectEvent(presContext) && fm) {
|
|
|
|
fm->SetFocus(this, nsIFocusManager::FLAG_NOSCROLL);
|
|
|
|
|
|
|
|
// ensure that the element is actually focused
|
|
|
|
nsCOMPtr<nsIDOMElement> focusedElement;
|
|
|
|
fm->GetFocusedElement(getter_AddRefs(focusedElement));
|
2013-03-28 19:41:32 +00:00
|
|
|
if (SameCOMIdentity(static_cast<nsIDOMNode*>(this), focusedElement)) {
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
// Now Select all the text!
|
|
|
|
SelectAll(presContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::DispatchSelectEvent(nsPresContext* aPresContext)
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
{
|
2008-10-07 18:53:23 +00:00
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
|
|
|
|
// If already handling select event, don't dispatch a second.
|
2011-11-16 07:50:19 +00:00
|
|
|
if (!mHandlingSelectEvent) {
|
2013-10-02 03:46:04 +00:00
|
|
|
WidgetEvent event(nsContentUtils::IsCallerChrome(), NS_FORM_SELECTED);
|
2008-10-07 18:53:23 +00:00
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
mHandlingSelectEvent = true;
|
2014-03-18 04:48:21 +00:00
|
|
|
EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
|
|
|
|
aPresContext, &event, nullptr, &status);
|
2011-11-16 07:50:19 +00:00
|
|
|
mHandlingSelectEvent = false;
|
2008-10-07 18:53:23 +00:00
|
|
|
}
|
2000-05-30 02:45:55 +00:00
|
|
|
|
2008-10-07 18:53:23 +00:00
|
|
|
// If the DOM event was not canceled (e.g. by a JS event handler
|
|
|
|
// returning false)
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
return (status == nsEventStatus_eIgnore);
|
2000-05-30 02:45:55 +00:00
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
|
2000-12-23 10:56:31 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SelectAll(nsPresContext* aPresContext)
|
1998-09-01 01:27:08 +00:00
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
|
2000-12-23 10:56:31 +00:00
|
|
|
|
|
|
|
if (formControlFrame) {
|
2006-12-26 17:47:52 +00:00
|
|
|
formControlFrame->SetFormProperty(nsGkAtoms::select, EmptyString());
|
1998-09-23 17:16:51 +00:00
|
|
|
}
|
1998-09-01 01:27:08 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2014-03-18 04:48:19 +00:00
|
|
|
HTMLInputElement::NeedToInitializeEditorForEvent(
|
|
|
|
EventChainPreVisitor& aVisitor) const
|
2010-02-02 04:00:12 +00:00
|
|
|
{
|
2010-05-13 22:56:24 +00:00
|
|
|
// We only need to initialize the editor for single line input controls because they
|
2010-02-02 04:00:12 +00:00
|
|
|
// are lazily initialized. We don't need to initialize the control for
|
|
|
|
// certain types of events, because we know that those events are safe to be
|
|
|
|
// handled without the editor being initialized. These events include:
|
2014-04-11 15:09:40 +00:00
|
|
|
// mousein/move/out, overflow/underflow, and DOM mutation events.
|
2011-11-16 07:50:19 +00:00
|
|
|
if (!IsSingleLineTextControl(false) ||
|
2014-08-04 05:28:57 +00:00
|
|
|
aVisitor.mEvent->mClass == eMutationEventClass) {
|
2011-11-16 07:50:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (aVisitor.mEvent->message) {
|
|
|
|
case NS_MOUSE_MOVE:
|
|
|
|
case NS_MOUSE_ENTER:
|
|
|
|
case NS_MOUSE_EXIT:
|
|
|
|
case NS_MOUSE_ENTER_SYNTH:
|
|
|
|
case NS_MOUSE_EXIT_SYNTH:
|
2014-04-11 15:09:40 +00:00
|
|
|
case NS_SCROLLPORT_UNDERFLOW:
|
|
|
|
case NS_SCROLLPORT_OVERFLOW:
|
2011-11-16 07:50:19 +00:00
|
|
|
return false;
|
|
|
|
default:
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-02-02 04:00:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-03 15:17:36 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsDisabledForEvents(uint32_t aMessage)
|
2013-01-03 15:17:36 +00:00
|
|
|
{
|
|
|
|
return IsElementDisabledForEvents(aMessage, GetPrimaryFrame());
|
|
|
|
}
|
|
|
|
|
2004-01-09 23:54:21 +00:00
|
|
|
nsresult
|
2014-03-18 04:48:19 +00:00
|
|
|
HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
1998-09-23 17:16:51 +00:00
|
|
|
{
|
1999-12-04 02:22:21 +00:00
|
|
|
// Do not process any DOM events if the element is disabled
|
2011-10-17 14:59:28 +00:00
|
|
|
aVisitor.mCanHandle = false;
|
2013-01-03 15:17:36 +00:00
|
|
|
if (IsDisabledForEvents(aVisitor.mEvent->message)) {
|
2002-12-17 04:31:21 +00:00
|
|
|
return NS_OK;
|
1999-12-04 02:22:21 +00:00
|
|
|
}
|
2010-09-18 21:33:16 +00:00
|
|
|
|
2010-02-02 04:00:12 +00:00
|
|
|
// Initialize the editor if needed.
|
|
|
|
if (NeedToInitializeEditorForEvent(aVisitor)) {
|
|
|
|
nsITextControlFrame* textControlFrame = do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (textControlFrame)
|
|
|
|
textControlFrame->EnsureEditorInitialized();
|
|
|
|
}
|
|
|
|
|
2007-07-20 23:20:33 +00:00
|
|
|
//FIXME Allow submission etc. also when there is no prescontext, Bug 329509.
|
|
|
|
if (!aVisitor.mPresContext) {
|
|
|
|
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
2013-03-28 19:41:32 +00:00
|
|
|
}
|
2000-08-02 22:06:37 +00:00
|
|
|
//
|
2002-12-17 04:31:21 +00:00
|
|
|
// Web pages expect the value of a radio button or checkbox to be set
|
2004-04-30 23:55:16 +00:00
|
|
|
// *before* onclick and DOMActivate fire, and they expect that if they set
|
|
|
|
// the value explicitly during onclick or DOMActivate it will not be toggled
|
|
|
|
// or any such nonsense.
|
2002-12-17 04:31:21 +00:00
|
|
|
// In order to support that (bug 57137 and 58460 are examples) we toggle
|
2004-04-30 23:55:16 +00:00
|
|
|
// the checked attribute *first*, and then fire onclick. If the user
|
|
|
|
// returns false, we reset the control to the old checked value. Otherwise,
|
|
|
|
// we dispatch DOMActivate. If DOMActivate is cancelled, we also reset
|
|
|
|
// the control to the old checked value. We need to keep track of whether
|
|
|
|
// we've already toggled the state from onclick since the user could
|
|
|
|
// explicitly dispatch DOMActivate on the element.
|
2002-12-17 04:31:21 +00:00
|
|
|
//
|
|
|
|
// This is a compatibility hack.
|
2002-03-07 20:53:40 +00:00
|
|
|
//
|
2004-04-30 23:55:16 +00:00
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
// Track whether we're in the outermost Dispatch invocation that will
|
2005-01-11 03:21:23 +00:00
|
|
|
// cause activation of the input. That is, if we're a click event, or a
|
|
|
|
// DOMActivate that was dispatched directly, this will be set, but if we're
|
|
|
|
// a DOMActivate dispatched from click handling, it will not be set.
|
2013-10-28 09:03:19 +00:00
|
|
|
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
2011-09-29 06:19:26 +00:00
|
|
|
bool outerActivateEvent =
|
2013-10-28 09:03:19 +00:00
|
|
|
((mouseEvent && mouseEvent->IsLeftClickEvent()) ||
|
2011-11-16 07:50:19 +00:00
|
|
|
(aVisitor.mEvent->message == NS_UI_ACTIVATE && !mInInternalActivate));
|
2004-04-30 23:55:16 +00:00
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
if (outerActivateEvent) {
|
|
|
|
aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT;
|
|
|
|
}
|
2002-03-07 20:53:40 +00:00
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool originalCheckedValue = false;
|
2002-03-07 20:53:40 +00:00
|
|
|
|
2005-01-11 03:21:23 +00:00
|
|
|
if (outerActivateEvent) {
|
2011-11-16 07:50:19 +00:00
|
|
|
mCheckedIsToggled = false;
|
2004-04-30 23:55:16 +00:00
|
|
|
|
2002-12-17 04:31:21 +00:00
|
|
|
switch(mType) {
|
2000-12-10 16:05:29 +00:00
|
|
|
case NS_FORM_INPUT_CHECKBOX:
|
|
|
|
{
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mIndeterminate) {
|
2009-01-22 00:07:44 +00:00
|
|
|
// indeterminate is always set to FALSE when the checkbox is toggled
|
2011-10-17 14:59:28 +00:00
|
|
|
SetIndeterminateInternal(false, false);
|
2009-01-22 00:07:44 +00:00
|
|
|
aVisitor.mItemFlags |= NS_ORIGINAL_INDETERMINATE_VALUE;
|
|
|
|
}
|
|
|
|
|
2002-12-17 04:31:21 +00:00
|
|
|
GetChecked(&originalCheckedValue);
|
2011-10-17 14:59:28 +00:00
|
|
|
DoSetChecked(!originalCheckedValue, true, true);
|
2011-11-16 07:50:19 +00:00
|
|
|
mCheckedIsToggled = true;
|
2000-12-10 16:05:29 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_FORM_INPUT_RADIO:
|
|
|
|
{
|
2010-08-18 18:30:41 +00:00
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> selectedRadioButton = GetSelectedRadioButton();
|
|
|
|
aVisitor.mItemData = selectedRadioButton;
|
2002-03-07 20:53:40 +00:00
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
originalCheckedValue = mChecked;
|
2002-12-17 04:31:21 +00:00
|
|
|
if (!originalCheckedValue) {
|
2011-10-17 14:59:28 +00:00
|
|
|
DoSetChecked(true, true, true);
|
2011-11-16 07:50:19 +00:00
|
|
|
mCheckedIsToggled = true;
|
2000-12-10 16:05:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2002-11-30 00:01:21 +00:00
|
|
|
case NS_FORM_INPUT_SUBMIT:
|
|
|
|
case NS_FORM_INPUT_IMAGE:
|
2013-03-28 19:41:32 +00:00
|
|
|
if (mForm) {
|
2002-11-30 00:01:21 +00:00
|
|
|
// tell the form that we are about to enter a click handler.
|
|
|
|
// that means that if there are scripted submissions, the
|
2013-03-28 19:41:32 +00:00
|
|
|
// latest one will be deferred until after the exit point of the handler.
|
2010-08-19 23:23:59 +00:00
|
|
|
mForm->OnSubmitClickBegin(this);
|
2002-11-30 00:01:21 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2000-12-10 16:05:29 +00:00
|
|
|
default:
|
|
|
|
break;
|
2011-11-16 07:50:19 +00:00
|
|
|
}
|
2000-08-02 22:06:37 +00:00
|
|
|
}
|
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
if (originalCheckedValue) {
|
|
|
|
aVisitor.mItemFlags |= NS_ORIGINAL_CHECKED_VALUE;
|
|
|
|
}
|
|
|
|
|
2012-12-16 01:26:05 +00:00
|
|
|
// If mNoContentDispatch is true we will not allow content to handle
|
2013-03-28 19:41:32 +00:00
|
|
|
// this event. But to allow middle mouse button paste to work we must allow
|
2001-11-07 06:29:29 +00:00
|
|
|
// middle clicks to go to text fields anyway.
|
2012-12-16 01:26:05 +00:00
|
|
|
if (aVisitor.mEvent->mFlags.mNoContentDispatch) {
|
2006-03-07 17:08:51 +00:00
|
|
|
aVisitor.mItemFlags |= NS_NO_CONTENT_DISPATCH;
|
|
|
|
}
|
2011-10-17 14:59:28 +00:00
|
|
|
if (IsSingleLineTextControl(false) &&
|
2006-11-16 21:35:39 +00:00
|
|
|
aVisitor.mEvent->message == NS_MOUSE_CLICK &&
|
2013-10-22 08:55:20 +00:00
|
|
|
aVisitor.mEvent->AsMouseEvent()->button ==
|
2013-10-02 06:38:27 +00:00
|
|
|
WidgetMouseEvent::eMiddleButton) {
|
2012-12-16 01:26:05 +00:00
|
|
|
aVisitor.mEvent->mFlags.mNoContentDispatch = false;
|
2001-11-07 06:29:29 +00:00
|
|
|
}
|
|
|
|
|
2002-12-17 04:31:21 +00:00
|
|
|
// We must cache type because mType may change during JS event (bug 2369)
|
2010-06-01 13:42:37 +00:00
|
|
|
aVisitor.mItemFlags |= mType;
|
2006-11-28 13:08:23 +00:00
|
|
|
|
|
|
|
// Fire onchange (if necessary), before we do the blur, bug 357684.
|
|
|
|
if (aVisitor.mEvent->message == NS_BLUR_CONTENT) {
|
2013-01-31 23:05:48 +00:00
|
|
|
// Experimental mobile types rely on the system UI to prevent users to not
|
|
|
|
// set invalid values but we have to be extra-careful. Especially if the
|
|
|
|
// option has been enabled on desktop.
|
|
|
|
if (IsExperimentalMobileType(mType)) {
|
2012-07-05 16:15:46 +00:00
|
|
|
nsAutoString aValue;
|
|
|
|
GetValueInternal(aValue);
|
2015-01-08 01:14:01 +00:00
|
|
|
nsresult rv = SetValueInternal(aValue, false, false);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2012-07-05 16:15:46 +00:00
|
|
|
}
|
2012-05-07 16:27:24 +00:00
|
|
|
FireChangeEventIfNeeded();
|
2006-11-28 13:08:23 +00:00
|
|
|
}
|
|
|
|
|
2013-04-22 09:11:56 +00:00
|
|
|
if (mType == NS_FORM_INPUT_RANGE &&
|
|
|
|
(aVisitor.mEvent->message == NS_FOCUS_CONTENT ||
|
|
|
|
aVisitor.mEvent->message == NS_BLUR_CONTENT)) {
|
2013-08-02 01:21:31 +00:00
|
|
|
// Just as nsGenericHTMLFormElementWithState::PreHandleEvent calls
|
2013-04-22 09:11:56 +00:00
|
|
|
// nsIFormControlFrame::SetFocus, we handle focus here.
|
|
|
|
nsIFrame* frame = GetPrimaryFrame();
|
|
|
|
if (frame) {
|
|
|
|
frame->InvalidateFrameSubtree();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-01 13:49:10 +00:00
|
|
|
if (mType == NS_FORM_INPUT_NUMBER &&
|
|
|
|
aVisitor.mEvent->mFlags.mIsTrusted) {
|
|
|
|
if (mNumberControlSpinnerIsSpinning) {
|
|
|
|
// If the timer is running the user has depressed the mouse on one of the
|
|
|
|
// spin buttons. If the mouse exits the button we either want to reverse
|
|
|
|
// the direction of spin if it has moved over the other button, or else
|
|
|
|
// we want to end the spin. We do this here (rather than in
|
|
|
|
// PostHandleEvent) because we don't want to let content preventDefault()
|
|
|
|
// the end of the spin.
|
|
|
|
if (aVisitor.mEvent->message == NS_MOUSE_MOVE) {
|
|
|
|
// Be aggressive about stopping the spin:
|
|
|
|
bool stopSpin = true;
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
2013-12-05 16:20:34 +00:00
|
|
|
bool oldNumberControlSpinTimerSpinsUpValue =
|
|
|
|
mNumberControlSpinnerSpinsUp;
|
2013-12-01 13:49:10 +00:00
|
|
|
switch (numberControlFrame->GetSpinButtonForPointerEvent(
|
|
|
|
aVisitor.mEvent->AsMouseEvent())) {
|
|
|
|
case nsNumberControlFrame::eSpinButtonUp:
|
|
|
|
mNumberControlSpinnerSpinsUp = true;
|
|
|
|
stopSpin = false;
|
|
|
|
break;
|
|
|
|
case nsNumberControlFrame::eSpinButtonDown:
|
|
|
|
mNumberControlSpinnerSpinsUp = false;
|
|
|
|
stopSpin = false;
|
|
|
|
break;
|
|
|
|
}
|
2013-12-05 16:20:34 +00:00
|
|
|
if (mNumberControlSpinnerSpinsUp !=
|
|
|
|
oldNumberControlSpinTimerSpinsUpValue) {
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
|
|
|
numberControlFrame->SpinnerStateChanged();
|
|
|
|
}
|
|
|
|
}
|
2013-12-01 13:49:10 +00:00
|
|
|
}
|
|
|
|
if (stopSpin) {
|
|
|
|
StopNumberControlSpinnerSpin();
|
|
|
|
}
|
|
|
|
} else if (aVisitor.mEvent->message == NS_MOUSE_BUTTON_UP) {
|
|
|
|
StopNumberControlSpinnerSpin();
|
|
|
|
}
|
|
|
|
}
|
2013-12-01 14:43:26 +00:00
|
|
|
if (aVisitor.mEvent->message == NS_FOCUS_CONTENT ||
|
|
|
|
aVisitor.mEvent->message == NS_BLUR_CONTENT) {
|
2014-01-13 12:03:55 +00:00
|
|
|
if (aVisitor.mEvent->message == NS_FOCUS_CONTENT) {
|
|
|
|
// Tell our frame it's getting focus so that it can make sure focus
|
|
|
|
// is moved to our anonymous text control.
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
|
|
|
// This could kill the frame!
|
|
|
|
numberControlFrame->HandleFocusEvent(aVisitor.mEvent);
|
2013-12-05 16:20:34 +00:00
|
|
|
}
|
2013-12-05 16:20:33 +00:00
|
|
|
}
|
2014-01-13 12:03:55 +00:00
|
|
|
nsIFrame* frame = GetPrimaryFrame();
|
|
|
|
if (frame && frame->IsThemed()) {
|
|
|
|
// Our frame's nested <input type=text> will be invalidated when it
|
|
|
|
// loses focus, but since we are also native themed we need to make
|
|
|
|
// sure that our entire area is repainted since any focus highlight
|
|
|
|
// from the theme should be removed from us (the repainting of the
|
|
|
|
// sub-area occupied by the anon text control is not enough to do
|
|
|
|
// that).
|
|
|
|
frame->InvalidateFrame();
|
|
|
|
}
|
2013-12-05 16:20:33 +00:00
|
|
|
} else if (aVisitor.mEvent->message == NS_KEY_UP) {
|
|
|
|
WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
|
|
|
|
if ((keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) &&
|
|
|
|
!(keyEvent->IsShift() || keyEvent->IsControl() ||
|
|
|
|
keyEvent->IsAlt() || keyEvent->IsMeta() ||
|
|
|
|
keyEvent->IsAltGraph() || keyEvent->IsFn() ||
|
|
|
|
keyEvent->IsOS())) {
|
|
|
|
// The up/down arrow key events fire 'change' events when released
|
|
|
|
// so that at the end of a series of up/down arrow key repeat events
|
|
|
|
// the value is considered to be "commited" by the user.
|
|
|
|
FireChangeEventIfNeeded();
|
|
|
|
}
|
2013-12-01 14:43:26 +00:00
|
|
|
}
|
2013-12-01 13:49:10 +00:00
|
|
|
}
|
|
|
|
|
2013-11-22 13:24:53 +00:00
|
|
|
nsresult rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
|
|
|
|
|
|
|
|
// We do this after calling the base class' PreHandleEvent so that
|
|
|
|
// nsIContent::PreHandleEvent doesn't reset any change we make to mCanHandle.
|
|
|
|
if (mType == NS_FORM_INPUT_NUMBER &&
|
|
|
|
aVisitor.mEvent->mFlags.mIsTrusted &&
|
|
|
|
aVisitor.mEvent->originalTarget != this) {
|
|
|
|
// <input type=number> has an anonymous <input type=text> descendant. If
|
|
|
|
// 'input' or 'change' events are fired at that text control then we need
|
|
|
|
// to do some special handling here.
|
|
|
|
HTMLInputElement* textControl = nullptr;
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
|
|
|
textControl = numberControlFrame->GetAnonTextControl();
|
|
|
|
}
|
|
|
|
if (textControl && aVisitor.mEvent->originalTarget == textControl) {
|
2014-04-10 07:11:37 +00:00
|
|
|
if (aVisitor.mEvent->message == NS_EDITOR_INPUT) {
|
2013-11-22 13:24:53 +00:00
|
|
|
// Propogate the anon text control's new value to our HTMLInputElement:
|
|
|
|
nsAutoString value;
|
2014-01-23 15:43:12 +00:00
|
|
|
numberControlFrame->GetValueOfAnonTextControl(value);
|
|
|
|
numberControlFrame->HandlingInputEvent(true);
|
2014-01-13 12:03:55 +00:00
|
|
|
nsWeakFrame weakNumberControlFrame(numberControlFrame);
|
2015-01-08 01:14:01 +00:00
|
|
|
rv = SetValueInternal(value, true, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-01-13 12:03:55 +00:00
|
|
|
if (weakNumberControlFrame.IsAlive()) {
|
|
|
|
numberControlFrame->HandlingInputEvent(false);
|
|
|
|
}
|
2013-11-22 13:24:53 +00:00
|
|
|
}
|
|
|
|
else if (aVisitor.mEvent->message == NS_FORM_CHANGE) {
|
|
|
|
// We cancel the DOM 'change' event that is fired for any change to our
|
|
|
|
// anonymous text control since we fire our own 'change' events and
|
|
|
|
// content shouldn't be seeing two 'change' events. Besides that we
|
|
|
|
// (as a number) control have tighter restrictions on when our internal
|
|
|
|
// value changes than our anon text control does, so in some cases
|
|
|
|
// (if our text control's value doesn't parse as a number) we don't
|
|
|
|
// want to fire a 'change' event at all.
|
|
|
|
aVisitor.mCanHandle = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
}
|
|
|
|
|
2013-03-08 09:40:12 +00:00
|
|
|
void
|
2013-10-02 03:46:03 +00:00
|
|
|
HTMLInputElement::StartRangeThumbDrag(WidgetGUIEvent* aEvent)
|
2013-03-08 09:40:12 +00:00
|
|
|
{
|
|
|
|
mIsDraggingRange = true;
|
2013-05-05 23:23:18 +00:00
|
|
|
mRangeThumbDragStartValue = GetValueAsDecimal();
|
2013-11-28 06:46:40 +00:00
|
|
|
// Don't use CAPTURE_RETARGETTOELEMENT, as that breaks pseudo-class styling
|
|
|
|
// of the thumb.
|
|
|
|
nsIPresShell::SetCapturingContent(this, CAPTURE_IGNOREALLOWED);
|
2013-03-08 09:40:12 +00:00
|
|
|
nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
|
2013-11-21 12:55:01 +00:00
|
|
|
|
|
|
|
// Before we change the value, record the current value so that we'll
|
|
|
|
// correctly send a 'change' event if appropriate. We need to do this here
|
|
|
|
// because the 'focus' event is handled after the 'mousedown' event that
|
|
|
|
// we're being called for (i.e. too late to update mFocusedValue, since we'll
|
|
|
|
// have changed it by then).
|
2014-01-30 10:45:46 +00:00
|
|
|
GetValue(mFocusedValue);
|
2013-11-21 12:55:01 +00:00
|
|
|
|
2013-03-08 09:40:12 +00:00
|
|
|
SetValueOfRangeForUserEvent(rangeFrame->GetValueAtEventPoint(aEvent));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-10-02 03:46:03 +00:00
|
|
|
HTMLInputElement::FinishRangeThumbDrag(WidgetGUIEvent* aEvent)
|
2013-03-08 09:40:12 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(mIsDraggingRange);
|
2013-03-28 19:41:32 +00:00
|
|
|
|
2013-03-08 09:40:12 +00:00
|
|
|
if (nsIPresShell::GetCapturingContent() == this) {
|
|
|
|
nsIPresShell::SetCapturingContent(nullptr, 0); // cancel capture
|
|
|
|
}
|
|
|
|
if (aEvent) {
|
|
|
|
nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
|
|
|
|
SetValueOfRangeForUserEvent(rangeFrame->GetValueAtEventPoint(aEvent));
|
|
|
|
}
|
|
|
|
mIsDraggingRange = false;
|
2013-03-16 05:49:41 +00:00
|
|
|
FireChangeEventIfNeeded();
|
2013-03-08 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::CancelRangeThumbDrag(bool aIsForUserEvent)
|
2013-03-08 09:40:12 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(mIsDraggingRange);
|
|
|
|
|
2013-04-16 14:20:37 +00:00
|
|
|
mIsDraggingRange = false;
|
2013-03-08 09:40:12 +00:00
|
|
|
if (nsIPresShell::GetCapturingContent() == this) {
|
|
|
|
nsIPresShell::SetCapturingContent(nullptr, 0); // cancel capture
|
|
|
|
}
|
2013-03-16 05:49:41 +00:00
|
|
|
if (aIsForUserEvent) {
|
|
|
|
SetValueOfRangeForUserEvent(mRangeThumbDragStartValue);
|
|
|
|
} else {
|
|
|
|
// Don't dispatch an 'input' event - at least not using
|
|
|
|
// DispatchTrustedEvent.
|
|
|
|
// TODO: decide what we should do here - bug 851782.
|
|
|
|
nsAutoString val;
|
|
|
|
ConvertNumberToString(mRangeThumbDragStartValue, val);
|
2015-01-08 01:14:01 +00:00
|
|
|
// TODO: What should we do if SetValueInternal fails? (The allocation
|
|
|
|
// is small, so we should be fine here.)
|
2013-03-16 05:49:41 +00:00
|
|
|
SetValueInternal(val, true, true);
|
|
|
|
nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (frame) {
|
2013-03-26 23:04:41 +00:00
|
|
|
frame->UpdateForValueChange();
|
2013-03-16 05:49:41 +00:00
|
|
|
}
|
2014-03-17 06:56:54 +00:00
|
|
|
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
|
|
|
new AsyncEventDispatcher(this, NS_LITERAL_STRING("input"), true, false);
|
|
|
|
asyncDispatcher->RunDOMEventWhenSafe();
|
2013-03-16 05:49:41 +00:00
|
|
|
}
|
2013-03-08 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-05-05 23:23:18 +00:00
|
|
|
HTMLInputElement::SetValueOfRangeForUserEvent(Decimal aValue)
|
2013-03-08 09:40:12 +00:00
|
|
|
{
|
2013-05-05 23:23:18 +00:00
|
|
|
MOZ_ASSERT(aValue.isFinite());
|
2013-03-08 09:40:12 +00:00
|
|
|
|
|
|
|
nsAutoString val;
|
|
|
|
ConvertNumberToString(aValue, val);
|
2015-01-08 01:14:01 +00:00
|
|
|
// TODO: What should we do if SetValueInternal fails? (The allocation
|
|
|
|
// is small, so we should be fine here.)
|
2013-03-08 09:40:12 +00:00
|
|
|
SetValueInternal(val, true, true);
|
2013-03-13 11:48:27 +00:00
|
|
|
nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
2013-03-08 09:40:12 +00:00
|
|
|
if (frame) {
|
2013-03-26 23:04:41 +00:00
|
|
|
frame->UpdateForValueChange();
|
2013-03-08 09:40:12 +00:00
|
|
|
}
|
2013-03-16 05:49:41 +00:00
|
|
|
nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
|
|
|
|
static_cast<nsIDOMHTMLInputElement*>(this),
|
|
|
|
NS_LITERAL_STRING("input"), true,
|
|
|
|
false);
|
2013-03-08 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
2013-12-01 13:49:10 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::StartNumberControlSpinnerSpin()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!mNumberControlSpinnerIsSpinning);
|
|
|
|
|
|
|
|
mNumberControlSpinnerIsSpinning = true;
|
|
|
|
|
|
|
|
nsRepeatService::GetInstance()->Start(HandleNumberControlSpin, this);
|
|
|
|
|
|
|
|
// Capture the mouse so that we can tell if the pointer moves from one
|
|
|
|
// spin button to the other, or to some other element:
|
|
|
|
nsIPresShell::SetCapturingContent(this, CAPTURE_IGNOREALLOWED);
|
2013-12-05 16:20:34 +00:00
|
|
|
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
|
|
|
numberControlFrame->SpinnerStateChanged();
|
|
|
|
}
|
2013-12-01 13:49:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HTMLInputElement::StopNumberControlSpinnerSpin()
|
|
|
|
{
|
|
|
|
if (mNumberControlSpinnerIsSpinning) {
|
|
|
|
if (nsIPresShell::GetCapturingContent() == this) {
|
|
|
|
nsIPresShell::SetCapturingContent(nullptr, 0); // cancel capture
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRepeatService::GetInstance()->Stop(HandleNumberControlSpin, this);
|
|
|
|
|
|
|
|
mNumberControlSpinnerIsSpinning = false;
|
2013-12-05 16:20:33 +00:00
|
|
|
|
|
|
|
FireChangeEventIfNeeded();
|
2013-12-05 16:20:34 +00:00
|
|
|
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
|
|
|
numberControlFrame->SpinnerStateChanged();
|
|
|
|
}
|
2013-12-01 13:49:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-05 16:20:33 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::StepNumberControlForUserEvent(int32_t aDirection)
|
|
|
|
{
|
2014-11-26 09:54:32 +00:00
|
|
|
// We can't use GetValidityState here because the validity state is not set
|
|
|
|
// if the user hasn't previously taken an action to set or change the value,
|
|
|
|
// according to the specs.
|
|
|
|
if (HasBadInput()) {
|
2014-02-12 17:13:32 +00:00
|
|
|
// If the user has typed a value into the control and inadvertently made a
|
|
|
|
// mistake (e.g. put a thousand separator at the wrong point) we do not
|
|
|
|
// want to wipe out what they typed if they try to increment/decrement the
|
|
|
|
// value. Better is to highlight the value as being invalid so that they
|
|
|
|
// can correct what they typed.
|
2014-02-26 23:04:31 +00:00
|
|
|
// We only do this if there actually is a value typed in by/displayed to
|
|
|
|
// the user. (IsValid() can return false if the 'required' attribute is
|
|
|
|
// set and the value is the empty string.)
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame &&
|
|
|
|
!numberControlFrame->AnonTextControlIsEmpty()) {
|
|
|
|
// We pass 'true' for UpdateValidityUIBits' aIsFocused argument
|
|
|
|
// regardless because we need the UI to update _now_ or the user will
|
|
|
|
// wonder why the step behavior isn't functioning.
|
|
|
|
UpdateValidityUIBits(true);
|
|
|
|
UpdateState(true);
|
|
|
|
return;
|
|
|
|
}
|
2014-02-12 17:13:32 +00:00
|
|
|
}
|
|
|
|
|
2013-12-05 16:20:33 +00:00
|
|
|
Decimal newValue = Decimal::nan(); // unchanged if value will not change
|
|
|
|
|
2014-01-15 17:22:16 +00:00
|
|
|
nsresult rv = GetValueIfStepped(aDirection, CALLED_FOR_USER_EVENT, &newValue);
|
2013-12-05 16:20:33 +00:00
|
|
|
|
|
|
|
if (NS_FAILED(rv) || !newValue.isFinite()) {
|
|
|
|
return; // value should not or will not change
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString newVal;
|
|
|
|
ConvertNumberToString(newValue, newVal);
|
2015-01-08 01:14:01 +00:00
|
|
|
// TODO: What should we do if SetValueInternal fails? (The allocation
|
|
|
|
// is small, so we should be fine here.)
|
2013-12-05 16:20:33 +00:00
|
|
|
SetValueInternal(newVal, true, true);
|
|
|
|
|
2013-12-05 16:20:33 +00:00
|
|
|
nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
|
|
|
|
static_cast<nsIDOMHTMLInputElement*>(this),
|
|
|
|
NS_LITERAL_STRING("input"), true,
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
static bool
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
SelectTextFieldOnFocus()
|
|
|
|
{
|
|
|
|
if (!gSelectTextFieldOnFocus) {
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t selectTextfieldsOnKeyFocus = -1;
|
2011-09-09 02:27:12 +00:00
|
|
|
nsresult rv =
|
|
|
|
LookAndFeel::GetInt(LookAndFeel::eIntID_SelectTextfieldsOnKeyFocus,
|
|
|
|
&selectTextfieldsOnKeyFocus);
|
|
|
|
if (NS_FAILED(rv)) {
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
gSelectTextFieldOnFocus = -1;
|
2011-09-09 02:27:12 +00:00
|
|
|
} else {
|
|
|
|
gSelectTextFieldOnFocus = selectTextfieldsOnKeyFocus != 0 ? 1 : -1;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return gSelectTextFieldOnFocus == 1;
|
2006-03-07 17:08:51 +00:00
|
|
|
}
|
2001-11-07 06:29:29 +00:00
|
|
|
|
2013-03-27 11:32:00 +00:00
|
|
|
bool
|
2013-04-19 22:18:33 +00:00
|
|
|
HTMLInputElement::ShouldPreventDOMActivateDispatch(EventTarget* aOriginalTarget)
|
2013-03-27 11:32:00 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* For the moment, there is only one situation where we actually want to
|
|
|
|
* prevent firing a DOMActivate event:
|
|
|
|
* - we are a <input type='file'> that just got a click event,
|
|
|
|
* - the event was targeted to our button which should have sent a
|
|
|
|
* DOMActivate event.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (mType != NS_FORM_INPUT_FILE) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> target = do_QueryInterface(aOriginalTarget);
|
|
|
|
if (!target) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return target->GetParent() == this &&
|
|
|
|
target->IsRootOfNativeAnonymousSubtree() &&
|
|
|
|
target->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
|
|
|
nsGkAtoms::button, eCaseMatters);
|
|
|
|
}
|
|
|
|
|
2013-08-02 11:40:49 +00:00
|
|
|
nsresult
|
2014-03-18 04:48:20 +00:00
|
|
|
HTMLInputElement::MaybeInitPickers(EventChainPostVisitor& aVisitor)
|
2013-06-03 21:40:41 +00:00
|
|
|
{
|
|
|
|
// Open a file picker when we receive a click on a <input type='file'>, or
|
|
|
|
// open a color picker when we receive a click on a <input type='color'>.
|
|
|
|
// A click is handled in the following cases:
|
|
|
|
// - preventDefault() has not been called (or something similar);
|
|
|
|
// - it's the left mouse button.
|
|
|
|
// We do not prevent non-trusted click because authors can already use
|
2013-08-02 11:40:49 +00:00
|
|
|
// .click(). However, the pickers will follow the rules of popup-blocking.
|
2013-10-28 09:03:19 +00:00
|
|
|
if (aVisitor.mEvent->mFlags.mDefaultPrevented) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
|
|
|
if (!(mouseEvent && mouseEvent->IsLeftClickEvent())) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (mType == NS_FORM_INPUT_FILE) {
|
|
|
|
return InitFilePicker(FILE_PICKER_FILE);
|
|
|
|
}
|
|
|
|
if (mType == NS_FORM_INPUT_COLOR) {
|
|
|
|
return InitColorPicker();
|
2013-06-03 21:40:41 +00:00
|
|
|
}
|
2013-08-02 11:40:49 +00:00
|
|
|
return NS_OK;
|
2013-06-03 21:40:41 +00:00
|
|
|
}
|
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
nsresult
|
2014-03-18 04:48:20 +00:00
|
|
|
HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
2006-03-07 17:08:51 +00:00
|
|
|
{
|
|
|
|
if (!aVisitor.mPresContext) {
|
2013-06-03 21:40:41 +00:00
|
|
|
// Hack alert! In order to open file picker even in case the element isn't
|
2013-08-02 11:40:49 +00:00
|
|
|
// in document, try to init picker even without PresContext.
|
|
|
|
return MaybeInitPickers(aVisitor);
|
2006-03-07 17:08:51 +00:00
|
|
|
}
|
2009-11-25 02:12:00 +00:00
|
|
|
|
2010-11-23 23:50:53 +00:00
|
|
|
if (aVisitor.mEvent->message == NS_FOCUS_CONTENT ||
|
|
|
|
aVisitor.mEvent->message == NS_BLUR_CONTENT) {
|
2013-03-28 19:41:32 +00:00
|
|
|
if (aVisitor.mEvent->message == NS_FOCUS_CONTENT &&
|
2013-11-21 12:55:01 +00:00
|
|
|
MayFireChangeOnBlur() &&
|
|
|
|
!mIsDraggingRange) { // StartRangeThumbDrag already set mFocusedValue
|
2014-01-30 10:45:46 +00:00
|
|
|
GetValue(mFocusedValue);
|
2012-05-07 16:27:24 +00:00
|
|
|
}
|
2010-11-23 23:56:24 +00:00
|
|
|
|
2013-12-01 13:49:10 +00:00
|
|
|
if (aVisitor.mEvent->message == NS_BLUR_CONTENT) {
|
|
|
|
if (mIsDraggingRange) {
|
|
|
|
FinishRangeThumbDrag();
|
|
|
|
} else if (mNumberControlSpinnerIsSpinning) {
|
|
|
|
StopNumberControlSpinnerSpin();
|
|
|
|
}
|
2013-03-08 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
2011-06-01 01:46:57 +00:00
|
|
|
UpdateValidityUIBits(aVisitor.mEvent->message == NS_FOCUS_CONTENT);
|
2010-11-23 23:50:53 +00:00
|
|
|
|
2011-06-01 01:46:57 +00:00
|
|
|
UpdateState(true);
|
2010-08-25 04:39:10 +00:00
|
|
|
}
|
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
nsresult rv = NS_OK;
|
2011-09-29 06:19:26 +00:00
|
|
|
bool outerActivateEvent = !!(aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT);
|
|
|
|
bool originalCheckedValue =
|
2008-02-10 06:16:30 +00:00
|
|
|
!!(aVisitor.mItemFlags & NS_ORIGINAL_CHECKED_VALUE);
|
2011-09-29 06:19:26 +00:00
|
|
|
bool noContentDispatch = !!(aVisitor.mItemFlags & NS_NO_CONTENT_DISPATCH);
|
2012-08-22 15:56:38 +00:00
|
|
|
uint8_t oldType = NS_CONTROL_TYPE(aVisitor.mItemFlags);
|
2013-03-27 11:32:00 +00:00
|
|
|
|
2004-04-30 23:55:16 +00:00
|
|
|
// Ideally we would make the default action for click and space just dispatch
|
|
|
|
// DOMActivate, and the default action for DOMActivate flip the checkbox/
|
|
|
|
// radio state and fire onchange. However, for backwards compatibility, we
|
|
|
|
// need to flip the state before firing click, and we need to fire click
|
|
|
|
// when space is pressed. So, we just nest the firing of DOMActivate inside
|
|
|
|
// the click event handling, and allow cancellation of DOMActivate to cancel
|
|
|
|
// the click.
|
2006-03-07 17:08:51 +00:00
|
|
|
if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault &&
|
2013-09-04 10:30:36 +00:00
|
|
|
!IsSingleLineTextControl(true) &&
|
|
|
|
mType != NS_FORM_INPUT_NUMBER) {
|
2013-10-28 09:03:19 +00:00
|
|
|
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
|
|
|
if (mouseEvent && mouseEvent->IsLeftClickEvent() &&
|
|
|
|
!ShouldPreventDOMActivateDispatch(aVisitor.mEvent->originalTarget)) {
|
2014-02-15 01:06:06 +00:00
|
|
|
// XXX Activating actually occurs even if it's caused by untrusted event.
|
|
|
|
// Therefore, shouldn't this be always trusted event?
|
2013-10-28 09:03:19 +00:00
|
|
|
InternalUIEvent actEvent(aVisitor.mEvent->mFlags.mIsTrusted,
|
2014-02-15 01:06:06 +00:00
|
|
|
NS_UI_ACTIVATE);
|
|
|
|
actEvent.detail = 1;
|
2013-10-28 09:03:19 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
|
|
|
|
if (shell) {
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
mInInternalActivate = true;
|
|
|
|
rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
|
|
|
|
mInInternalActivate = false;
|
|
|
|
|
|
|
|
// If activate is cancelled, we must do the same as when click is
|
|
|
|
// cancelled (revert the checkbox to its original value).
|
|
|
|
if (status == nsEventStatus_eConsumeNoDefault) {
|
|
|
|
aVisitor.mEventStatus = status;
|
|
|
|
}
|
|
|
|
}
|
2004-04-30 23:55:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-11 03:21:23 +00:00
|
|
|
if (outerActivateEvent) {
|
2002-12-17 04:31:21 +00:00
|
|
|
switch(oldType) {
|
2002-11-30 00:01:21 +00:00
|
|
|
case NS_FORM_INPUT_SUBMIT:
|
|
|
|
case NS_FORM_INPUT_IMAGE:
|
2013-03-28 19:41:32 +00:00
|
|
|
if (mForm) {
|
2002-11-30 00:01:21 +00:00
|
|
|
// tell the form that we are about to exit a click handler
|
|
|
|
// so the form knows not to defer subsequent submissions
|
|
|
|
// the pending ones that were created during the handler
|
|
|
|
// will be flushed or forgoten.
|
|
|
|
mForm->OnSubmitClickEnd();
|
|
|
|
}
|
|
|
|
break;
|
2011-11-16 07:50:19 +00:00
|
|
|
}
|
2002-11-30 00:01:21 +00:00
|
|
|
}
|
|
|
|
|
2001-11-07 06:29:29 +00:00
|
|
|
// Reset the flag for other content besides this text field
|
2012-12-16 01:26:05 +00:00
|
|
|
aVisitor.mEvent->mFlags.mNoContentDispatch = noContentDispatch;
|
2001-11-07 06:29:29 +00:00
|
|
|
|
2000-12-10 16:05:29 +00:00
|
|
|
// now check to see if the event was "cancelled"
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mCheckedIsToggled && outerActivateEvent) {
|
2006-03-07 17:08:51 +00:00
|
|
|
if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
|
2002-12-17 04:31:21 +00:00
|
|
|
// if it was cancelled and a radio button, then set the old
|
|
|
|
// selected btn to TRUE. if it is a checkbox then set it to its
|
|
|
|
// original value
|
2011-11-22 12:38:37 +00:00
|
|
|
if (oldType == NS_FORM_INPUT_RADIO) {
|
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> selectedRadioButton =
|
|
|
|
do_QueryInterface(aVisitor.mItemData);
|
|
|
|
if (selectedRadioButton) {
|
|
|
|
selectedRadioButton->SetChecked(true);
|
|
|
|
}
|
|
|
|
// If there was no checked radio button or this one is no longer a
|
|
|
|
// radio button we must reset it back to false to cancel the action.
|
|
|
|
// See how the web of hack grows?
|
|
|
|
if (!selectedRadioButton || mType != NS_FORM_INPUT_RADIO) {
|
2011-10-17 14:59:28 +00:00
|
|
|
DoSetChecked(false, true, true);
|
2002-12-17 04:31:21 +00:00
|
|
|
}
|
|
|
|
} else if (oldType == NS_FORM_INPUT_CHECKBOX) {
|
2011-09-29 06:19:26 +00:00
|
|
|
bool originalIndeterminateValue =
|
2009-01-22 00:07:44 +00:00
|
|
|
!!(aVisitor.mItemFlags & NS_ORIGINAL_INDETERMINATE_VALUE);
|
2011-10-17 14:59:28 +00:00
|
|
|
SetIndeterminateInternal(originalIndeterminateValue, false);
|
|
|
|
DoSetChecked(originalCheckedValue, true, true);
|
2002-12-17 04:31:21 +00:00
|
|
|
}
|
|
|
|
} else {
|
2011-10-18 10:53:36 +00:00
|
|
|
nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
|
2010-12-17 17:45:46 +00:00
|
|
|
static_cast<nsIDOMHTMLInputElement*>(this),
|
2011-10-17 14:59:28 +00:00
|
|
|
NS_LITERAL_STRING("change"), true,
|
|
|
|
false);
|
2002-12-17 04:31:21 +00:00
|
|
|
#ifdef ACCESSIBILITY
|
|
|
|
// Fire an event to notify accessibility
|
|
|
|
if (mType == NS_FORM_INPUT_CHECKBOX) {
|
2006-05-16 03:54:46 +00:00
|
|
|
FireEventForAccessibility(this, aVisitor.mPresContext,
|
2002-12-17 04:31:21 +00:00
|
|
|
NS_LITERAL_STRING("CheckboxStateChange"));
|
|
|
|
} else {
|
2006-05-16 03:54:46 +00:00
|
|
|
FireEventForAccessibility(this, aVisitor.mPresContext,
|
|
|
|
NS_LITERAL_STRING("RadioStateChange"));
|
|
|
|
// Fire event for the previous selected radio.
|
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> previous =
|
|
|
|
do_QueryInterface(aVisitor.mItemData);
|
2013-03-28 19:41:32 +00:00
|
|
|
if (previous) {
|
2006-10-12 13:30:07 +00:00
|
|
|
FireEventForAccessibility(previous, aVisitor.mPresContext,
|
|
|
|
NS_LITERAL_STRING("RadioStateChange"));
|
|
|
|
}
|
2002-12-17 04:31:21 +00:00
|
|
|
}
|
|
|
|
#endif
|
2000-12-10 16:05:29 +00:00
|
|
|
}
|
|
|
|
}
|
2000-10-24 01:41:07 +00:00
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2013-12-01 13:49:10 +00:00
|
|
|
WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
|
|
|
|
if (mType == NS_FORM_INPUT_NUMBER &&
|
|
|
|
keyEvent && keyEvent->message == NS_KEY_PRESS &&
|
|
|
|
aVisitor.mEvent->mFlags.mIsTrusted &&
|
|
|
|
(keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) &&
|
|
|
|
!(keyEvent->IsShift() || keyEvent->IsControl() ||
|
|
|
|
keyEvent->IsAlt() || keyEvent->IsMeta() ||
|
|
|
|
keyEvent->IsAltGraph() || keyEvent->IsFn() ||
|
|
|
|
keyEvent->IsOS())) {
|
|
|
|
// We handle the up/down arrow keys specially for <input type=number>.
|
|
|
|
// On some platforms the editor for the nested text control will
|
|
|
|
// process these keys to send the cursor to the start/end of the text
|
|
|
|
// control and as a result aVisitor.mEventStatus will already have been
|
|
|
|
// set to nsEventStatus_eConsumeNoDefault. However, we know that
|
|
|
|
// whenever the up/down arrow keys cause the value of the number
|
|
|
|
// control to change the string in the text control will change, and
|
|
|
|
// the cursor will be moved to the end of the text control, overwriting
|
|
|
|
// the editor's handling of up/down keypress events. For that reason we
|
|
|
|
// just ignore aVisitor.mEventStatus here and go ahead and handle the
|
|
|
|
// event to increase/decrease the value of the number control.
|
2014-04-13 18:42:40 +00:00
|
|
|
if (!aVisitor.mEvent->mFlags.mDefaultPreventedByContent && IsMutable()) {
|
2013-12-08 17:58:54 +00:00
|
|
|
StepNumberControlForUserEvent(keyEvent->keyCode == NS_VK_UP ? 1 : -1);
|
|
|
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
|
|
|
}
|
2013-12-01 13:49:10 +00:00
|
|
|
} else if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
|
2006-03-07 17:08:51 +00:00
|
|
|
switch (aVisitor.mEvent->message) {
|
2002-11-30 00:01:21 +00:00
|
|
|
|
|
|
|
case NS_FOCUS_CONTENT:
|
|
|
|
{
|
2009-10-01 17:53:10 +00:00
|
|
|
// see if we should select the contents of the textbox. This happens
|
|
|
|
// for text and password fields when the field was focused by the
|
|
|
|
// keyboard or a navigation, the platform allows it, and it wasn't
|
|
|
|
// just because we raised a window.
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
2011-10-17 14:59:28 +00:00
|
|
|
if (fm && IsSingleLineTextControl(false) &&
|
2013-10-18 06:10:22 +00:00
|
|
|
!aVisitor.mEvent->AsFocusEvent()->fromRaise &&
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
SelectTextFieldOnFocus()) {
|
2014-10-02 19:07:24 +00:00
|
|
|
nsIDocument* document = GetComposedDoc();
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
if (document) {
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t lastFocusMethod;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
fm->GetLastFocusMethod(document->GetWindow(), &lastFocusMethod);
|
2009-08-26 16:19:41 +00:00
|
|
|
if (lastFocusMethod &
|
|
|
|
(nsIFocusManager::FLAG_BYKEY | nsIFocusManager::FLAG_BYMOVEFOCUS)) {
|
2014-08-22 20:11:27 +00:00
|
|
|
nsRefPtr<nsPresContext> presContext =
|
|
|
|
GetPresContext(eForComposedDoc);
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
if (DispatchSelectEvent(presContext)) {
|
|
|
|
SelectAll(presContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2006-03-07 17:08:51 +00:00
|
|
|
}
|
2002-11-30 00:01:21 +00:00
|
|
|
|
|
|
|
case NS_KEY_PRESS:
|
|
|
|
case NS_KEY_UP:
|
|
|
|
{
|
|
|
|
// For backwards compat, trigger checks/radios/buttons with
|
|
|
|
// space or enter (bug 25300)
|
2013-10-18 06:10:24 +00:00
|
|
|
WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
|
2006-03-07 17:08:51 +00:00
|
|
|
if ((aVisitor.mEvent->message == NS_KEY_PRESS &&
|
2002-11-30 00:01:21 +00:00
|
|
|
keyEvent->keyCode == NS_VK_RETURN) ||
|
2006-03-07 17:08:51 +00:00
|
|
|
(aVisitor.mEvent->message == NS_KEY_UP &&
|
2002-11-30 00:01:21 +00:00
|
|
|
keyEvent->keyCode == NS_VK_SPACE)) {
|
2002-12-17 04:31:21 +00:00
|
|
|
switch(mType) {
|
2002-11-30 00:01:21 +00:00
|
|
|
case NS_FORM_INPUT_CHECKBOX:
|
|
|
|
case NS_FORM_INPUT_RADIO:
|
|
|
|
{
|
|
|
|
// Checkbox and Radio try to submit on Enter press
|
|
|
|
if (keyEvent->keyCode != NS_VK_SPACE) {
|
2006-03-07 17:08:51 +00:00
|
|
|
MaybeSubmitForm(aVisitor.mPresContext);
|
2004-01-05 23:39:50 +00:00
|
|
|
|
2002-11-30 00:01:21 +00:00
|
|
|
break; // If we are submitting, do not send click event
|
2001-08-16 07:38:47 +00:00
|
|
|
}
|
2002-11-30 00:01:21 +00:00
|
|
|
// else fall through and treat Space like click...
|
2001-08-16 07:38:47 +00:00
|
|
|
}
|
2002-11-30 00:01:21 +00:00
|
|
|
case NS_FORM_INPUT_BUTTON:
|
|
|
|
case NS_FORM_INPUT_RESET:
|
|
|
|
case NS_FORM_INPUT_SUBMIT:
|
|
|
|
case NS_FORM_INPUT_IMAGE: // Bug 34418
|
2013-07-09 22:25:27 +00:00
|
|
|
case NS_FORM_INPUT_COLOR:
|
2002-11-30 00:01:21 +00:00
|
|
|
{
|
2013-10-02 06:38:27 +00:00
|
|
|
WidgetMouseEvent event(aVisitor.mEvent->mFlags.mIsTrusted,
|
|
|
|
NS_MOUSE_CLICK, nullptr,
|
|
|
|
WidgetMouseEvent::eReal);
|
2011-08-26 07:43:56 +00:00
|
|
|
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
|
2002-11-30 00:01:21 +00:00
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
2005-04-28 23:48:28 +00:00
|
|
|
|
2014-03-18 04:48:21 +00:00
|
|
|
EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
|
|
|
|
aVisitor.mPresContext, &event,
|
|
|
|
nullptr, &status);
|
2010-12-27 20:42:10 +00:00
|
|
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
2002-11-30 00:01:21 +00:00
|
|
|
} // case
|
|
|
|
} // switch
|
|
|
|
}
|
2006-03-07 17:08:51 +00:00
|
|
|
if (aVisitor.mEvent->message == NS_KEY_PRESS &&
|
2012-04-25 03:00:02 +00:00
|
|
|
mType == NS_FORM_INPUT_RADIO && !keyEvent->IsAlt() &&
|
|
|
|
!keyEvent->IsControl() && !keyEvent->IsMeta()) {
|
2011-09-29 06:19:26 +00:00
|
|
|
bool isMovingBack = false;
|
2004-07-05 01:31:30 +00:00
|
|
|
switch (keyEvent->keyCode) {
|
2013-03-28 19:41:32 +00:00
|
|
|
case NS_VK_UP:
|
2004-07-05 01:31:30 +00:00
|
|
|
case NS_VK_LEFT:
|
2011-10-17 14:59:28 +00:00
|
|
|
isMovingBack = true;
|
2010-12-20 03:44:00 +00:00
|
|
|
// FALLTHROUGH
|
2004-07-05 01:31:30 +00:00
|
|
|
case NS_VK_DOWN:
|
|
|
|
case NS_VK_RIGHT:
|
|
|
|
// Arrow key pressed, focus+select prev/next radio button
|
2011-05-04 12:49:59 +00:00
|
|
|
nsIRadioGroupContainer* container = GetRadioGroupContainer();
|
2004-07-05 01:31:30 +00:00
|
|
|
if (container) {
|
|
|
|
nsAutoString name;
|
2011-05-04 12:49:59 +00:00
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
2013-08-10 01:17:51 +00:00
|
|
|
nsRefPtr<HTMLInputElement> selectedRadioButton;
|
2011-05-04 12:49:59 +00:00
|
|
|
container->GetNextRadioButton(name, isMovingBack, this,
|
|
|
|
getter_AddRefs(selectedRadioButton));
|
2013-08-10 01:17:51 +00:00
|
|
|
if (selectedRadioButton) {
|
|
|
|
rv = selectedRadioButton->Focus();
|
2011-05-04 12:49:59 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
2013-10-02 06:38:27 +00:00
|
|
|
WidgetMouseEvent event(aVisitor.mEvent->mFlags.mIsTrusted,
|
|
|
|
NS_MOUSE_CLICK, nullptr,
|
|
|
|
WidgetMouseEvent::eReal);
|
2011-08-26 07:43:56 +00:00
|
|
|
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
|
2014-03-18 04:48:21 +00:00
|
|
|
rv =
|
|
|
|
EventDispatcher::Dispatch(ToSupports(selectedRadioButton),
|
|
|
|
aVisitor.mPresContext,
|
|
|
|
&event, nullptr, &status);
|
2004-07-05 01:31:30 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2011-05-04 12:49:59 +00:00
|
|
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
2004-07-05 01:31:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-06-04 00:44:04 +00:00
|
|
|
|
2002-11-30 00:01:21 +00:00
|
|
|
/*
|
2011-04-13 19:43:34 +00:00
|
|
|
* For some input types, if the user hits enter, the form is submitted.
|
2002-11-30 00:01:21 +00:00
|
|
|
*
|
|
|
|
* Bug 99920, bug 109463 and bug 147850:
|
2002-12-17 04:31:21 +00:00
|
|
|
* (a) if there is a submit control in the form, click the first
|
|
|
|
* submit control in the form.
|
|
|
|
* (b) if there is just one text control in the form, submit by
|
|
|
|
* sending a submit event directly to the form
|
2002-11-30 00:01:21 +00:00
|
|
|
* (c) if there is more than one text input and no submit buttons, do
|
|
|
|
* not submit, period.
|
|
|
|
*/
|
|
|
|
|
2006-03-07 17:08:51 +00:00
|
|
|
if (aVisitor.mEvent->message == NS_KEY_PRESS &&
|
2014-02-15 00:57:39 +00:00
|
|
|
keyEvent->keyCode == NS_VK_RETURN &&
|
2012-06-10 20:23:17 +00:00
|
|
|
(IsSingleLineTextControl(false, mType) ||
|
2013-10-16 14:39:45 +00:00
|
|
|
mType == NS_FORM_INPUT_NUMBER ||
|
2013-01-31 23:01:50 +00:00
|
|
|
IsExperimentalMobileType(mType))) {
|
2013-01-31 23:05:48 +00:00
|
|
|
FireChangeEventIfNeeded();
|
2011-04-13 19:43:34 +00:00
|
|
|
rv = MaybeSubmitForm(aVisitor.mPresContext);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-06-04 00:44:04 +00:00
|
|
|
}
|
|
|
|
|
2013-03-01 15:34:06 +00:00
|
|
|
if (aVisitor.mEvent->message == NS_KEY_PRESS &&
|
|
|
|
mType == NS_FORM_INPUT_RANGE && !keyEvent->IsAlt() &&
|
|
|
|
!keyEvent->IsControl() && !keyEvent->IsMeta() &&
|
|
|
|
(keyEvent->keyCode == NS_VK_LEFT ||
|
|
|
|
keyEvent->keyCode == NS_VK_RIGHT ||
|
|
|
|
keyEvent->keyCode == NS_VK_UP ||
|
|
|
|
keyEvent->keyCode == NS_VK_DOWN ||
|
|
|
|
keyEvent->keyCode == NS_VK_PAGE_UP ||
|
|
|
|
keyEvent->keyCode == NS_VK_PAGE_DOWN ||
|
|
|
|
keyEvent->keyCode == NS_VK_HOME ||
|
|
|
|
keyEvent->keyCode == NS_VK_END)) {
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal minimum = GetMinimum();
|
|
|
|
Decimal maximum = GetMaximum();
|
|
|
|
MOZ_ASSERT(minimum.isFinite() && maximum.isFinite());
|
2013-03-01 15:34:06 +00:00
|
|
|
if (minimum < maximum) { // else the value is locked to the minimum
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal value = GetValueAsDecimal();
|
|
|
|
Decimal step = GetStep();
|
2013-03-01 15:34:06 +00:00
|
|
|
if (step == kStepAny) {
|
|
|
|
step = GetDefaultStep();
|
|
|
|
}
|
2013-05-05 23:23:18 +00:00
|
|
|
MOZ_ASSERT(value.isFinite() && step.isFinite());
|
|
|
|
Decimal newValue;
|
2013-03-01 15:34:06 +00:00
|
|
|
switch (keyEvent->keyCode) {
|
|
|
|
case NS_VK_LEFT:
|
2013-08-13 11:21:05 +00:00
|
|
|
newValue = value + (GetComputedDirectionality() == eDir_RTL
|
|
|
|
? step : -step);
|
2013-03-01 15:34:06 +00:00
|
|
|
break;
|
|
|
|
case NS_VK_RIGHT:
|
2013-08-13 11:21:05 +00:00
|
|
|
newValue = value + (GetComputedDirectionality() == eDir_RTL
|
|
|
|
? -step : step);
|
2013-03-01 15:34:06 +00:00
|
|
|
break;
|
|
|
|
case NS_VK_UP:
|
|
|
|
// Even for horizontal range, "up" means "increase"
|
|
|
|
newValue = value + step;
|
|
|
|
break;
|
|
|
|
case NS_VK_DOWN:
|
|
|
|
// Even for horizontal range, "down" means "decrease"
|
|
|
|
newValue = value - step;
|
|
|
|
break;
|
|
|
|
case NS_VK_HOME:
|
|
|
|
newValue = minimum;
|
|
|
|
break;
|
|
|
|
case NS_VK_END:
|
|
|
|
newValue = maximum;
|
|
|
|
break;
|
|
|
|
case NS_VK_PAGE_UP:
|
|
|
|
// For PgUp/PgDn we jump 10% of the total range, unless step
|
|
|
|
// requires us to jump more.
|
2014-06-07 03:17:06 +00:00
|
|
|
newValue = value + std::max(step, (maximum - minimum) / Decimal(10));
|
2013-03-01 15:34:06 +00:00
|
|
|
break;
|
|
|
|
case NS_VK_PAGE_DOWN:
|
2014-06-07 03:17:06 +00:00
|
|
|
newValue = value - std::max(step, (maximum - minimum) / Decimal(10));
|
2013-03-01 15:34:06 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-03-09 14:12:06 +00:00
|
|
|
SetValueOfRangeForUserEvent(newValue);
|
2013-03-01 15:34:06 +00:00
|
|
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-30 00:01:21 +00:00
|
|
|
} break; // NS_KEY_PRESS || NS_KEY_UP
|
|
|
|
|
2006-11-16 21:35:39 +00:00
|
|
|
case NS_MOUSE_BUTTON_DOWN:
|
|
|
|
case NS_MOUSE_BUTTON_UP:
|
|
|
|
case NS_MOUSE_DOUBLECLICK:
|
2002-11-30 00:01:21 +00:00
|
|
|
{
|
2006-11-16 21:35:39 +00:00
|
|
|
// cancel all of these events for buttons
|
|
|
|
//XXXsmaug Why?
|
2013-10-22 08:55:20 +00:00
|
|
|
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
|
|
|
if (mouseEvent->button == WidgetMouseEvent::eMiddleButton ||
|
|
|
|
mouseEvent->button == WidgetMouseEvent::eRightButton) {
|
2006-11-16 21:35:39 +00:00
|
|
|
if (mType == NS_FORM_INPUT_BUTTON ||
|
|
|
|
mType == NS_FORM_INPUT_RESET ||
|
|
|
|
mType == NS_FORM_INPUT_SUBMIT) {
|
|
|
|
if (aVisitor.mDOMEvent) {
|
|
|
|
aVisitor.mDOMEvent->StopPropagation();
|
|
|
|
} else {
|
|
|
|
rv = NS_ERROR_FAILURE;
|
|
|
|
}
|
2002-11-30 00:01:21 +00:00
|
|
|
}
|
2013-12-01 13:49:10 +00:00
|
|
|
}
|
|
|
|
if (mType == NS_FORM_INPUT_NUMBER &&
|
|
|
|
aVisitor.mEvent->mFlags.mIsTrusted) {
|
|
|
|
if (mouseEvent->button == WidgetMouseEvent::eLeftButton &&
|
|
|
|
!(mouseEvent->IsShift() || mouseEvent->IsControl() ||
|
|
|
|
mouseEvent->IsAlt() || mouseEvent->IsMeta() ||
|
|
|
|
mouseEvent->IsAltGraph() || mouseEvent->IsFn() ||
|
|
|
|
mouseEvent->IsOS())) {
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame) {
|
2014-04-13 18:42:40 +00:00
|
|
|
if (aVisitor.mEvent->message == NS_MOUSE_BUTTON_DOWN &&
|
|
|
|
IsMutable()) {
|
2013-12-01 13:49:10 +00:00
|
|
|
switch (numberControlFrame->GetSpinButtonForPointerEvent(
|
|
|
|
aVisitor.mEvent->AsMouseEvent())) {
|
|
|
|
case nsNumberControlFrame::eSpinButtonUp:
|
2013-12-05 16:20:33 +00:00
|
|
|
StepNumberControlForUserEvent(1);
|
2013-12-01 13:49:10 +00:00
|
|
|
mNumberControlSpinnerSpinsUp = true;
|
|
|
|
StartNumberControlSpinnerSpin();
|
|
|
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
|
|
|
break;
|
|
|
|
case nsNumberControlFrame::eSpinButtonDown:
|
2013-12-05 16:20:33 +00:00
|
|
|
StepNumberControlForUserEvent(-1);
|
2013-12-01 13:49:10 +00:00
|
|
|
mNumberControlSpinnerSpinsUp = false;
|
|
|
|
StartNumberControlSpinnerSpin();
|
|
|
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
|
|
|
|
// We didn't handle this to step up/down. Whatever this was, be
|
|
|
|
// aggressive about stopping the spin. (And don't set
|
|
|
|
// nsEventStatus_eConsumeNoDefault after doing so, since that
|
|
|
|
// might prevent, say, the context menu from opening.)
|
|
|
|
StopNumberControlSpinnerSpin();
|
|
|
|
}
|
2006-11-16 21:35:39 +00:00
|
|
|
}
|
2002-11-30 00:01:21 +00:00
|
|
|
break;
|
|
|
|
}
|
2006-03-07 17:08:51 +00:00
|
|
|
default:
|
|
|
|
break;
|
2004-05-17 22:05:41 +00:00
|
|
|
}
|
|
|
|
|
2005-01-11 03:21:23 +00:00
|
|
|
if (outerActivateEvent) {
|
2004-05-17 22:05:41 +00:00
|
|
|
if (mForm && (oldType == NS_FORM_INPUT_SUBMIT ||
|
|
|
|
oldType == NS_FORM_INPUT_IMAGE)) {
|
|
|
|
if (mType != NS_FORM_INPUT_SUBMIT && mType != NS_FORM_INPUT_IMAGE) {
|
|
|
|
// If the type has changed to a non-submit type, then we want to
|
|
|
|
// flush the stored submission if there is one (as if the submit()
|
|
|
|
// was allowed to succeed)
|
|
|
|
mForm->FlushPendingSubmission();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch(mType) {
|
|
|
|
case NS_FORM_INPUT_RESET:
|
|
|
|
case NS_FORM_INPUT_SUBMIT:
|
|
|
|
case NS_FORM_INPUT_IMAGE:
|
|
|
|
if (mForm) {
|
2013-09-27 06:20:55 +00:00
|
|
|
InternalFormEvent event(true,
|
|
|
|
(mType == NS_FORM_INPUT_RESET) ? NS_FORM_RESET : NS_FORM_SUBMIT);
|
2004-05-17 22:05:41 +00:00
|
|
|
event.originator = this;
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
|
2007-03-26 05:38:22 +00:00
|
|
|
nsCOMPtr<nsIPresShell> presShell =
|
|
|
|
aVisitor.mPresContext->GetPresShell();
|
2004-05-17 22:05:41 +00:00
|
|
|
|
|
|
|
// If |nsIPresShell::Destroy| has been called due to
|
2006-03-07 17:08:51 +00:00
|
|
|
// handling the event the pres context will return a null
|
|
|
|
// pres shell. See bug 125624.
|
2010-09-11 04:07:41 +00:00
|
|
|
// TODO: removing this code and have the submit event sent by the
|
|
|
|
// form, see bug 592124.
|
|
|
|
if (presShell && (event.message != NS_FORM_SUBMIT ||
|
2010-09-11 04:11:58 +00:00
|
|
|
mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) ||
|
2010-09-14 23:38:07 +00:00
|
|
|
// We know the element is a submit control, if this check is moved,
|
|
|
|
// make sure formnovalidate is used only if it's a submit control.
|
|
|
|
HasAttr(kNameSpaceID_None, nsGkAtoms::formnovalidate) ||
|
2010-09-11 04:07:41 +00:00
|
|
|
mForm->CheckValidFormSubmission())) {
|
2009-10-30 01:49:11 +00:00
|
|
|
// Hold a strong ref while dispatching
|
2013-06-19 14:24:37 +00:00
|
|
|
nsRefPtr<mozilla::dom::HTMLFormElement> form(mForm);
|
2009-10-30 01:49:11 +00:00
|
|
|
presShell->HandleDOMEventWithTarget(mForm, &event, &status);
|
2010-12-27 20:42:10 +00:00
|
|
|
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
2002-12-17 04:31:21 +00:00
|
|
|
}
|
|
|
|
}
|
2004-05-17 22:05:41 +00:00
|
|
|
break;
|
2000-05-30 02:45:55 +00:00
|
|
|
|
2004-05-17 22:05:41 +00:00
|
|
|
default:
|
|
|
|
break;
|
2013-03-28 19:41:32 +00:00
|
|
|
} //switch
|
2004-05-17 22:05:41 +00:00
|
|
|
} //click or outer activate event
|
2006-03-07 17:08:51 +00:00
|
|
|
} else if (outerActivateEvent &&
|
|
|
|
(oldType == NS_FORM_INPUT_SUBMIT ||
|
|
|
|
oldType == NS_FORM_INPUT_IMAGE) &&
|
|
|
|
mForm) {
|
|
|
|
// tell the form to flush a possible pending submission.
|
|
|
|
// the reason is that the script returned false (the event was
|
|
|
|
// not ignored) so if there is a stored submission, it needs to
|
|
|
|
// be submitted immediately.
|
|
|
|
mForm->FlushPendingSubmission();
|
|
|
|
}
|
2000-01-11 20:33:36 +00:00
|
|
|
} // if
|
1999-07-26 15:02:19 +00:00
|
|
|
|
2013-03-08 09:40:12 +00:00
|
|
|
if (NS_SUCCEEDED(rv) && mType == NS_FORM_INPUT_RANGE) {
|
|
|
|
PostHandleEventForRangeThumb(aVisitor);
|
|
|
|
}
|
|
|
|
|
2013-08-02 11:40:49 +00:00
|
|
|
return MaybeInitPickers(aVisitor);
|
1998-09-01 01:27:08 +00:00
|
|
|
}
|
|
|
|
|
2013-03-08 09:40:12 +00:00
|
|
|
void
|
2014-03-18 04:48:20 +00:00
|
|
|
HTMLInputElement::PostHandleEventForRangeThumb(EventChainPostVisitor& aVisitor)
|
2013-03-08 09:40:12 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(mType == NS_FORM_INPUT_RANGE);
|
|
|
|
|
|
|
|
if (nsEventStatus_eConsumeNoDefault == aVisitor.mEventStatus ||
|
2014-08-04 05:28:50 +00:00
|
|
|
!(aVisitor.mEvent->mClass == eMouseEventClass ||
|
2014-08-04 05:28:53 +00:00
|
|
|
aVisitor.mEvent->mClass == eTouchEventClass ||
|
2014-08-04 05:28:48 +00:00
|
|
|
aVisitor.mEvent->mClass == eKeyboardEventClass)) {
|
2013-03-08 09:40:12 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (!rangeFrame && mIsDraggingRange) {
|
|
|
|
CancelRangeThumbDrag();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (aVisitor.mEvent->message)
|
|
|
|
{
|
|
|
|
case NS_MOUSE_BUTTON_DOWN:
|
|
|
|
case NS_TOUCH_START: {
|
|
|
|
if (mIsDraggingRange) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (nsIPresShell::GetCapturingContent()) {
|
|
|
|
break; // don't start drag if someone else is already capturing
|
|
|
|
}
|
2013-10-18 06:10:26 +00:00
|
|
|
WidgetInputEvent* inputEvent = aVisitor.mEvent->AsInputEvent();
|
2013-03-08 09:40:12 +00:00
|
|
|
if (inputEvent->IsShift() || inputEvent->IsControl() ||
|
|
|
|
inputEvent->IsAlt() || inputEvent->IsMeta() ||
|
|
|
|
inputEvent->IsAltGraph() || inputEvent->IsFn() ||
|
|
|
|
inputEvent->IsOS()) {
|
|
|
|
break; // ignore
|
|
|
|
}
|
|
|
|
if (aVisitor.mEvent->message == NS_MOUSE_BUTTON_DOWN) {
|
2013-10-22 08:55:20 +00:00
|
|
|
if (aVisitor.mEvent->AsMouseEvent()->buttons ==
|
|
|
|
WidgetMouseEvent::eLeftButtonFlag) {
|
2013-03-08 09:40:12 +00:00
|
|
|
StartRangeThumbDrag(inputEvent);
|
|
|
|
} else if (mIsDraggingRange) {
|
|
|
|
CancelRangeThumbDrag();
|
|
|
|
}
|
|
|
|
} else {
|
2013-10-18 06:10:23 +00:00
|
|
|
if (aVisitor.mEvent->AsTouchEvent()->touches.Length() == 1) {
|
2013-03-08 09:40:12 +00:00
|
|
|
StartRangeThumbDrag(inputEvent);
|
|
|
|
} else if (mIsDraggingRange) {
|
|
|
|
CancelRangeThumbDrag();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NS_MOUSE_MOVE:
|
|
|
|
case NS_TOUCH_MOVE:
|
|
|
|
if (!mIsDraggingRange) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (nsIPresShell::GetCapturingContent() != this) {
|
|
|
|
// Someone else grabbed capture.
|
|
|
|
CancelRangeThumbDrag();
|
|
|
|
break;
|
|
|
|
}
|
2013-10-01 07:23:02 +00:00
|
|
|
SetValueOfRangeForUserEvent(
|
2013-10-18 06:10:26 +00:00
|
|
|
rangeFrame->GetValueAtEventPoint(aVisitor.mEvent->AsInputEvent()));
|
2013-03-08 09:40:12 +00:00
|
|
|
aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_MOUSE_BUTTON_UP:
|
|
|
|
case NS_TOUCH_END:
|
|
|
|
if (!mIsDraggingRange) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// We don't check to see whether we are the capturing content here and
|
|
|
|
// call CancelRangeThumbDrag() if that is the case. We just finish off
|
|
|
|
// the drag and set our final value (unless someone has called
|
|
|
|
// preventDefault() and prevents us getting here).
|
2013-10-18 06:10:26 +00:00
|
|
|
FinishRangeThumbDrag(aVisitor.mEvent->AsInputEvent());
|
2013-03-08 09:40:12 +00:00
|
|
|
aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_KEY_PRESS:
|
|
|
|
if (mIsDraggingRange &&
|
2013-10-18 06:10:24 +00:00
|
|
|
aVisitor.mEvent->AsKeyboardEvent()->keyCode == NS_VK_ESCAPE) {
|
2013-03-08 09:40:12 +00:00
|
|
|
CancelRangeThumbDrag();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NS_TOUCH_CANCEL:
|
|
|
|
if (mIsDraggingRange) {
|
|
|
|
CancelRangeThumbDrag();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-20 08:00:04 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::MaybeLoadImage()
|
2009-05-20 08:00:04 +00:00
|
|
|
{
|
|
|
|
// Our base URI may have changed; claim that our URI changed, and the
|
|
|
|
// nsImageLoadingContent will decide whether a new image load is warranted.
|
|
|
|
nsAutoString uri;
|
|
|
|
if (mType == NS_FORM_INPUT_IMAGE &&
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::src, uri) &&
|
2014-08-19 21:49:38 +00:00
|
|
|
(NS_FAILED(LoadImage(uri, false, true, eImageLoadType_Normal)) ||
|
2009-05-20 08:00:04 +00:00
|
|
|
!LoadingEnabled())) {
|
2011-10-17 14:59:28 +00:00
|
|
|
CancelImageRequests(true);
|
2009-05-20 08:00:04 +00:00
|
|
|
}
|
|
|
|
}
|
1999-07-26 15:02:19 +00:00
|
|
|
|
2005-04-05 23:54:35 +00:00
|
|
|
nsresult
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|
|
|
nsIContent* aBindingParent,
|
|
|
|
bool aCompileEventHandlers)
|
2002-07-20 23:09:24 +00:00
|
|
|
{
|
2013-08-02 01:21:31 +00:00
|
|
|
nsresult rv = nsGenericHTMLFormElementWithState::BindToTree(aDocument, aParent,
|
|
|
|
aBindingParent,
|
|
|
|
aCompileEventHandlers);
|
2005-04-05 23:54:35 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2003-07-24 17:10:14 +00:00
|
|
|
|
2012-08-13 22:11:50 +00:00
|
|
|
nsImageLoadingContent::BindToTree(aDocument, aParent, aBindingParent,
|
|
|
|
aCompileEventHandlers);
|
|
|
|
|
2005-04-05 23:54:35 +00:00
|
|
|
if (mType == NS_FORM_INPUT_IMAGE) {
|
2003-07-24 17:10:14 +00:00
|
|
|
// Our base URI may have changed; claim that our URI changed, and the
|
|
|
|
// nsImageLoadingContent will decide whether a new image load is warranted.
|
2009-05-20 08:00:04 +00:00
|
|
|
if (HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
|
2011-06-01 01:46:57 +00:00
|
|
|
// FIXME: Bug 660963 it would be nice if we could just have
|
|
|
|
// ClearBrokenState update our state and do it fast...
|
2009-05-20 08:00:04 +00:00
|
|
|
ClearBrokenState();
|
2011-06-01 01:46:57 +00:00
|
|
|
RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
|
2009-05-20 08:00:04 +00:00
|
|
|
nsContentUtils::AddScriptRunner(
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_NewRunnableMethod(this, &HTMLInputElement::MaybeLoadImage));
|
2003-07-24 17:10:14 +00:00
|
|
|
}
|
|
|
|
}
|
2005-04-05 23:54:35 +00:00
|
|
|
|
2002-07-20 23:09:24 +00:00
|
|
|
// Add radio to document if we don't have a form already (if we do it's
|
|
|
|
// already been added into that group)
|
|
|
|
if (aDocument && !mForm && mType == NS_FORM_INPUT_RADIO) {
|
|
|
|
AddedToRadioGroup();
|
|
|
|
}
|
2005-04-05 23:54:35 +00:00
|
|
|
|
2012-11-21 10:13:57 +00:00
|
|
|
// Set direction based on value if dir=auto
|
|
|
|
SetDirectionIfAuto(HasDirAuto(), false);
|
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
// An element can't suffer from value missing if it is not in a document.
|
|
|
|
// We have to check if we suffer from that as we are now in a document.
|
|
|
|
UpdateValueMissingValidityState();
|
|
|
|
|
2010-09-18 21:33:16 +00:00
|
|
|
// If there is a disabled fieldset in the parent chain, the element is now
|
|
|
|
// barred from constraint validation and can't suffer from value missing
|
|
|
|
// (call done before).
|
|
|
|
UpdateBarredFromConstraintValidation();
|
|
|
|
|
2011-06-01 01:46:57 +00:00
|
|
|
// And now make sure our state is up to date
|
|
|
|
UpdateState(false);
|
|
|
|
|
2005-04-05 23:54:35 +00:00
|
|
|
return rv;
|
2002-07-20 23:09:24 +00:00
|
|
|
}
|
|
|
|
|
2004-01-09 23:54:21 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
2003-07-24 17:10:14 +00:00
|
|
|
{
|
2005-04-05 23:54:35 +00:00
|
|
|
// If we have a form and are unbound from it,
|
2013-08-02 01:21:31 +00:00
|
|
|
// nsGenericHTMLFormElementWithState::UnbindFromTree() will unset the form and
|
2005-04-05 23:54:35 +00:00
|
|
|
// that takes care of form's WillRemove so we just have to take care
|
|
|
|
// of the case where we're removing from the document and we don't
|
|
|
|
// have a form
|
|
|
|
if (!mForm && mType == NS_FORM_INPUT_RADIO) {
|
2010-11-11 12:34:27 +00:00
|
|
|
WillRemoveFromRadioGroup();
|
2003-07-24 17:10:14 +00:00
|
|
|
}
|
2005-04-05 23:54:35 +00:00
|
|
|
|
2012-08-13 22:11:50 +00:00
|
|
|
nsImageLoadingContent::UnbindFromTree(aDeep, aNullParent);
|
2013-08-02 01:21:31 +00:00
|
|
|
nsGenericHTMLFormElementWithState::UnbindFromTree(aDeep, aNullParent);
|
2010-08-21 17:52:57 +00:00
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
// GetCurrentDoc is returning nullptr so we can update the value
|
2010-08-21 17:52:57 +00:00
|
|
|
// missing validity state to reflect we are no longer into a doc.
|
|
|
|
UpdateValueMissingValidityState();
|
2010-09-18 21:33:16 +00:00
|
|
|
// We might be no longer disabled because of parent chain changed.
|
|
|
|
UpdateBarredFromConstraintValidation();
|
2011-06-01 01:46:57 +00:00
|
|
|
|
|
|
|
// And now make sure our state is up to date
|
|
|
|
UpdateState(false);
|
2003-07-24 17:10:14 +00:00
|
|
|
}
|
|
|
|
|
2010-06-09 18:13:56 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::HandleTypeChange(uint8_t aNewType)
|
2010-06-09 18:13:56 +00:00
|
|
|
{
|
2013-03-08 09:40:12 +00:00
|
|
|
if (mType == NS_FORM_INPUT_RANGE && mIsDraggingRange) {
|
2013-03-16 05:49:41 +00:00
|
|
|
CancelRangeThumbDrag(false);
|
2013-03-08 09:40:12 +00:00
|
|
|
}
|
|
|
|
|
2010-09-14 00:23:03 +00:00
|
|
|
ValueModeType aOldValueMode = GetValueMode();
|
2013-02-12 20:16:58 +00:00
|
|
|
uint8_t oldType = mType;
|
2010-09-14 00:23:03 +00:00
|
|
|
nsAutoString aOldValue;
|
2010-09-20 20:33:17 +00:00
|
|
|
|
2013-02-12 20:16:58 +00:00
|
|
|
if (aOldValueMode == VALUE_MODE_VALUE) {
|
2010-09-20 20:33:17 +00:00
|
|
|
GetValue(aOldValue);
|
|
|
|
}
|
2010-09-14 00:23:03 +00:00
|
|
|
|
2013-02-12 20:16:58 +00:00
|
|
|
// We already have a copy of the value, lets free it and changes the type.
|
|
|
|
FreeData();
|
|
|
|
mType = aNewType;
|
2011-03-24 16:06:58 +00:00
|
|
|
|
2013-02-12 20:16:58 +00:00
|
|
|
if (IsSingleLineTextControl()) {
|
2010-06-09 18:13:56 +00:00
|
|
|
mInputData.mState = new nsTextEditorState(this);
|
|
|
|
}
|
|
|
|
|
2013-02-12 20:16:58 +00:00
|
|
|
/**
|
|
|
|
* The following code is trying to reproduce the algorithm described here:
|
|
|
|
* http://www.whatwg.org/specs/web-apps/current-work/complete.html#input-type-change
|
|
|
|
*/
|
|
|
|
switch (GetValueMode()) {
|
|
|
|
case VALUE_MODE_DEFAULT:
|
|
|
|
case VALUE_MODE_DEFAULT_ON:
|
|
|
|
// If the previous value mode was value, we need to set the value content
|
|
|
|
// attribute to the previous value.
|
|
|
|
// There is no value sanitizing algorithm for elements in this mode.
|
|
|
|
if (aOldValueMode == VALUE_MODE_VALUE && !aOldValue.IsEmpty()) {
|
|
|
|
SetAttr(kNameSpaceID_None, nsGkAtoms::value, aOldValue, true);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VALUE_MODE_VALUE:
|
|
|
|
// If the previous value mode wasn't value, we have to set the value to
|
|
|
|
// the value content attribute.
|
|
|
|
// SetValueInternal is going to sanitize the value.
|
|
|
|
{
|
|
|
|
nsAutoString value;
|
|
|
|
if (aOldValueMode != VALUE_MODE_VALUE) {
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::value, value);
|
|
|
|
} else {
|
|
|
|
value = aOldValue;
|
2010-09-20 20:33:17 +00:00
|
|
|
}
|
2015-01-08 01:14:01 +00:00
|
|
|
// TODO: What should we do if SetValueInternal fails? (The allocation
|
|
|
|
// may potentially be big, but most likely we've failed to allocate
|
|
|
|
// before the type change.)
|
2013-02-12 20:16:58 +00:00
|
|
|
SetValueInternal(value, false, false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VALUE_MODE_FILENAME:
|
|
|
|
default:
|
|
|
|
// We don't care about the value.
|
|
|
|
// There is no value sanitizing algorithm for elements in this mode.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Updating mFocusedValue in consequence:
|
2013-03-16 05:49:41 +00:00
|
|
|
// If the new type fires a change event on blur, but the previous type
|
|
|
|
// doesn't, we should set mFocusedValue to the current value.
|
|
|
|
// Otherwise, if the new type doesn't fire a change event on blur, but the
|
|
|
|
// previous type does, we should clear out mFocusedValue.
|
|
|
|
if (MayFireChangeOnBlur(mType) && !MayFireChangeOnBlur(oldType)) {
|
2014-01-30 10:45:46 +00:00
|
|
|
GetValue(mFocusedValue);
|
2013-02-12 20:16:58 +00:00
|
|
|
} else if (!IsSingleLineTextControl(mType, false) &&
|
|
|
|
IsSingleLineTextControl(oldType, false)) {
|
|
|
|
mFocusedValue.Truncate();
|
2010-07-21 00:11:19 +00:00
|
|
|
}
|
2010-08-21 17:52:57 +00:00
|
|
|
|
2012-06-22 09:41:32 +00:00
|
|
|
UpdateHasRange();
|
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
// Do not notify, it will be done after if needed.
|
2011-10-17 14:59:28 +00:00
|
|
|
UpdateAllValidityStates(false);
|
2010-07-21 00:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SanitizeValue(nsAString& aValue)
|
2010-07-21 00:11:19 +00:00
|
|
|
{
|
2011-11-16 07:50:19 +00:00
|
|
|
NS_ASSERTION(!mParserCreating, "The element parsing should be finished!");
|
2010-09-20 20:33:17 +00:00
|
|
|
|
2010-07-21 00:11:19 +00:00
|
|
|
switch (mType) {
|
|
|
|
case NS_FORM_INPUT_TEXT:
|
|
|
|
case NS_FORM_INPUT_SEARCH:
|
|
|
|
case NS_FORM_INPUT_TEL:
|
|
|
|
case NS_FORM_INPUT_PASSWORD:
|
|
|
|
{
|
2014-01-04 15:02:17 +00:00
|
|
|
char16_t crlf[] = { char16_t('\r'), char16_t('\n'), 0 };
|
2010-07-21 00:11:19 +00:00
|
|
|
aValue.StripChars(crlf);
|
|
|
|
}
|
|
|
|
break;
|
2011-08-22 12:58:01 +00:00
|
|
|
case NS_FORM_INPUT_EMAIL:
|
2010-08-18 18:34:14 +00:00
|
|
|
case NS_FORM_INPUT_URL:
|
|
|
|
{
|
2014-01-04 15:02:17 +00:00
|
|
|
char16_t crlf[] = { char16_t('\r'), char16_t('\n'), 0 };
|
2010-08-18 18:34:14 +00:00
|
|
|
aValue.StripChars(crlf);
|
|
|
|
|
|
|
|
aValue = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aValue);
|
|
|
|
}
|
|
|
|
break;
|
2012-06-10 20:24:03 +00:00
|
|
|
case NS_FORM_INPUT_NUMBER:
|
|
|
|
{
|
2013-12-01 13:49:09 +00:00
|
|
|
Decimal value;
|
|
|
|
bool ok = ConvertStringToNumber(aValue, value);
|
|
|
|
if (!ok) {
|
2012-06-10 20:24:03 +00:00
|
|
|
aValue.Truncate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2013-02-16 12:35:57 +00:00
|
|
|
case NS_FORM_INPUT_RANGE:
|
|
|
|
{
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal minimum = GetMinimum();
|
|
|
|
Decimal maximum = GetMaximum();
|
|
|
|
MOZ_ASSERT(minimum.isFinite() && maximum.isFinite(),
|
2013-02-16 12:35:57 +00:00
|
|
|
"type=range should have a default maximum/minimum");
|
|
|
|
|
|
|
|
// We use this to avoid modifying the string unnecessarily, since that
|
|
|
|
// may introduce rounding. This is set to true only if the value we
|
|
|
|
// parse out from aValue needs to be sanitized.
|
|
|
|
bool needSanitization = false;
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal value;
|
2013-02-16 12:35:57 +00:00
|
|
|
bool ok = ConvertStringToNumber(aValue, value);
|
|
|
|
if (!ok) {
|
|
|
|
needSanitization = true;
|
|
|
|
// Set value to midway between minimum and maximum.
|
2014-06-07 03:17:06 +00:00
|
|
|
value = maximum <= minimum ? minimum : minimum + (maximum - minimum)/Decimal(2);
|
2013-02-16 12:35:57 +00:00
|
|
|
} else if (value < minimum || maximum < minimum) {
|
|
|
|
needSanitization = true;
|
|
|
|
value = minimum;
|
|
|
|
} else if (value > maximum) {
|
|
|
|
needSanitization = true;
|
|
|
|
value = maximum;
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal step = GetStep();
|
2013-02-16 12:35:57 +00:00
|
|
|
if (step != kStepAny) {
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal stepBase = GetStepBase();
|
2013-02-16 12:35:57 +00:00
|
|
|
// There could be rounding issues below when dealing with fractional
|
|
|
|
// numbers, but let's ignore that until ECMAScript supplies us with a
|
|
|
|
// decimal number type.
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal deltaToStep = NS_floorModulo(value - stepBase, step);
|
2014-06-07 03:17:06 +00:00
|
|
|
if (deltaToStep != Decimal(0)) {
|
2013-02-16 12:35:57 +00:00
|
|
|
// "suffering from a step mismatch"
|
|
|
|
// Round the element's value to the nearest number for which the
|
|
|
|
// element would not suffer from a step mismatch, and which is
|
|
|
|
// greater than or equal to the minimum, and, if the maximum is not
|
|
|
|
// less than the minimum, which is less than or equal to the
|
|
|
|
// maximum, if there is a number that matches these constraints:
|
2014-06-07 03:17:06 +00:00
|
|
|
MOZ_ASSERT(deltaToStep > Decimal(0), "stepBelow/stepAbove will be wrong");
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal stepBelow = value - deltaToStep;
|
|
|
|
Decimal stepAbove = value - deltaToStep + step;
|
2014-06-07 03:17:06 +00:00
|
|
|
Decimal halfStep = step / Decimal(2);
|
2013-02-16 12:35:57 +00:00
|
|
|
bool stepAboveIsClosest = (stepAbove - value) <= halfStep;
|
|
|
|
bool stepAboveInRange = stepAbove >= minimum &&
|
|
|
|
stepAbove <= maximum;
|
|
|
|
bool stepBelowInRange = stepBelow >= minimum &&
|
|
|
|
stepBelow <= maximum;
|
|
|
|
|
|
|
|
if ((stepAboveIsClosest || !stepBelowInRange) && stepAboveInRange) {
|
|
|
|
needSanitization = true;
|
|
|
|
value = stepAbove;
|
|
|
|
} else if ((!stepAboveIsClosest || !stepAboveInRange) && stepBelowInRange) {
|
|
|
|
needSanitization = true;
|
|
|
|
value = stepBelow;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (needSanitization) {
|
2013-05-05 23:23:18 +00:00
|
|
|
char buf[32];
|
|
|
|
DebugOnly<bool> ok = value.toString(buf, ArrayLength(buf));
|
|
|
|
aValue.AssignASCII(buf);
|
|
|
|
MOZ_ASSERT(ok, "buf not big enough");
|
2013-02-16 12:35:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2012-12-27 18:48:13 +00:00
|
|
|
case NS_FORM_INPUT_DATE:
|
|
|
|
{
|
|
|
|
if (!aValue.IsEmpty() && !IsValidDate(aValue)) {
|
|
|
|
aValue.Truncate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2013-01-11 15:00:52 +00:00
|
|
|
case NS_FORM_INPUT_TIME:
|
|
|
|
{
|
|
|
|
if (!aValue.IsEmpty() && !IsValidTime(aValue)) {
|
|
|
|
aValue.Truncate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2013-05-23 13:02:23 +00:00
|
|
|
case NS_FORM_INPUT_COLOR:
|
|
|
|
{
|
|
|
|
if (IsValidSimpleColor(aValue)) {
|
|
|
|
ToLowerCase(aValue);
|
|
|
|
} else {
|
|
|
|
// Set default (black) color, if aValue wasn't parsed correctly.
|
|
|
|
aValue.AssignLiteral("#000000");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool HTMLInputElement::IsValidSimpleColor(const nsAString& aValue) const
|
|
|
|
{
|
|
|
|
if (aValue.Length() != 7 || aValue.First() != '#') {
|
|
|
|
return false;
|
2012-12-27 18:48:13 +00:00
|
|
|
}
|
2013-05-23 13:02:23 +00:00
|
|
|
|
|
|
|
for (int i = 1; i < 7; ++i) {
|
|
|
|
if (!nsCRT::IsAsciiDigit(aValue[i]) &&
|
|
|
|
!(aValue[i] >= 'a' && aValue[i] <= 'f') &&
|
|
|
|
!(aValue[i] >= 'A' && aValue[i] <= 'F')) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2012-12-27 18:48:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsValidDate(const nsAString& aValue) const
|
2012-12-27 18:48:13 +00:00
|
|
|
{
|
2012-12-27 18:55:31 +00:00
|
|
|
uint32_t year, month, day;
|
2013-01-11 15:02:58 +00:00
|
|
|
return GetValueAsDate(aValue, &year, &month, &day);
|
2012-12-27 18:55:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetValueAsDate(const nsAString& aValue,
|
|
|
|
uint32_t* aYear,
|
|
|
|
uint32_t* aMonth,
|
|
|
|
uint32_t* aDay) const
|
2012-12-27 18:55:31 +00:00
|
|
|
{
|
|
|
|
|
2012-12-27 18:48:13 +00:00
|
|
|
/*
|
2013-01-11 15:02:58 +00:00
|
|
|
* Parse the year, month, day values out a date string formatted as 'yyyy-mm-dd'.
|
2012-12-27 18:48:13 +00:00
|
|
|
* -The year must be 4 or more digits long, and year > 0
|
|
|
|
* -The month must be exactly 2 digits long, and 01 <= month <= 12
|
|
|
|
* -The day must be exactly 2 digit long, and 01 <= day <= maxday
|
|
|
|
* Where maxday is the number of days in the month 'month' and year 'year'
|
|
|
|
*/
|
|
|
|
|
2013-01-11 15:02:58 +00:00
|
|
|
if (aValue.Length() < 10) {
|
2012-12-27 18:48:13 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-04-15 14:45:05 +00:00
|
|
|
uint32_t endOfYearOffset = aValue.Length() - 6;
|
|
|
|
|
|
|
|
if (aValue[endOfYearOffset] != '-' ||
|
|
|
|
aValue[endOfYearOffset + 3] != '-') {
|
2013-01-11 15:02:58 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-12-27 18:48:13 +00:00
|
|
|
|
2014-04-15 14:45:05 +00:00
|
|
|
if (!DigitSubStringToNumber(aValue, 0, endOfYearOffset, aYear) ||
|
|
|
|
*aYear < 1) {
|
2013-01-11 15:02:58 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-12-27 18:48:13 +00:00
|
|
|
|
2013-01-11 15:02:58 +00:00
|
|
|
if (!DigitSubStringToNumber(aValue, endOfYearOffset + 1, 2, aMonth) ||
|
|
|
|
*aMonth < 1 || *aMonth > 12) {
|
|
|
|
return false;
|
2010-07-21 00:11:19 +00:00
|
|
|
}
|
2012-12-27 18:48:13 +00:00
|
|
|
|
2013-01-11 15:02:58 +00:00
|
|
|
return DigitSubStringToNumber(aValue, endOfYearOffset + 4, 2, aDay) &&
|
|
|
|
*aDay > 0 && *aDay <= NumberOfDaysInMonth(*aMonth, *aYear);
|
2010-06-09 18:13:56 +00:00
|
|
|
}
|
|
|
|
|
2012-12-27 18:48:13 +00:00
|
|
|
uint32_t
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::NumberOfDaysInMonth(uint32_t aMonth, uint32_t aYear) const
|
2012-12-27 18:48:13 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Returns the number of days in a month.
|
|
|
|
* Months that are |longMonths| always have 31 days.
|
|
|
|
* Months that are not |longMonths| have 30 days except February (month 2).
|
|
|
|
* February has 29 days during leap years which are years that are divisible by 400.
|
|
|
|
* or divisible by 100 and 4. February has 28 days otherwise.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static const bool longMonths[] = { true, false, true, false, true, false,
|
|
|
|
true, true, false, true, false, true };
|
|
|
|
MOZ_ASSERT(aMonth <= 12 && aMonth > 0);
|
|
|
|
|
|
|
|
if (longMonths[aMonth-1]) {
|
|
|
|
return 31;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aMonth != 2) {
|
|
|
|
return 30;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (aYear % 400 == 0 || (aYear % 100 != 0 && aYear % 4 == 0))
|
|
|
|
? 29 : 28;
|
|
|
|
}
|
2013-01-11 15:00:52 +00:00
|
|
|
|
|
|
|
/* static */ bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::DigitSubStringToNumber(const nsAString& aStr,
|
|
|
|
uint32_t aStart, uint32_t aLen,
|
|
|
|
uint32_t* aRetVal)
|
2013-01-11 15:00:52 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(aStr.Length() > (aStart + aLen - 1));
|
|
|
|
|
|
|
|
for (uint32_t offset = 0; offset < aLen; ++offset) {
|
|
|
|
if (!NS_IsAsciiDigit(aStr[aStart + offset])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult ec;
|
|
|
|
*aRetVal = static_cast<uint32_t>(PromiseFlatString(Substring(aStr, aStart, aLen)).ToInteger(&ec));
|
|
|
|
|
|
|
|
return NS_SUCCEEDED(ec);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsValidTime(const nsAString& aValue) const
|
2013-01-22 18:22:33 +00:00
|
|
|
{
|
|
|
|
return ParseTime(aValue, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::ParseTime(const nsAString& aValue, uint32_t* aResult)
|
2013-01-11 15:00:52 +00:00
|
|
|
{
|
|
|
|
/* The string must have the following parts:
|
|
|
|
* - HOURS: two digits, value being in [0, 23];
|
|
|
|
* - Colon (:);
|
|
|
|
* - MINUTES: two digits, value being in [0, 59];
|
|
|
|
* - Optional:
|
|
|
|
* - Colon (:);
|
|
|
|
* - SECONDS: two digits, value being in [0, 59];
|
|
|
|
* - Optional:
|
|
|
|
* - DOT (.);
|
|
|
|
* - FRACTIONAL SECONDS: one to three digits, no value range.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// The following format is the shorter one allowed: "HH:MM".
|
|
|
|
if (aValue.Length() < 5) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t hours;
|
|
|
|
if (!DigitSubStringToNumber(aValue, 0, 2, &hours) || hours > 23) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hours/minutes separator.
|
|
|
|
if (aValue[2] != ':') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t minutes;
|
|
|
|
if (!DigitSubStringToNumber(aValue, 3, 2, &minutes) || minutes > 59) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aValue.Length() == 5) {
|
2013-01-22 18:22:33 +00:00
|
|
|
if (aResult) {
|
|
|
|
*aResult = ((hours * 60) + minutes) * 60000;
|
|
|
|
}
|
2013-01-11 15:00:52 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The following format is the next shorter one: "HH:MM:SS".
|
|
|
|
if (aValue.Length() < 8 || aValue[5] != ':') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t seconds;
|
|
|
|
if (!DigitSubStringToNumber(aValue, 6, 2, &seconds) || seconds > 59) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aValue.Length() == 8) {
|
2013-01-22 18:22:33 +00:00
|
|
|
if (aResult) {
|
|
|
|
*aResult = (((hours * 60) + minutes) * 60 + seconds) * 1000;
|
|
|
|
}
|
2013-01-11 15:00:52 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The string must follow this format now: "HH:MM:SS.{s,ss,sss}".
|
|
|
|
// There can be 1 to 3 digits for the fractions of seconds.
|
|
|
|
if (aValue.Length() == 9 || aValue.Length() > 12 || aValue[8] != '.') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t fractionsSeconds;
|
2013-01-22 18:22:33 +00:00
|
|
|
if (!DigitSubStringToNumber(aValue, 9, aValue.Length() - 9, &fractionsSeconds)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aResult) {
|
|
|
|
*aResult = (((hours * 60) + minutes) * 60 + seconds) * 1000 +
|
|
|
|
// NOTE: there is 10.0 instead of 10 and static_cast<int> because
|
|
|
|
// some old [and stupid] compilers can't just do the right thing.
|
|
|
|
fractionsSeconds * pow(10.0, static_cast<int>(3 - (aValue.Length() - 9)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2013-01-11 15:00:52 +00:00
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::ParseAttribute(int32_t aNamespaceID,
|
|
|
|
nsIAtom* aAttribute,
|
|
|
|
const nsAString& aValue,
|
|
|
|
nsAttrValue& aResult)
|
1998-09-01 01:27:08 +00:00
|
|
|
{
|
2005-11-29 16:37:15 +00:00
|
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aAttribute == nsGkAtoms::type) {
|
2005-11-29 16:37:15 +00:00
|
|
|
// XXX ARG!! This is major evilness. ParseAttribute
|
|
|
|
// shouldn't set members. Override SetAttr instead
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t newType;
|
2011-09-29 06:19:26 +00:00
|
|
|
bool success = aResult.ParseEnumValue(aValue, kInputTypeTable, false);
|
2010-04-15 11:03:00 +00:00
|
|
|
if (success) {
|
2007-07-25 04:29:47 +00:00
|
|
|
newType = aResult.GetEnumValue();
|
2013-02-16 12:35:57 +00:00
|
|
|
if ((IsExperimentalMobileType(newType) &&
|
|
|
|
!Preferences::GetBool("dom.experimental_forms", false)) ||
|
2013-09-12 18:11:00 +00:00
|
|
|
(newType == NS_FORM_INPUT_NUMBER &&
|
|
|
|
!Preferences::GetBool("dom.forms.number", false)) ||
|
2013-05-23 13:02:23 +00:00
|
|
|
(newType == NS_FORM_INPUT_COLOR &&
|
|
|
|
!Preferences::GetBool("dom.forms.color", false))) {
|
2012-06-23 12:32:54 +00:00
|
|
|
newType = kInputDefaultType->value;
|
2013-01-21 10:48:48 +00:00
|
|
|
aResult.SetTo(newType, &aValue);
|
|
|
|
}
|
2007-07-25 04:29:47 +00:00
|
|
|
} else {
|
2010-04-15 11:03:00 +00:00
|
|
|
newType = kInputDefaultType->value;
|
2005-11-29 16:37:15 +00:00
|
|
|
}
|
2004-03-04 02:06:28 +00:00
|
|
|
|
2008-08-25 17:21:28 +00:00
|
|
|
if (newType != mType) {
|
|
|
|
// Make sure to do the check for newType being NS_FORM_INPUT_FILE and
|
|
|
|
// the corresponding SetValueInternal() call _before_ we set mType.
|
|
|
|
// That way the logic in SetValueInternal() will work right (that logic
|
|
|
|
// makes assumptions about our frame based on mType, but we won't have
|
|
|
|
// had time to recreate frames yet -- that happens later in the
|
|
|
|
// SetAttr() process).
|
2009-10-27 18:14:34 +00:00
|
|
|
if (newType == NS_FORM_INPUT_FILE || mType == NS_FORM_INPUT_FILE) {
|
|
|
|
// This call isn't strictly needed any more since we'll never
|
|
|
|
// confuse values and filenames. However it's there for backwards
|
2008-08-25 17:21:28 +00:00
|
|
|
// compat.
|
2010-11-23 23:45:53 +00:00
|
|
|
ClearFiles(false);
|
2008-08-25 17:21:28 +00:00
|
|
|
}
|
2004-03-04 02:06:28 +00:00
|
|
|
|
2010-06-09 18:13:56 +00:00
|
|
|
HandleTypeChange(newType);
|
2008-08-25 17:21:28 +00:00
|
|
|
}
|
2006-02-09 16:34:06 +00:00
|
|
|
|
2007-07-25 04:29:47 +00:00
|
|
|
return success;
|
2005-11-29 16:37:15 +00:00
|
|
|
}
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aAttribute == nsGkAtoms::width) {
|
2011-02-04 19:46:16 +00:00
|
|
|
return aResult.ParseSpecialIntValue(aValue);
|
2005-11-29 16:37:15 +00:00
|
|
|
}
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aAttribute == nsGkAtoms::height) {
|
2011-02-04 19:46:16 +00:00
|
|
|
return aResult.ParseSpecialIntValue(aValue);
|
2005-11-29 16:37:15 +00:00
|
|
|
}
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aAttribute == nsGkAtoms::maxlength) {
|
2010-03-05 19:38:26 +00:00
|
|
|
return aResult.ParseNonNegativeIntValue(aValue);
|
2005-11-29 16:37:15 +00:00
|
|
|
}
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aAttribute == nsGkAtoms::size) {
|
2010-11-06 09:30:27 +00:00
|
|
|
return aResult.ParsePositiveIntValue(aValue);
|
2005-11-29 16:37:15 +00:00
|
|
|
}
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aAttribute == nsGkAtoms::border) {
|
2005-11-29 16:37:15 +00:00
|
|
|
return aResult.ParseIntWithBounds(aValue, 0);
|
|
|
|
}
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aAttribute == nsGkAtoms::align) {
|
2005-11-29 16:37:15 +00:00
|
|
|
return ParseAlignValue(aValue, aResult);
|
|
|
|
}
|
2010-08-20 17:47:30 +00:00
|
|
|
if (aAttribute == nsGkAtoms::formmethod) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return aResult.ParseEnumValue(aValue, kFormMethodTable, false);
|
2010-08-20 17:47:30 +00:00
|
|
|
}
|
|
|
|
if (aAttribute == nsGkAtoms::formenctype) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false);
|
2010-08-20 17:47:30 +00:00
|
|
|
}
|
2010-09-14 17:58:34 +00:00
|
|
|
if (aAttribute == nsGkAtoms::autocomplete) {
|
2014-06-06 07:25:02 +00:00
|
|
|
aResult.ParseAtomArray(aValue);
|
|
|
|
return true;
|
2010-09-14 17:58:34 +00:00
|
|
|
}
|
2012-08-17 09:53:44 +00:00
|
|
|
if (aAttribute == nsGkAtoms::inputmode) {
|
|
|
|
return aResult.ParseEnumValue(aValue, kInputInputmodeTable, false);
|
|
|
|
}
|
2005-11-29 16:37:15 +00:00
|
|
|
if (ParseImageAttribute(aAttribute, aValue, aResult)) {
|
|
|
|
// We have to call |ParseImageAttribute| unconditionally since we
|
|
|
|
// don't know if we're going to have a type="image" attribute yet,
|
|
|
|
// (or could have it set dynamically in the future). See bug
|
|
|
|
// 214077.
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2005-11-29 16:37:15 +00:00
|
|
|
}
|
1998-11-07 05:27:39 +00:00
|
|
|
}
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2005-11-29 16:37:15 +00:00
|
|
|
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
|
|
|
aResult);
|
1998-09-01 01:27:08 +00:00
|
|
|
}
|
|
|
|
|
2013-11-19 19:21:29 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
|
|
|
nsRuleData* aData)
|
1998-09-01 01:27:08 +00:00
|
|
|
{
|
2006-12-26 17:47:52 +00:00
|
|
|
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
|
2004-04-13 16:45:59 +00:00
|
|
|
if (value && value->Type() == nsAttrValue::eEnum &&
|
|
|
|
value->GetEnumValue() == NS_FORM_INPUT_IMAGE) {
|
2013-08-02 01:21:31 +00:00
|
|
|
nsGenericHTMLFormElementWithState::MapImageBorderAttributeInto(aAttributes, aData);
|
|
|
|
nsGenericHTMLFormElementWithState::MapImageMarginAttributeInto(aAttributes, aData);
|
|
|
|
nsGenericHTMLFormElementWithState::MapImageSizeAttributesInto(aAttributes, aData);
|
2002-12-27 00:41:52 +00:00
|
|
|
// Images treat align as "float"
|
2013-08-02 01:21:31 +00:00
|
|
|
nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes, aData);
|
2013-03-28 19:41:32 +00:00
|
|
|
}
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2013-08-02 01:21:31 +00:00
|
|
|
nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aData);
|
1998-09-01 01:27:08 +00:00
|
|
|
}
|
|
|
|
|
2004-10-24 17:10:32 +00:00
|
|
|
nsChangeHint
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
|
|
|
|
int32_t aModType) const
|
1999-07-07 01:24:40 +00:00
|
|
|
{
|
2004-10-24 17:10:32 +00:00
|
|
|
nsChangeHint retval =
|
2013-08-02 01:21:31 +00:00
|
|
|
nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute, aModType);
|
2006-12-26 17:47:52 +00:00
|
|
|
if (aAttribute == nsGkAtoms::type) {
|
2004-10-24 17:10:32 +00:00
|
|
|
NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
|
2007-12-19 17:46:54 +00:00
|
|
|
} else if (mType == NS_FORM_INPUT_IMAGE &&
|
|
|
|
(aAttribute == nsGkAtoms::alt ||
|
|
|
|
aAttribute == nsGkAtoms::value)) {
|
|
|
|
// We might need to rebuild our alt text. Just go ahead and
|
|
|
|
// reconstruct our frame. This should be quite rare..
|
|
|
|
NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
|
2006-12-26 17:47:52 +00:00
|
|
|
} else if (aAttribute == nsGkAtoms::value) {
|
2004-10-24 17:10:32 +00:00
|
|
|
NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
|
2006-12-26 17:47:52 +00:00
|
|
|
} else if (aAttribute == nsGkAtoms::size &&
|
2011-10-17 14:59:28 +00:00
|
|
|
IsSingleLineTextControl(false)) {
|
2004-10-24 17:10:32 +00:00
|
|
|
NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
|
2010-10-19 13:11:07 +00:00
|
|
|
} else if (PlaceholderApplies() && aAttribute == nsGkAtoms::placeholder) {
|
|
|
|
NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
|
2003-07-11 21:16:12 +00:00
|
|
|
}
|
2004-10-24 17:10:32 +00:00
|
|
|
return retval;
|
2003-07-11 21:16:12 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
NS_IMETHODIMP_(bool)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
2003-07-11 21:16:12 +00:00
|
|
|
{
|
2004-02-25 21:04:50 +00:00
|
|
|
static const MappedAttributeEntry attributes[] = {
|
2006-12-26 17:47:52 +00:00
|
|
|
{ &nsGkAtoms::align },
|
|
|
|
{ &nsGkAtoms::type },
|
2012-07-30 14:20:58 +00:00
|
|
|
{ nullptr },
|
2003-04-16 20:54:20 +00:00
|
|
|
};
|
|
|
|
|
2004-02-25 21:04:50 +00:00
|
|
|
static const MappedAttributeEntry* const map[] = {
|
2003-04-16 20:54:20 +00:00
|
|
|
attributes,
|
|
|
|
sCommonAttributeMap,
|
2003-07-11 21:16:12 +00:00
|
|
|
sImageMarginSizeAttributeMap,
|
2003-04-16 20:54:20 +00:00
|
|
|
sImageBorderAttributeMap,
|
|
|
|
};
|
|
|
|
|
2011-12-18 10:09:27 +00:00
|
|
|
return FindAttributeDependence(aAttribute, map);
|
1999-07-07 01:24:40 +00:00
|
|
|
}
|
|
|
|
|
2005-01-12 19:45:38 +00:00
|
|
|
nsMapRuleToAttributesFunc
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetAttributeMappingFunction() const
|
1998-09-05 04:00:06 +00:00
|
|
|
{
|
2005-01-12 19:45:38 +00:00
|
|
|
return &MapAttributesIntoRule;
|
1998-09-05 04:00:06 +00:00
|
|
|
}
|
|
|
|
|
2000-06-23 14:12:24 +00:00
|
|
|
|
1999-12-01 15:12:49 +00:00
|
|
|
// Controllers Methods
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
nsIControllers*
|
|
|
|
HTMLInputElement::GetControllers(ErrorResult& aRv)
|
1999-12-01 15:12:49 +00:00
|
|
|
{
|
|
|
|
//XXX: what about type "file"?
|
2011-10-17 14:59:28 +00:00
|
|
|
if (IsSingleLineTextControl(false))
|
1999-12-01 15:12:49 +00:00
|
|
|
{
|
|
|
|
if (!mControllers)
|
|
|
|
{
|
2000-02-16 01:41:17 +00:00
|
|
|
nsresult rv;
|
2002-12-17 13:29:39 +00:00
|
|
|
mControllers = do_CreateInstance(kXULControllersCID, &rv);
|
2013-03-28 19:41:32 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2002-12-17 13:29:39 +00:00
|
|
|
|
2000-12-23 10:56:31 +00:00
|
|
|
nsCOMPtr<nsIController>
|
|
|
|
controller(do_CreateInstance("@mozilla.org/editor/editorcontroller;1",
|
|
|
|
&rv));
|
2013-03-28 19:41:32 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2002-12-17 13:29:39 +00:00
|
|
|
|
1999-12-15 03:54:52 +00:00
|
|
|
mControllers->AppendController(controller);
|
2011-12-24 00:11:30 +00:00
|
|
|
|
|
|
|
controller = do_CreateInstance("@mozilla.org/editor/editingcontroller;1",
|
|
|
|
&rv);
|
2013-03-28 19:41:32 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2011-12-24 00:11:30 +00:00
|
|
|
|
|
|
|
mControllers->AppendController(controller);
|
1999-12-01 15:12:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
return mControllers;
|
1999-12-01 15:12:49 +00:00
|
|
|
}
|
2000-04-13 05:15:59 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetControllers(nsIControllers** aResult)
|
2000-04-13 05:15:59 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aResult);
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
ErrorResult rv;
|
|
|
|
nsRefPtr<nsIControllers> controller = GetControllers(rv);
|
|
|
|
controller.forget(aResult);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
int32_t
|
|
|
|
HTMLInputElement::GetTextLength(ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
nsAutoString val;
|
|
|
|
GetValue(val);
|
|
|
|
return val.Length();
|
2000-04-13 05:15:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetTextLength(int32_t* aTextLength)
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
|
|
|
*aTextLength = GetTextLength(rv);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetSelectionRange(int32_t aSelectionStart,
|
|
|
|
int32_t aSelectionEnd,
|
2013-03-28 19:41:32 +00:00
|
|
|
const Optional<nsAString>& aDirection,
|
|
|
|
ErrorResult& aRv)
|
2000-04-13 05:15:59 +00:00
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
|
2014-03-25 15:36:49 +00:00
|
|
|
nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
|
|
|
|
if (textControlFrame) {
|
|
|
|
// Default to forward, even if not specified.
|
|
|
|
// Note that we don't currently support directionless selections, so
|
|
|
|
// "none" is treated like "forward".
|
|
|
|
nsITextControlFrame::SelectionDirection dir = nsITextControlFrame::eForward;
|
|
|
|
if (aDirection.WasPassed() && aDirection.Value().EqualsLiteral("backward")) {
|
|
|
|
dir = nsITextControlFrame::eBackward;
|
|
|
|
}
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2014-03-25 15:36:49 +00:00
|
|
|
aRv = textControlFrame->SetSelectionRange(aSelectionStart, aSelectionEnd, dir);
|
|
|
|
if (!aRv.Failed()) {
|
|
|
|
aRv = textControlFrame->ScrollSelectionIntoView();
|
|
|
|
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
|
|
|
new AsyncEventDispatcher(this, NS_LITERAL_STRING("select"),
|
|
|
|
true, false);
|
|
|
|
asyncDispatcher->PostDOMEvent();
|
2011-02-05 00:29:29 +00:00
|
|
|
}
|
2000-04-13 05:15:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetSelectionRange(int32_t aSelectionStart,
|
|
|
|
int32_t aSelectionEnd,
|
|
|
|
const nsAString& aDirection)
|
2000-04-13 05:15:59 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
ErrorResult rv;
|
|
|
|
Optional<nsAString> direction;
|
|
|
|
direction = &aDirection;
|
2011-07-29 21:31:57 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
SetSelectionRange(aSelectionStart, aSelectionEnd, direction, rv);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
2011-10-07 13:40:11 +00:00
|
|
|
|
2013-09-18 05:29:04 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::SetRangeText(const nsAString& aReplacement, ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
if (!SupportsSetRangeText()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t start, end;
|
|
|
|
aRv = GetSelectionRange(&start, &end);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
nsTextEditorState* state = GetEditorState();
|
|
|
|
if (state && state->IsSelectionCached()) {
|
|
|
|
start = state->GetSelectionProperties().mStart;
|
|
|
|
end = state->GetSelectionProperties().mEnd;
|
|
|
|
aRv = NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SetRangeText(aReplacement, start, end, mozilla::dom::SelectionMode::Preserve,
|
|
|
|
aRv, start, end);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HTMLInputElement::SetRangeText(const nsAString& aReplacement, uint32_t aStart,
|
|
|
|
uint32_t aEnd, const SelectionMode& aSelectMode,
|
|
|
|
ErrorResult& aRv, int32_t aSelectionStart,
|
|
|
|
int32_t aSelectionEnd)
|
|
|
|
{
|
|
|
|
if (!SupportsSetRangeText()) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aStart > aEnd) {
|
|
|
|
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString value;
|
|
|
|
GetValueInternal(value);
|
|
|
|
uint32_t inputValueLength = value.Length();
|
|
|
|
|
|
|
|
if (aStart > inputValueLength) {
|
|
|
|
aStart = inputValueLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aEnd > inputValueLength) {
|
|
|
|
aEnd = inputValueLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aSelectionStart == -1 && aSelectionEnd == -1) {
|
2013-12-17 13:30:24 +00:00
|
|
|
aRv = GetSelectionRange(&aSelectionStart, &aSelectionEnd);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
nsTextEditorState* state = GetEditorState();
|
|
|
|
if (state && state->IsSelectionCached()) {
|
|
|
|
aSelectionStart = state->GetSelectionProperties().mStart;
|
|
|
|
aSelectionEnd = state->GetSelectionProperties().mEnd;
|
|
|
|
aRv = NS_OK;
|
2013-09-18 05:29:04 +00:00
|
|
|
}
|
2013-12-17 13:30:24 +00:00
|
|
|
}
|
2013-09-18 05:29:04 +00:00
|
|
|
}
|
|
|
|
|
2013-12-17 13:30:24 +00:00
|
|
|
if (aStart <= aEnd) {
|
2013-09-18 05:29:04 +00:00
|
|
|
value.Replace(aStart, aEnd - aStart, aReplacement);
|
2015-01-08 01:14:01 +00:00
|
|
|
nsresult rv = SetValueInternal(value, false, false);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
return;
|
|
|
|
}
|
2013-09-18 05:29:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t newEnd = aStart + aReplacement.Length();
|
|
|
|
int32_t delta = aReplacement.Length() - (aEnd - aStart);
|
|
|
|
|
|
|
|
switch (aSelectMode) {
|
|
|
|
case mozilla::dom::SelectionMode::Select:
|
|
|
|
{
|
|
|
|
aSelectionStart = aStart;
|
|
|
|
aSelectionEnd = newEnd;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case mozilla::dom::SelectionMode::Start:
|
|
|
|
{
|
|
|
|
aSelectionStart = aSelectionEnd = aStart;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case mozilla::dom::SelectionMode::End:
|
|
|
|
{
|
|
|
|
aSelectionStart = aSelectionEnd = newEnd;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case mozilla::dom::SelectionMode::Preserve:
|
|
|
|
{
|
2013-12-17 13:30:24 +00:00
|
|
|
if ((uint32_t)aSelectionStart > aEnd) {
|
2013-09-18 05:29:04 +00:00
|
|
|
aSelectionStart += delta;
|
2013-12-17 13:30:24 +00:00
|
|
|
} else if ((uint32_t)aSelectionStart > aStart) {
|
|
|
|
aSelectionStart = aStart;
|
|
|
|
}
|
2013-09-18 05:29:04 +00:00
|
|
|
|
2013-12-17 13:30:24 +00:00
|
|
|
if ((uint32_t)aSelectionEnd > aEnd) {
|
2013-09-18 05:29:04 +00:00
|
|
|
aSelectionEnd += delta;
|
2013-12-17 13:30:24 +00:00
|
|
|
} else if ((uint32_t)aSelectionEnd > aStart) {
|
2013-09-18 05:29:04 +00:00
|
|
|
aSelectionEnd = newEnd;
|
2013-12-17 13:30:24 +00:00
|
|
|
}
|
2013-09-18 05:29:04 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-05-16 17:41:31 +00:00
|
|
|
default:
|
|
|
|
MOZ_CRASH("Unknown mode!");
|
2013-09-18 05:29:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Optional<nsAString> direction;
|
|
|
|
SetSelectionRange(aSelectionStart, aSelectionEnd, direction, aRv);
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
int32_t
|
|
|
|
HTMLInputElement::GetSelectionStart(ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
int32_t selEnd, selStart;
|
|
|
|
aRv = GetSelectionRange(&selStart, &selEnd);
|
|
|
|
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
nsTextEditorState* state = GetEditorState();
|
2011-10-07 13:40:11 +00:00
|
|
|
if (state && state->IsSelectionCached()) {
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv = NS_OK;
|
|
|
|
return state->GetSelectionProperties().mStart;
|
2011-10-07 13:40:11 +00:00
|
|
|
}
|
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
|
|
|
|
return selStart;
|
2000-04-13 05:15:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetSelectionStart(int32_t* aSelectionStart)
|
2000-04-13 05:15:59 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aSelectionStart);
|
|
|
|
|
|
|
|
ErrorResult rv;
|
|
|
|
*aSelectionStart = GetSelectionStart(rv);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HTMLInputElement::SetSelectionStart(int32_t aSelectionStart, ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
nsTextEditorState* state = GetEditorState();
|
2011-07-29 21:31:57 +00:00
|
|
|
if (state && state->IsSelectionCached()) {
|
|
|
|
state->GetSelectionProperties().mStart = aSelectionStart;
|
2013-03-28 19:41:32 +00:00
|
|
|
return;
|
2011-07-29 21:31:57 +00:00
|
|
|
}
|
|
|
|
|
2011-07-28 17:51:22 +00:00
|
|
|
nsAutoString direction;
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv = GetSelectionDirection(direction);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t start, end;
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv = GetSelectionRange(&start, &end);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-28 17:51:22 +00:00
|
|
|
start = aSelectionStart;
|
|
|
|
if (end < start) {
|
|
|
|
end = start;
|
2000-04-13 05:15:59 +00:00
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
|
|
|
|
aRv = SetSelectionRange(start, end, direction);
|
2000-04-13 05:15:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetSelectionStart(int32_t aSelectionStart)
|
2000-04-13 05:15:59 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
ErrorResult rv;
|
|
|
|
SetSelectionStart(aSelectionStart, rv);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
2011-07-29 21:31:57 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
int32_t
|
|
|
|
HTMLInputElement::GetSelectionEnd(ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
int32_t selStart, selEnd;
|
|
|
|
aRv = GetSelectionRange(&selStart, &selEnd);
|
2011-10-07 13:40:11 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
if (aRv.Failed()) {
|
|
|
|
nsTextEditorState* state = GetEditorState();
|
2011-10-07 13:40:11 +00:00
|
|
|
if (state && state->IsSelectionCached()) {
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv = NS_OK;
|
|
|
|
return state->GetSelectionProperties().mEnd;
|
2011-10-07 13:40:11 +00:00
|
|
|
}
|
|
|
|
}
|
2000-04-13 05:15:59 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
return selEnd;
|
|
|
|
}
|
2000-04-13 05:15:59 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetSelectionEnd(int32_t* aSelectionEnd)
|
2000-04-13 05:15:59 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aSelectionEnd);
|
|
|
|
|
|
|
|
ErrorResult rv;
|
|
|
|
*aSelectionEnd = GetSelectionEnd(rv);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HTMLInputElement::SetSelectionEnd(int32_t aSelectionEnd, ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
nsTextEditorState* state = GetEditorState();
|
2011-07-29 21:31:57 +00:00
|
|
|
if (state && state->IsSelectionCached()) {
|
|
|
|
state->GetSelectionProperties().mEnd = aSelectionEnd;
|
2013-03-28 19:41:32 +00:00
|
|
|
return;
|
2011-07-29 21:31:57 +00:00
|
|
|
}
|
|
|
|
|
2011-07-28 17:51:22 +00:00
|
|
|
nsAutoString direction;
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv = GetSelectionDirection(direction);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t start, end;
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv = GetSelectionRange(&start, &end);
|
|
|
|
if (aRv.Failed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-28 17:51:22 +00:00
|
|
|
end = aSelectionEnd;
|
|
|
|
if (start > end) {
|
|
|
|
start = end;
|
2000-04-13 05:15:59 +00:00
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
|
|
|
|
aRv = SetSelectionRange(start, end, direction);
|
2000-04-13 05:15:59 +00:00
|
|
|
}
|
|
|
|
|
2007-07-25 04:29:47 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetSelectionEnd(int32_t aSelectionEnd)
|
2007-07-25 04:29:47 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
ErrorResult rv;
|
|
|
|
SetSelectionEnd(aSelectionEnd, rv);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
2007-07-25 04:29:47 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
HTMLInputElement::GetFiles(nsIDOMFileList** aFileList)
|
|
|
|
{
|
2014-10-08 16:15:23 +00:00
|
|
|
nsRefPtr<FileList> list = GetFiles();
|
2013-03-28 19:41:32 +00:00
|
|
|
list.forget(aFileList);
|
2007-07-25 04:29:47 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-04-13 05:15:59 +00:00
|
|
|
nsresult
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetSelectionRange(int32_t* aSelectionStart,
|
|
|
|
int32_t* aSelectionEnd)
|
2000-04-13 05:15:59 +00:00
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
|
2014-03-25 15:36:49 +00:00
|
|
|
nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
|
|
|
|
if (textControlFrame) {
|
|
|
|
return textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd);
|
2000-04-13 05:15:59 +00:00
|
|
|
}
|
2000-12-23 10:56:31 +00:00
|
|
|
|
2014-03-25 15:36:49 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2000-04-13 05:15:59 +00:00
|
|
|
}
|
|
|
|
|
2011-07-29 21:31:57 +00:00
|
|
|
static void
|
|
|
|
DirectionToName(nsITextControlFrame::SelectionDirection dir, nsAString& aDirection)
|
|
|
|
{
|
|
|
|
if (dir == nsITextControlFrame::eNone) {
|
|
|
|
aDirection.AssignLiteral("none");
|
|
|
|
} else if (dir == nsITextControlFrame::eForward) {
|
|
|
|
aDirection.AssignLiteral("forward");
|
|
|
|
} else if (dir == nsITextControlFrame::eBackward) {
|
|
|
|
aDirection.AssignLiteral("backward");
|
|
|
|
} else {
|
|
|
|
NS_NOTREACHED("Invalid SelectionDirection value");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::GetSelectionDirection(nsAString& aDirection, ErrorResult& aRv)
|
2011-07-28 17:51:22 +00:00
|
|
|
{
|
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
2011-10-17 14:59:28 +00:00
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
|
2014-03-25 15:36:49 +00:00
|
|
|
nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
|
|
|
|
if (textControlFrame) {
|
|
|
|
nsITextControlFrame::SelectionDirection dir;
|
|
|
|
rv = textControlFrame->GetSelectionRange(nullptr, nullptr, &dir);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
DirectionToName(dir, aDirection);
|
2011-07-28 17:51:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-07 13:40:11 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2011-10-07 13:40:11 +00:00
|
|
|
if (state && state->IsSelectionCached()) {
|
|
|
|
DirectionToName(state->GetSelectionProperties().mDirection, aDirection);
|
2013-03-28 19:41:32 +00:00
|
|
|
return;
|
2011-10-07 13:40:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
aRv.Throw(rv);
|
|
|
|
}
|
2011-07-28 17:51:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetSelectionDirection(nsAString& aDirection)
|
2013-03-28 19:41:32 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
ErrorResult rv;
|
|
|
|
GetSelectionDirection(aDirection, rv);
|
|
|
|
return rv.ErrorCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
HTMLInputElement::SetSelectionDirection(const nsAString& aDirection, ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
nsTextEditorState* state = GetEditorState();
|
2011-07-29 21:31:57 +00:00
|
|
|
if (state && state->IsSelectionCached()) {
|
|
|
|
nsITextControlFrame::SelectionDirection dir = nsITextControlFrame::eNone;
|
|
|
|
if (aDirection.EqualsLiteral("forward")) {
|
|
|
|
dir = nsITextControlFrame::eForward;
|
|
|
|
} else if (aDirection.EqualsLiteral("backward")) {
|
|
|
|
dir = nsITextControlFrame::eBackward;
|
|
|
|
}
|
|
|
|
state->GetSelectionProperties().mDirection = dir;
|
2013-03-28 19:41:32 +00:00
|
|
|
return;
|
2011-07-29 21:31:57 +00:00
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t start, end;
|
2013-03-28 19:41:32 +00:00
|
|
|
aRv = GetSelectionRange(&start, &end);
|
|
|
|
if (!aRv.Failed()) {
|
|
|
|
aRv = SetSelectionRange(start, end, aDirection);
|
2011-07-28 17:51:22 +00:00
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
}
|
2011-07-28 17:51:22 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
HTMLInputElement::SetSelectionDirection(const nsAString& aDirection)
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
|
|
|
SetSelectionDirection(aDirection, rv);
|
|
|
|
return rv.ErrorCode();
|
2011-07-28 17:51:22 +00:00
|
|
|
}
|
|
|
|
|
2002-12-17 23:38:04 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetPhonetic(nsAString& aPhonetic)
|
2002-12-17 23:38:04 +00:00
|
|
|
{
|
2011-11-16 07:50:19 +00:00
|
|
|
aPhonetic.Truncate();
|
2011-10-17 14:59:28 +00:00
|
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
|
2014-03-25 15:36:49 +00:00
|
|
|
nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
|
|
|
|
if (textControlFrame) {
|
|
|
|
textControlFrame->GetPhonetic(aPhonetic);
|
2002-12-17 23:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-08-17 03:13:07 +00:00
|
|
|
#ifdef ACCESSIBILITY
|
2006-05-16 03:54:46 +00:00
|
|
|
/*static*/ nsresult
|
|
|
|
FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget,
|
|
|
|
nsPresContext* aPresContext,
|
|
|
|
const nsAString& aEventType)
|
2001-05-11 21:11:38 +00:00
|
|
|
{
|
2003-03-05 03:20:17 +00:00
|
|
|
nsCOMPtr<nsIDOMEvent> event;
|
2013-03-09 11:34:29 +00:00
|
|
|
nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aTarget);
|
2014-03-18 04:48:21 +00:00
|
|
|
if (NS_SUCCEEDED(EventDispatcher::CreateEvent(element, aPresContext, nullptr,
|
|
|
|
NS_LITERAL_STRING("Events"),
|
|
|
|
getter_AddRefs(event)))) {
|
2011-10-17 14:59:28 +00:00
|
|
|
event->InitEvent(aEventType, true, true);
|
2012-06-10 23:44:50 +00:00
|
|
|
event->SetTrusted(true);
|
2005-04-28 23:48:28 +00:00
|
|
|
|
2014-03-18 04:48:21 +00:00
|
|
|
EventDispatcher::DispatchDOMEvent(aTarget, nullptr, event, aPresContext,
|
|
|
|
nullptr);
|
2003-03-05 03:20:17 +00:00
|
|
|
}
|
2001-05-11 21:11:38 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-08-17 03:13:07 +00:00
|
|
|
#endif
|
2001-11-02 07:40:01 +00:00
|
|
|
|
2010-07-22 15:10:27 +00:00
|
|
|
nsresult
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetDefaultValueAsValue()
|
2001-11-02 07:40:01 +00:00
|
|
|
{
|
2010-09-08 17:42:35 +00:00
|
|
|
NS_ASSERTION(GetValueMode() == VALUE_MODE_VALUE,
|
|
|
|
"GetValueMode() should return VALUE_MODE_VALUE!");
|
2001-11-05 06:50:21 +00:00
|
|
|
|
2010-09-08 17:42:35 +00:00
|
|
|
// The element has a content attribute value different from it's value when
|
|
|
|
// it's in the value mode value.
|
|
|
|
nsAutoString resetVal;
|
|
|
|
GetDefaultValue(resetVal);
|
|
|
|
|
|
|
|
// SetValueInternal is going to sanitize the value.
|
2011-10-17 14:59:28 +00:00
|
|
|
return SetValueInternal(resetVal, false, false);
|
2010-07-22 15:10:27 +00:00
|
|
|
}
|
|
|
|
|
2012-11-21 10:13:57 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetDirectionIfAuto(bool aAuto, bool aNotify)
|
2012-11-21 10:13:57 +00:00
|
|
|
{
|
|
|
|
if (aAuto) {
|
|
|
|
SetHasDirAuto();
|
|
|
|
if (IsSingleLineTextControl(true)) {
|
|
|
|
nsAutoString value;
|
|
|
|
GetValue(value);
|
|
|
|
SetDirectionalityFromValue(this, value, aNotify);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ClearHasDirAuto();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-22 15:10:27 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::Reset()
|
2010-07-22 15:10:27 +00:00
|
|
|
{
|
2010-09-08 17:42:35 +00:00
|
|
|
// We should be able to reset all dirty flags regardless of the type.
|
2011-10-17 14:59:28 +00:00
|
|
|
SetCheckedChanged(false);
|
|
|
|
SetValueChanged(false);
|
2010-07-22 15:10:27 +00:00
|
|
|
|
2010-09-08 17:42:35 +00:00
|
|
|
switch (GetValueMode()) {
|
|
|
|
case VALUE_MODE_VALUE:
|
|
|
|
return SetDefaultValueAsValue();
|
|
|
|
case VALUE_MODE_DEFAULT_ON:
|
2012-08-03 10:38:52 +00:00
|
|
|
DoSetChecked(DefaultChecked(), true, false);
|
|
|
|
return NS_OK;
|
2010-09-08 17:42:35 +00:00
|
|
|
case VALUE_MODE_FILENAME:
|
2010-11-23 23:45:53 +00:00
|
|
|
ClearFiles(false);
|
2010-09-08 17:42:35 +00:00
|
|
|
return NS_OK;
|
|
|
|
case VALUE_MODE_DEFAULT:
|
2010-07-22 15:10:27 +00:00
|
|
|
default:
|
2010-09-08 17:42:35 +00:00
|
|
|
return NS_OK;
|
2010-07-22 15:10:27 +00:00
|
|
|
}
|
2001-11-02 07:40:01 +00:00
|
|
|
}
|
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
|
2001-11-02 07:40:01 +00:00
|
|
|
{
|
2002-02-16 01:19:24 +00:00
|
|
|
// Disabled elements don't submit
|
|
|
|
// For type=reset, and type=button, we just never submit, period.
|
|
|
|
// For type=image and type=button, we only submit if we were the button
|
|
|
|
// pressed
|
|
|
|
// For type=radio and type=checkbox, we only submit if checked=true
|
2010-09-18 21:33:16 +00:00
|
|
|
if (IsDisabled() || mType == NS_FORM_INPUT_RESET ||
|
2010-02-25 05:58:16 +00:00
|
|
|
mType == NS_FORM_INPUT_BUTTON ||
|
|
|
|
((mType == NS_FORM_INPUT_SUBMIT || mType == NS_FORM_INPUT_IMAGE) &&
|
2010-08-19 21:58:20 +00:00
|
|
|
aFormSubmission->GetOriginatingElement() != this) ||
|
2010-02-25 05:58:16 +00:00
|
|
|
((mType == NS_FORM_INPUT_RADIO || mType == NS_FORM_INPUT_CHECKBOX) &&
|
2011-11-16 07:50:19 +00:00
|
|
|
!mChecked)) {
|
2010-02-25 05:58:16 +00:00
|
|
|
return NS_OK;
|
2002-01-24 19:08:57 +00:00
|
|
|
}
|
2001-11-02 07:40:01 +00:00
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
// Get the name
|
|
|
|
nsAutoString name;
|
2011-05-04 12:46:09 +00:00
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
2001-11-02 07:40:01 +00:00
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
// Submit .x, .y for input type=image
|
2002-12-18 23:38:09 +00:00
|
|
|
if (mType == NS_FORM_INPUT_IMAGE) {
|
2007-02-18 16:49:54 +00:00
|
|
|
// Get a property set by the frame to find out where it was clicked.
|
|
|
|
nsIntPoint* lastClickedPoint =
|
2007-07-08 07:08:04 +00:00
|
|
|
static_cast<nsIntPoint*>(GetProperty(nsGkAtoms::imageClickedPoint));
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t x, y;
|
2007-02-18 16:49:54 +00:00
|
|
|
if (lastClickedPoint) {
|
2004-01-22 03:26:17 +00:00
|
|
|
// Convert the values to strings for submission
|
2008-11-03 02:25:11 +00:00
|
|
|
x = lastClickedPoint->x;
|
|
|
|
y = lastClickedPoint->y;
|
|
|
|
} else {
|
|
|
|
x = y = 0;
|
2004-01-22 03:26:17 +00:00
|
|
|
}
|
2007-02-18 16:49:54 +00:00
|
|
|
|
2008-11-03 02:25:11 +00:00
|
|
|
nsAutoString xVal, yVal;
|
|
|
|
xVal.AppendInt(x);
|
|
|
|
yVal.AppendInt(y);
|
|
|
|
|
2004-01-22 03:26:17 +00:00
|
|
|
if (!name.IsEmpty()) {
|
2010-02-25 05:58:16 +00:00
|
|
|
aFormSubmission->AddNameValuePair(name + NS_LITERAL_STRING(".x"), xVal);
|
|
|
|
aFormSubmission->AddNameValuePair(name + NS_LITERAL_STRING(".y"), yVal);
|
2004-01-22 03:26:17 +00:00
|
|
|
} else {
|
|
|
|
// If the Image Element has no name, simply return x and y
|
2007-02-18 16:49:54 +00:00
|
|
|
// to Nav and IE compatibility.
|
2010-02-25 05:58:16 +00:00
|
|
|
aFormSubmission->AddNameValuePair(NS_LITERAL_STRING("x"), xVal);
|
|
|
|
aFormSubmission->AddNameValuePair(NS_LITERAL_STRING("y"), yVal);
|
2001-11-02 07:40:01 +00:00
|
|
|
}
|
2010-02-25 05:57:54 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
2002-02-16 01:19:24 +00:00
|
|
|
}
|
2001-11-02 07:40:01 +00:00
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
//
|
|
|
|
// Submit name=value
|
|
|
|
//
|
|
|
|
|
|
|
|
// If name not there, don't submit
|
2011-05-04 12:46:09 +00:00
|
|
|
if (name.IsEmpty()) {
|
2010-02-25 05:58:16 +00:00
|
|
|
return NS_OK;
|
2002-02-16 01:19:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the value
|
|
|
|
nsAutoString value;
|
2011-11-16 07:50:19 +00:00
|
|
|
nsresult rv = GetValue(value);
|
2002-02-16 01:19:24 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2005-01-20 16:47:25 +00:00
|
|
|
if (mType == NS_FORM_INPUT_SUBMIT && value.IsEmpty() &&
|
2006-12-26 17:47:52 +00:00
|
|
|
!HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
|
2005-01-20 16:47:25 +00:00
|
|
|
// Get our default value, which is the same as our default label
|
2005-01-20 17:07:51 +00:00
|
|
|
nsXPIDLString defaultValue;
|
2005-01-20 16:47:25 +00:00
|
|
|
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
2005-01-20 17:07:51 +00:00
|
|
|
"Submit", defaultValue);
|
|
|
|
value = defaultValue;
|
2005-01-20 16:47:25 +00:00
|
|
|
}
|
2013-03-03 18:30:13 +00:00
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
//
|
2009-01-23 09:02:09 +00:00
|
|
|
// Submit file if its input type=file and this encoding method accepts files
|
2002-02-16 01:19:24 +00:00
|
|
|
//
|
2002-12-18 23:38:09 +00:00
|
|
|
if (mType == NS_FORM_INPUT_FILE) {
|
2009-10-25 04:13:30 +00:00
|
|
|
// Submit files
|
2002-02-16 01:19:24 +00:00
|
|
|
|
2014-10-08 16:15:23 +00:00
|
|
|
const nsTArray<nsRefPtr<File>>& files = GetFilesInternal();
|
2009-10-25 04:13:30 +00:00
|
|
|
|
2013-08-16 10:11:29 +00:00
|
|
|
for (uint32_t i = 0; i < files.Length(); ++i) {
|
2013-03-03 18:30:13 +00:00
|
|
|
aFormSubmission->AddNameFilePair(name, files[i], NullString());
|
2001-11-02 07:40:01 +00:00
|
|
|
}
|
2009-10-25 04:13:30 +00:00
|
|
|
|
2013-08-16 10:11:29 +00:00
|
|
|
if (files.IsEmpty()) {
|
2009-11-19 20:58:46 +00:00
|
|
|
// If no file was selected, pretend we had an empty file with an
|
|
|
|
// empty filename.
|
2013-03-03 18:30:13 +00:00
|
|
|
aFormSubmission->AddNameFilePair(name, nullptr, NullString());
|
2009-11-19 20:58:46 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-10-25 04:13:30 +00:00
|
|
|
return NS_OK;
|
2002-02-16 01:19:24 +00:00
|
|
|
}
|
2001-11-02 07:40:01 +00:00
|
|
|
|
2010-02-25 05:58:16 +00:00
|
|
|
if (mType == NS_FORM_INPUT_HIDDEN && name.EqualsLiteral("_charset_")) {
|
|
|
|
nsCString charset;
|
|
|
|
aFormSubmission->GetCharset(charset);
|
2011-11-16 07:50:19 +00:00
|
|
|
return aFormSubmission->AddNameValuePair(name,
|
|
|
|
NS_ConvertASCIItoUTF16(charset));
|
2010-03-11 12:29:51 +00:00
|
|
|
}
|
2011-11-16 07:50:19 +00:00
|
|
|
if (IsSingleLineTextControl(true) &&
|
|
|
|
name.EqualsLiteral("isindex") &&
|
|
|
|
aFormSubmission->SupportsIsindexSubmission()) {
|
|
|
|
return aFormSubmission->AddIsindex(value);
|
2001-11-02 07:40:01 +00:00
|
|
|
}
|
2011-11-16 07:50:19 +00:00
|
|
|
return aFormSubmission->AddNameValuePair(name, value);
|
2001-11-02 07:40:01 +00:00
|
|
|
}
|
|
|
|
|
2002-02-16 01:19:24 +00:00
|
|
|
|
2001-11-02 07:40:01 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SaveState()
|
2001-11-02 07:40:01 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsRefPtr<HTMLInputElementState> inputState;
|
2013-05-03 17:17:09 +00:00
|
|
|
switch (GetValueMode()) {
|
|
|
|
case VALUE_MODE_DEFAULT_ON:
|
|
|
|
if (mCheckedChanged) {
|
|
|
|
inputState = new HTMLInputElementState();
|
|
|
|
inputState->SetChecked(mChecked);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
2001-11-02 07:40:01 +00:00
|
|
|
break;
|
2013-05-03 17:17:09 +00:00
|
|
|
case VALUE_MODE_FILENAME:
|
2013-08-16 10:11:29 +00:00
|
|
|
if (!mFiles.IsEmpty()) {
|
2013-05-03 17:17:09 +00:00
|
|
|
inputState = new HTMLInputElementState();
|
2014-11-11 17:13:50 +00:00
|
|
|
inputState->SetFileImpls(mFiles);
|
2013-05-03 17:17:09 +00:00
|
|
|
}
|
2008-12-12 19:25:22 +00:00
|
|
|
break;
|
2013-05-03 17:17:09 +00:00
|
|
|
case VALUE_MODE_VALUE:
|
|
|
|
case VALUE_MODE_DEFAULT:
|
|
|
|
// VALUE_MODE_DEFAULT shouldn't have their value saved except 'hidden',
|
|
|
|
// mType shouldn't be NS_FORM_INPUT_PASSWORD and value should have changed.
|
|
|
|
if ((GetValueMode() == VALUE_MODE_DEFAULT &&
|
|
|
|
mType != NS_FORM_INPUT_HIDDEN) ||
|
|
|
|
mType == NS_FORM_INPUT_PASSWORD || !mValueChanged) {
|
2013-05-02 15:15:50 +00:00
|
|
|
break;
|
2006-04-25 09:18:42 +00:00
|
|
|
}
|
2013-05-03 17:17:09 +00:00
|
|
|
|
|
|
|
inputState = new HTMLInputElementState();
|
|
|
|
nsAutoString value;
|
|
|
|
GetValue(value);
|
|
|
|
DebugOnly<nsresult> rv =
|
|
|
|
nsLinebreakConverter::ConvertStringLineBreaks(
|
|
|
|
value,
|
|
|
|
nsLinebreakConverter::eLinebreakPlatform,
|
|
|
|
nsLinebreakConverter::eLinebreakContent);
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Converting linebreaks failed!");
|
|
|
|
inputState->SetValue(value);
|
|
|
|
break;
|
2001-11-02 07:40:01 +00:00
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
|
2008-12-12 19:25:22 +00:00
|
|
|
if (inputState) {
|
2013-07-24 07:38:13 +00:00
|
|
|
nsPresState* state = GetPrimaryPresState();
|
2008-12-12 19:25:22 +00:00
|
|
|
if (state) {
|
|
|
|
state->SetStateProperty(inputState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mDisabledChanged) {
|
2013-07-24 07:38:13 +00:00
|
|
|
nsPresState* state = GetPrimaryPresState();
|
2003-11-10 05:52:29 +00:00
|
|
|
if (state) {
|
2010-09-18 21:33:16 +00:00
|
|
|
// We do not want to save the real disabled state but the disabled
|
|
|
|
// attribute.
|
|
|
|
state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
|
2003-11-10 05:52:29 +00:00
|
|
|
}
|
|
|
|
}
|
2001-11-02 07:40:01 +00:00
|
|
|
|
2013-07-24 07:38:13 +00:00
|
|
|
return NS_OK;
|
2001-11-02 07:40:01 +00:00
|
|
|
}
|
|
|
|
|
2004-01-09 23:54:21 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::DoneCreatingElement()
|
2002-03-31 10:14:01 +00:00
|
|
|
{
|
2011-11-16 07:50:19 +00:00
|
|
|
mParserCreating = false;
|
2002-03-31 10:14:01 +00:00
|
|
|
|
|
|
|
//
|
2005-09-01 18:58:31 +00:00
|
|
|
// Restore state as needed. Note that disabled state applies to all control
|
|
|
|
// types.
|
2002-03-31 10:14:01 +00:00
|
|
|
//
|
2011-09-29 06:19:26 +00:00
|
|
|
bool restoredCheckedState =
|
2013-08-02 01:21:31 +00:00
|
|
|
!mInhibitRestoration && NS_SUCCEEDED(GenerateStateKey()) && RestoreFormControlState();
|
2002-03-31 10:14:01 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// If restore does not occur, we initialize .checked using the CHECKED
|
|
|
|
// property.
|
|
|
|
//
|
2011-11-16 07:50:19 +00:00
|
|
|
if (!restoredCheckedState && mShouldInitChecked) {
|
2011-11-16 07:50:19 +00:00
|
|
|
DoSetChecked(DefaultChecked(), false, true);
|
2011-10-17 14:59:28 +00:00
|
|
|
DoSetCheckedChanged(false, false);
|
2002-03-31 10:14:01 +00:00
|
|
|
}
|
|
|
|
|
2010-09-20 20:33:17 +00:00
|
|
|
// Sanitize the value.
|
|
|
|
if (GetValueMode() == VALUE_MODE_VALUE) {
|
|
|
|
nsAutoString aValue;
|
|
|
|
GetValue(aValue);
|
2015-01-08 01:14:01 +00:00
|
|
|
// TODO: What should we do if SetValueInternal fails? (The allocation
|
|
|
|
// may potentially be big, but most likely we've failed to allocate
|
|
|
|
// before the type change.)
|
2011-10-17 14:59:28 +00:00
|
|
|
SetValueInternal(aValue, false, false);
|
2010-09-20 20:33:17 +00:00
|
|
|
}
|
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
mShouldInitChecked = false;
|
2002-03-31 10:14:01 +00:00
|
|
|
}
|
|
|
|
|
2014-04-03 04:18:36 +00:00
|
|
|
EventStates
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IntrinsicState() const
|
2005-06-03 02:02:45 +00:00
|
|
|
{
|
2007-02-09 06:20:47 +00:00
|
|
|
// If you add states here, and they're type-dependent, you need to add them
|
|
|
|
// to the type case in AfterSetAttr.
|
2013-03-28 19:41:32 +00:00
|
|
|
|
2014-04-03 04:18:36 +00:00
|
|
|
EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
|
2006-08-16 03:20:19 +00:00
|
|
|
if (mType == NS_FORM_INPUT_CHECKBOX || mType == NS_FORM_INPUT_RADIO) {
|
|
|
|
// Check current checked state (:checked)
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mChecked) {
|
2006-08-16 03:20:19 +00:00
|
|
|
state |= NS_EVENT_STATE_CHECKED;
|
|
|
|
}
|
|
|
|
|
2009-02-11 01:19:37 +00:00
|
|
|
// Check current indeterminate state (:indeterminate)
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mType == NS_FORM_INPUT_CHECKBOX && mIndeterminate) {
|
2009-02-11 01:19:37 +00:00
|
|
|
state |= NS_EVENT_STATE_INDETERMINATE;
|
|
|
|
}
|
|
|
|
|
2006-08-16 03:20:19 +00:00
|
|
|
// Check whether we are the default checked element (:default)
|
2011-11-16 07:50:19 +00:00
|
|
|
if (DefaultChecked()) {
|
2006-08-16 03:20:19 +00:00
|
|
|
state |= NS_EVENT_STATE_DEFAULT;
|
|
|
|
}
|
2005-09-18 18:05:40 +00:00
|
|
|
} else if (mType == NS_FORM_INPUT_IMAGE) {
|
|
|
|
state |= nsImageLoadingContent::ImageState();
|
2005-06-03 02:02:45 +00:00
|
|
|
}
|
2006-08-16 03:20:19 +00:00
|
|
|
|
2010-08-19 00:03:20 +00:00
|
|
|
if (DoesRequiredApply() && HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
|
|
|
|
state |= NS_EVENT_STATE_REQUIRED;
|
|
|
|
} else {
|
|
|
|
state |= NS_EVENT_STATE_OPTIONAL;
|
|
|
|
}
|
|
|
|
|
2010-08-21 18:51:38 +00:00
|
|
|
if (IsCandidateForConstraintValidation()) {
|
2010-11-23 23:49:50 +00:00
|
|
|
if (IsValid()) {
|
2010-11-23 23:55:22 +00:00
|
|
|
state |= NS_EVENT_STATE_VALID;
|
2010-11-23 23:49:50 +00:00
|
|
|
} else {
|
|
|
|
state |= NS_EVENT_STATE_INVALID;
|
2010-11-23 23:50:53 +00:00
|
|
|
|
2011-01-27 13:51:45 +00:00
|
|
|
if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
|
|
|
|
(GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
|
2011-11-16 07:50:19 +00:00
|
|
|
(mCanShowInvalidUI && ShouldShowValidityUI()))) {
|
2010-11-23 23:49:50 +00:00
|
|
|
state |= NS_EVENT_STATE_MOZ_UI_INVALID;
|
|
|
|
}
|
|
|
|
}
|
2010-11-23 23:56:24 +00:00
|
|
|
|
|
|
|
// :-moz-ui-valid applies if all of the following conditions are true:
|
|
|
|
// 1. The element is not focused, or had either :-moz-ui-valid or
|
|
|
|
// :-moz-ui-invalid applying before it was focused ;
|
|
|
|
// 2. The element is either valid or isn't allowed to have
|
|
|
|
// :-moz-ui-invalid applying ;
|
2011-01-27 13:51:45 +00:00
|
|
|
// 3. The element has no form owner or its form owner doesn't have the
|
|
|
|
// novalidate attribute set ;
|
|
|
|
// 4. The element has already been modified or the user tried to submit the
|
|
|
|
// form owner while invalid.
|
|
|
|
if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
|
2011-11-16 07:50:19 +00:00
|
|
|
(mCanShowValidUI && ShouldShowValidityUI() &&
|
2011-01-27 13:51:45 +00:00
|
|
|
(IsValid() || (!state.HasState(NS_EVENT_STATE_MOZ_UI_INVALID) &&
|
2011-11-16 07:50:19 +00:00
|
|
|
!mCanShowInvalidUI)))) {
|
2010-11-23 23:56:24 +00:00
|
|
|
state |= NS_EVENT_STATE_MOZ_UI_VALID;
|
|
|
|
}
|
2010-08-21 17:52:57 +00:00
|
|
|
}
|
|
|
|
|
2010-09-10 05:08:56 +00:00
|
|
|
if (mForm && !mForm->GetValidity() && IsSubmitControl()) {
|
|
|
|
state |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
|
|
|
|
}
|
|
|
|
|
2012-06-09 17:44:47 +00:00
|
|
|
// :in-range and :out-of-range only apply if the element currently has a range.
|
|
|
|
if (mHasRange) {
|
|
|
|
state |= (GetValidityState(VALIDITY_STATE_RANGE_OVERFLOW) ||
|
|
|
|
GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW))
|
|
|
|
? NS_EVENT_STATE_OUTOFRANGE
|
|
|
|
: NS_EVENT_STATE_INRANGE;
|
|
|
|
}
|
|
|
|
|
2005-06-03 02:02:45 +00:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2013-12-08 21:26:42 +00:00
|
|
|
void
|
2014-04-03 04:18:36 +00:00
|
|
|
HTMLInputElement::AddStates(EventStates aStates)
|
2013-12-08 21:26:42 +00:00
|
|
|
{
|
|
|
|
if (mType == NS_FORM_INPUT_TEXT) {
|
2014-04-03 04:18:36 +00:00
|
|
|
EventStates focusStates(aStates & (NS_EVENT_STATE_FOCUS |
|
|
|
|
NS_EVENT_STATE_FOCUSRING));
|
2013-12-08 21:26:42 +00:00
|
|
|
if (!focusStates.IsEmpty()) {
|
|
|
|
HTMLInputElement* ownerNumberControl = GetOwnerNumberControl();
|
|
|
|
if (ownerNumberControl) {
|
|
|
|
ownerNumberControl->AddStates(focusStates);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nsGenericHTMLFormElementWithState::AddStates(aStates);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-04-03 04:18:36 +00:00
|
|
|
HTMLInputElement::RemoveStates(EventStates aStates)
|
2013-12-08 21:26:42 +00:00
|
|
|
{
|
|
|
|
if (mType == NS_FORM_INPUT_TEXT) {
|
2014-04-03 04:18:36 +00:00
|
|
|
EventStates focusStates(aStates & (NS_EVENT_STATE_FOCUS |
|
|
|
|
NS_EVENT_STATE_FOCUSRING));
|
2013-12-08 21:26:42 +00:00
|
|
|
if (!focusStates.IsEmpty()) {
|
|
|
|
HTMLInputElement* ownerNumberControl = GetOwnerNumberControl();
|
|
|
|
if (ownerNumberControl) {
|
|
|
|
ownerNumberControl->RemoveStates(focusStates);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nsGenericHTMLFormElementWithState::RemoveStates(aStates);
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::RestoreState(nsPresState* aState)
|
2001-11-02 07:40:01 +00:00
|
|
|
{
|
2011-09-29 06:19:26 +00:00
|
|
|
bool restoredCheckedState = false;
|
2001-11-02 07:40:01 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
nsCOMPtr<HTMLInputElementState> inputState
|
2008-12-12 19:25:22 +00:00
|
|
|
(do_QueryInterface(aState->GetStateProperty()));
|
|
|
|
|
|
|
|
if (inputState) {
|
2013-05-03 17:17:09 +00:00
|
|
|
switch (GetValueMode()) {
|
|
|
|
case VALUE_MODE_DEFAULT_ON:
|
|
|
|
if (inputState->IsCheckedSet()) {
|
|
|
|
restoredCheckedState = true;
|
|
|
|
DoSetChecked(inputState->GetChecked(), true, true);
|
2013-05-02 15:15:50 +00:00
|
|
|
}
|
2013-05-03 17:17:09 +00:00
|
|
|
break;
|
|
|
|
case VALUE_MODE_FILENAME:
|
2008-12-12 19:25:22 +00:00
|
|
|
{
|
2014-11-11 17:13:50 +00:00
|
|
|
const nsTArray<nsRefPtr<FileImpl>>& fileImpls = inputState->GetFileImpls();
|
|
|
|
|
|
|
|
nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
|
|
|
|
MOZ_ASSERT(global);
|
|
|
|
|
|
|
|
nsTArray<nsRefPtr<File>> files;
|
|
|
|
for (uint32_t i = 0, len = fileImpls.Length(); i < len; ++i) {
|
|
|
|
nsRefPtr<File> file = new File(global, fileImpls[i]);
|
|
|
|
files.AppendElement(file);
|
|
|
|
}
|
|
|
|
|
2010-11-23 23:45:53 +00:00
|
|
|
SetFiles(files, true);
|
2013-05-03 17:17:09 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VALUE_MODE_VALUE:
|
|
|
|
case VALUE_MODE_DEFAULT:
|
|
|
|
if (GetValueMode() == VALUE_MODE_DEFAULT &&
|
|
|
|
mType != NS_FORM_INPUT_HIDDEN) {
|
2013-05-02 15:15:50 +00:00
|
|
|
break;
|
2007-10-10 03:39:16 +00:00
|
|
|
}
|
2013-05-03 17:17:09 +00:00
|
|
|
|
2015-01-08 01:14:01 +00:00
|
|
|
// TODO: What should we do if SetValueInternal fails? (The allocation
|
|
|
|
// may potentially be big, but most likely we've failed to allocate
|
|
|
|
// before the type change.)
|
2013-05-03 17:17:09 +00:00
|
|
|
SetValueInternal(inputState->GetValue(), false, true);
|
|
|
|
break;
|
2008-12-12 19:25:22 +00:00
|
|
|
}
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
2008-12-12 19:25:22 +00:00
|
|
|
|
|
|
|
if (aState->IsDisabledSet()) {
|
|
|
|
SetDisabled(aState->GetDisabled());
|
2003-11-10 05:52:29 +00:00
|
|
|
}
|
2002-03-07 20:53:40 +00:00
|
|
|
|
2004-09-21 18:04:47 +00:00
|
|
|
return restoredCheckedState;
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::AllowDrop()
|
2004-02-11 21:31:53 +00:00
|
|
|
{
|
|
|
|
// Allow drop on anything other than file inputs.
|
|
|
|
|
|
|
|
return mType != NS_FORM_INPUT_FILE;
|
|
|
|
}
|
2002-03-07 20:53:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Radio group stuff
|
|
|
|
*/
|
|
|
|
|
2010-07-14 06:39:48 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::AddedToRadioGroup()
|
2002-03-07 20:53:40 +00:00
|
|
|
{
|
2012-05-14 20:32:39 +00:00
|
|
|
// If the element is neither in a form nor a document, there is no group so we
|
|
|
|
// should just stop here.
|
|
|
|
if (!mForm && !IsInDoc()) {
|
2010-07-14 06:39:48 +00:00
|
|
|
return;
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2012-05-14 20:32:39 +00:00
|
|
|
// Make sure not to notify if we're still being created by the parser
|
|
|
|
bool notify = !mParserCreating;
|
|
|
|
|
2002-03-07 20:53:40 +00:00
|
|
|
//
|
|
|
|
// If the input element is checked, and we add it to the group, it will
|
|
|
|
// deselect whatever is currently selected in that group
|
|
|
|
//
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mChecked) {
|
2002-03-07 20:53:40 +00:00
|
|
|
//
|
|
|
|
// If it is checked, call "RadioSetChecked" to perform the selection/
|
|
|
|
// deselection ritual. This has the side effect of repainting the
|
|
|
|
// radio button, but as adding a checked radio button into the group
|
|
|
|
// should not be that common an occurrence, I think we can live with
|
|
|
|
// that.
|
|
|
|
//
|
2010-11-23 23:53:39 +00:00
|
|
|
RadioSetChecked(notify);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// For integrity purposes, we have to ensure that "checkedChanged" is
|
|
|
|
// the same for this new element as for all the others in the group
|
|
|
|
//
|
2011-11-16 07:50:19 +00:00
|
|
|
bool checkedChanged = mCheckedChanged;
|
2011-04-11 18:31:00 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIRadioVisitor> visitor =
|
|
|
|
new nsRadioGetCheckedChangedVisitor(&checkedChanged, this);
|
2010-11-23 23:53:39 +00:00
|
|
|
VisitGroup(visitor, notify);
|
2011-04-11 18:31:00 +00:00
|
|
|
|
2010-11-23 23:53:39 +00:00
|
|
|
SetCheckedChangedInternal(checkedChanged);
|
2011-04-11 18:31:00 +00:00
|
|
|
|
2002-07-20 23:09:24 +00:00
|
|
|
//
|
|
|
|
// Add the radio to the radio group container.
|
|
|
|
//
|
|
|
|
nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
|
|
|
|
if (container) {
|
|
|
|
nsAutoString name;
|
2011-05-04 12:49:59 +00:00
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
|
|
|
container->AddToRadioGroup(name, static_cast<nsIFormControl*>(this));
|
2011-02-25 18:16:04 +00:00
|
|
|
|
2011-05-04 12:49:59 +00:00
|
|
|
// We initialize the validity of the element to the validity of the group
|
|
|
|
// because we assume UpdateValueMissingState() will be called after.
|
|
|
|
SetValidityState(VALIDITY_STATE_VALUE_MISSING,
|
2011-07-19 09:44:55 +00:00
|
|
|
container->GetValueMissingState(name));
|
2002-07-20 23:09:24 +00:00
|
|
|
}
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2010-07-14 06:39:48 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::WillRemoveFromRadioGroup()
|
2002-03-07 20:53:40 +00:00
|
|
|
{
|
2011-05-04 12:49:59 +00:00
|
|
|
nsIRadioGroupContainer* container = GetRadioGroupContainer();
|
|
|
|
if (!container) {
|
2010-07-14 06:39:48 +00:00
|
|
|
return;
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2011-05-04 12:49:59 +00:00
|
|
|
nsAutoString name;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
|
|
|
|
2002-03-07 20:53:40 +00:00
|
|
|
// If this button was checked, we need to notify the group that there is no
|
|
|
|
// longer a selected radio button
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mChecked) {
|
2012-07-30 14:20:58 +00:00
|
|
|
container->SetCurrentRadioButton(name, nullptr);
|
2002-07-20 23:09:24 +00:00
|
|
|
}
|
2010-12-16 19:51:59 +00:00
|
|
|
|
2011-05-04 12:49:59 +00:00
|
|
|
// Remove this radio from its group in the container.
|
|
|
|
// We need to call UpdateValueMissingValidityStateForRadio before to make sure
|
|
|
|
// the group validity is updated (with this element being ignored).
|
|
|
|
UpdateValueMissingValidityStateForRadio(true);
|
|
|
|
container->RemoveFromRadioGroup(name, static_cast<nsIFormControl*>(this));
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, int32_t* aTabIndex)
|
2004-07-05 01:31:30 +00:00
|
|
|
{
|
2013-08-02 01:21:31 +00:00
|
|
|
if (nsGenericHTMLFormElementWithState::IsHTMLFocusable(aWithMouse, aIsFocusable,
|
|
|
|
aTabIndex))
|
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2004-07-24 21:12:43 +00:00
|
|
|
}
|
2004-07-05 01:31:30 +00:00
|
|
|
|
2010-09-18 21:33:16 +00:00
|
|
|
if (IsDisabled()) {
|
2011-10-17 14:59:28 +00:00
|
|
|
*aIsFocusable = false;
|
|
|
|
return true;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
}
|
|
|
|
|
2013-03-01 15:34:06 +00:00
|
|
|
if (IsSingleLineTextControl(false) ||
|
2013-12-01 13:49:10 +00:00
|
|
|
mType == NS_FORM_INPUT_RANGE) {
|
2011-10-17 14:59:28 +00:00
|
|
|
*aIsFocusable = true;
|
|
|
|
return false;
|
2004-07-24 21:12:43 +00:00
|
|
|
}
|
2004-07-05 01:31:30 +00:00
|
|
|
|
2010-06-21 12:37:34 +00:00
|
|
|
#ifdef XP_MACOSX
|
2011-09-29 06:19:26 +00:00
|
|
|
const bool defaultFocusable = !aWithMouse || nsFocusManager::sMouseFocusesFormControl;
|
2010-06-21 12:37:34 +00:00
|
|
|
#else
|
2011-09-29 06:19:26 +00:00
|
|
|
const bool defaultFocusable = true;
|
2010-06-21 12:37:34 +00:00
|
|
|
#endif
|
|
|
|
|
2013-12-01 13:49:10 +00:00
|
|
|
if (mType == NS_FORM_INPUT_FILE ||
|
|
|
|
mType == NS_FORM_INPUT_NUMBER) {
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
if (aTabIndex) {
|
2013-12-01 13:49:10 +00:00
|
|
|
// We only want our native anonymous child to be tabable to, not ourself.
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
*aTabIndex = -1;
|
|
|
|
}
|
2013-12-01 13:49:10 +00:00
|
|
|
if (mType == NS_FORM_INPUT_NUMBER) {
|
|
|
|
*aIsFocusable = true;
|
|
|
|
} else {
|
|
|
|
*aIsFocusable = defaultFocusable;
|
|
|
|
}
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 18:00:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mType == NS_FORM_INPUT_HIDDEN) {
|
2004-07-24 21:12:43 +00:00
|
|
|
if (aTabIndex) {
|
|
|
|
*aTabIndex = -1;
|
|
|
|
}
|
2011-10-17 14:59:28 +00:00
|
|
|
*aIsFocusable = false;
|
|
|
|
return false;
|
2004-07-05 01:31:30 +00:00
|
|
|
}
|
|
|
|
|
2004-07-24 21:12:43 +00:00
|
|
|
if (!aTabIndex) {
|
|
|
|
// The other controls are all focusable
|
2010-06-21 12:37:34 +00:00
|
|
|
*aIsFocusable = defaultFocusable;
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2004-07-24 21:12:43 +00:00
|
|
|
}
|
|
|
|
|
2004-07-05 01:31:30 +00:00
|
|
|
if (mType != NS_FORM_INPUT_RADIO) {
|
2010-06-21 12:37:34 +00:00
|
|
|
*aIsFocusable = defaultFocusable;
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2004-07-05 01:31:30 +00:00
|
|
|
}
|
|
|
|
|
2011-11-16 07:50:19 +00:00
|
|
|
if (mChecked) {
|
2004-07-05 01:31:30 +00:00
|
|
|
// Selected radio buttons are tabbable
|
2010-06-21 12:37:34 +00:00
|
|
|
*aIsFocusable = defaultFocusable;
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2004-07-05 01:31:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Current radio button is not selected.
|
|
|
|
// But make it tabbable if nothing in group is selected.
|
2011-05-04 12:49:59 +00:00
|
|
|
nsIRadioGroupContainer* container = GetRadioGroupContainer();
|
|
|
|
if (!container) {
|
2010-06-21 12:37:34 +00:00
|
|
|
*aIsFocusable = defaultFocusable;
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2004-07-05 01:31:30 +00:00
|
|
|
}
|
|
|
|
|
2011-05-04 12:49:59 +00:00
|
|
|
nsAutoString name;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
|
|
|
|
2013-08-10 01:17:51 +00:00
|
|
|
if (container->GetCurrentRadioButton(name)) {
|
2004-07-24 21:12:43 +00:00
|
|
|
*aTabIndex = -1;
|
2004-07-05 01:31:30 +00:00
|
|
|
}
|
2010-06-21 12:37:34 +00:00
|
|
|
*aIsFocusable = defaultFocusable;
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2004-07-05 01:31:30 +00:00
|
|
|
}
|
|
|
|
|
2002-03-07 20:53:40 +00:00
|
|
|
nsresult
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::VisitGroup(nsIRadioVisitor* aVisitor, bool aFlushContent)
|
2002-03-07 20:53:40 +00:00
|
|
|
{
|
2011-05-04 12:49:59 +00:00
|
|
|
nsIRadioGroupContainer* container = GetRadioGroupContainer();
|
2002-07-20 23:09:24 +00:00
|
|
|
if (container) {
|
2002-03-07 20:53:40 +00:00
|
|
|
nsAutoString name;
|
2011-05-04 12:49:59 +00:00
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
|
|
|
return container->WalkRadioGroup(name, aVisitor, aFlushContent);
|
2002-03-07 20:53:40 +00:00
|
|
|
}
|
2011-05-04 12:49:59 +00:00
|
|
|
|
|
|
|
aVisitor->Visit(this);
|
|
|
|
return NS_OK;
|
2001-11-02 07:40:01 +00:00
|
|
|
}
|
2002-03-07 20:53:40 +00:00
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::ValueModeType
|
|
|
|
HTMLInputElement::GetValueMode() const
|
2010-08-18 18:30:41 +00:00
|
|
|
{
|
|
|
|
switch (mType)
|
|
|
|
{
|
|
|
|
case NS_FORM_INPUT_HIDDEN:
|
|
|
|
case NS_FORM_INPUT_SUBMIT:
|
|
|
|
case NS_FORM_INPUT_BUTTON:
|
|
|
|
case NS_FORM_INPUT_RESET:
|
|
|
|
case NS_FORM_INPUT_IMAGE:
|
|
|
|
return VALUE_MODE_DEFAULT;
|
|
|
|
case NS_FORM_INPUT_CHECKBOX:
|
|
|
|
case NS_FORM_INPUT_RADIO:
|
|
|
|
return VALUE_MODE_DEFAULT_ON;
|
|
|
|
case NS_FORM_INPUT_FILE:
|
|
|
|
return VALUE_MODE_FILENAME;
|
|
|
|
#ifdef DEBUG
|
|
|
|
case NS_FORM_INPUT_TEXT:
|
|
|
|
case NS_FORM_INPUT_PASSWORD:
|
|
|
|
case NS_FORM_INPUT_SEARCH:
|
|
|
|
case NS_FORM_INPUT_TEL:
|
2010-08-18 18:31:54 +00:00
|
|
|
case NS_FORM_INPUT_EMAIL:
|
2010-08-18 18:33:37 +00:00
|
|
|
case NS_FORM_INPUT_URL:
|
2012-06-10 20:23:17 +00:00
|
|
|
case NS_FORM_INPUT_NUMBER:
|
2013-02-16 12:35:57 +00:00
|
|
|
case NS_FORM_INPUT_RANGE:
|
2012-12-27 16:06:53 +00:00
|
|
|
case NS_FORM_INPUT_DATE:
|
2013-01-08 17:10:00 +00:00
|
|
|
case NS_FORM_INPUT_TIME:
|
2013-05-23 13:02:23 +00:00
|
|
|
case NS_FORM_INPUT_COLOR:
|
2010-08-18 18:30:41 +00:00
|
|
|
return VALUE_MODE_VALUE;
|
|
|
|
default:
|
|
|
|
NS_NOTYETIMPLEMENTED("Unexpected input type in GetValueMode()");
|
|
|
|
return VALUE_MODE_VALUE;
|
|
|
|
#else // DEBUG
|
|
|
|
default:
|
|
|
|
return VALUE_MODE_VALUE;
|
|
|
|
#endif // DEBUG
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsMutable() const
|
2010-08-18 18:30:41 +00:00
|
|
|
{
|
2014-03-06 03:48:04 +00:00
|
|
|
return !IsDisabled() &&
|
2010-08-18 18:30:41 +00:00
|
|
|
!(DoesReadOnlyApply() &&
|
|
|
|
HasAttr(kNameSpaceID_None, nsGkAtoms::readonly));
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::DoesReadOnlyApply() const
|
2010-08-18 18:30:41 +00:00
|
|
|
{
|
|
|
|
switch (mType)
|
|
|
|
{
|
|
|
|
case NS_FORM_INPUT_HIDDEN:
|
|
|
|
case NS_FORM_INPUT_BUTTON:
|
|
|
|
case NS_FORM_INPUT_IMAGE:
|
|
|
|
case NS_FORM_INPUT_RESET:
|
|
|
|
case NS_FORM_INPUT_SUBMIT:
|
|
|
|
case NS_FORM_INPUT_RADIO:
|
|
|
|
case NS_FORM_INPUT_FILE:
|
|
|
|
case NS_FORM_INPUT_CHECKBOX:
|
2013-02-16 12:35:57 +00:00
|
|
|
case NS_FORM_INPUT_RANGE:
|
2013-05-23 13:02:23 +00:00
|
|
|
case NS_FORM_INPUT_COLOR:
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 18:30:41 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
case NS_FORM_INPUT_TEXT:
|
|
|
|
case NS_FORM_INPUT_PASSWORD:
|
|
|
|
case NS_FORM_INPUT_SEARCH:
|
|
|
|
case NS_FORM_INPUT_TEL:
|
2010-08-18 18:31:54 +00:00
|
|
|
case NS_FORM_INPUT_EMAIL:
|
2010-08-18 18:33:37 +00:00
|
|
|
case NS_FORM_INPUT_URL:
|
2012-06-10 20:23:17 +00:00
|
|
|
case NS_FORM_INPUT_NUMBER:
|
2012-12-27 16:06:53 +00:00
|
|
|
case NS_FORM_INPUT_DATE:
|
2013-01-08 17:10:00 +00:00
|
|
|
case NS_FORM_INPUT_TIME:
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-08-18 18:30:41 +00:00
|
|
|
default:
|
|
|
|
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesReadOnlyApply()");
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-08-18 18:30:41 +00:00
|
|
|
#else // DEBUG
|
|
|
|
default:
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-08-18 18:30:41 +00:00
|
|
|
#endif // DEBUG
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::DoesRequiredApply() const
|
2010-08-18 18:30:41 +00:00
|
|
|
{
|
|
|
|
switch (mType)
|
|
|
|
{
|
|
|
|
case NS_FORM_INPUT_HIDDEN:
|
|
|
|
case NS_FORM_INPUT_BUTTON:
|
|
|
|
case NS_FORM_INPUT_IMAGE:
|
|
|
|
case NS_FORM_INPUT_RESET:
|
|
|
|
case NS_FORM_INPUT_SUBMIT:
|
2013-02-16 12:35:57 +00:00
|
|
|
case NS_FORM_INPUT_RANGE:
|
2013-05-23 13:02:23 +00:00
|
|
|
case NS_FORM_INPUT_COLOR:
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 18:30:41 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
case NS_FORM_INPUT_RADIO:
|
|
|
|
case NS_FORM_INPUT_CHECKBOX:
|
|
|
|
case NS_FORM_INPUT_FILE:
|
|
|
|
case NS_FORM_INPUT_TEXT:
|
|
|
|
case NS_FORM_INPUT_PASSWORD:
|
|
|
|
case NS_FORM_INPUT_SEARCH:
|
|
|
|
case NS_FORM_INPUT_TEL:
|
2010-08-18 18:31:54 +00:00
|
|
|
case NS_FORM_INPUT_EMAIL:
|
2010-08-18 18:33:37 +00:00
|
|
|
case NS_FORM_INPUT_URL:
|
2012-06-10 20:23:17 +00:00
|
|
|
case NS_FORM_INPUT_NUMBER:
|
2012-12-27 16:06:53 +00:00
|
|
|
case NS_FORM_INPUT_DATE:
|
2013-01-08 17:10:00 +00:00
|
|
|
case NS_FORM_INPUT_TIME:
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-08-18 18:30:41 +00:00
|
|
|
default:
|
|
|
|
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-08-18 18:30:41 +00:00
|
|
|
#else // DEBUG
|
|
|
|
default:
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-08-18 18:30:41 +00:00
|
|
|
#endif // DEBUG
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-27 16:06:53 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::PlaceholderApplies() const
|
2012-12-27 16:06:53 +00:00
|
|
|
{
|
2013-01-08 17:10:00 +00:00
|
|
|
if (mType == NS_FORM_INPUT_DATE ||
|
|
|
|
mType == NS_FORM_INPUT_TIME) {
|
2012-12-27 16:06:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return IsSingleLineTextControl(false);
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::DoesPatternApply() const
|
2010-08-18 19:26:22 +00:00
|
|
|
{
|
2013-09-04 10:30:36 +00:00
|
|
|
// TODO: temporary until bug 773205 is fixed.
|
2013-01-31 23:01:50 +00:00
|
|
|
if (IsExperimentalMobileType(mType)) {
|
2012-06-10 20:23:17 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-10-17 14:59:28 +00:00
|
|
|
return IsSingleLineTextControl(false);
|
2010-08-18 19:26:22 +00:00
|
|
|
}
|
|
|
|
|
2012-06-22 09:36:24 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::DoesMinMaxApply() const
|
2012-06-22 09:36:24 +00:00
|
|
|
{
|
|
|
|
switch (mType)
|
|
|
|
{
|
|
|
|
case NS_FORM_INPUT_NUMBER:
|
2012-12-27 16:06:53 +00:00
|
|
|
case NS_FORM_INPUT_DATE:
|
2013-01-31 23:00:08 +00:00
|
|
|
case NS_FORM_INPUT_TIME:
|
2013-02-16 12:35:57 +00:00
|
|
|
case NS_FORM_INPUT_RANGE:
|
2012-06-22 09:36:24 +00:00
|
|
|
// TODO:
|
|
|
|
// All date/time types.
|
|
|
|
return true;
|
|
|
|
#ifdef DEBUG
|
|
|
|
case NS_FORM_INPUT_RESET:
|
|
|
|
case NS_FORM_INPUT_SUBMIT:
|
|
|
|
case NS_FORM_INPUT_IMAGE:
|
|
|
|
case NS_FORM_INPUT_BUTTON:
|
|
|
|
case NS_FORM_INPUT_HIDDEN:
|
|
|
|
case NS_FORM_INPUT_RADIO:
|
|
|
|
case NS_FORM_INPUT_CHECKBOX:
|
|
|
|
case NS_FORM_INPUT_FILE:
|
|
|
|
case NS_FORM_INPUT_TEXT:
|
|
|
|
case NS_FORM_INPUT_PASSWORD:
|
|
|
|
case NS_FORM_INPUT_SEARCH:
|
|
|
|
case NS_FORM_INPUT_TEL:
|
|
|
|
case NS_FORM_INPUT_EMAIL:
|
|
|
|
case NS_FORM_INPUT_URL:
|
2013-05-23 13:02:23 +00:00
|
|
|
case NS_FORM_INPUT_COLOR:
|
2012-06-22 09:36:24 +00:00
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
|
|
|
|
return false;
|
|
|
|
#else // DEBUG
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
#endif // DEBUG
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-16 00:56:00 +00:00
|
|
|
bool
|
|
|
|
HTMLInputElement::DoesAutocompleteApply() const
|
|
|
|
{
|
|
|
|
switch (mType)
|
|
|
|
{
|
|
|
|
case NS_FORM_INPUT_HIDDEN:
|
|
|
|
case NS_FORM_INPUT_TEXT:
|
|
|
|
case NS_FORM_INPUT_SEARCH:
|
|
|
|
case NS_FORM_INPUT_URL:
|
|
|
|
case NS_FORM_INPUT_TEL:
|
|
|
|
case NS_FORM_INPUT_EMAIL:
|
|
|
|
case NS_FORM_INPUT_PASSWORD:
|
|
|
|
case NS_FORM_INPUT_DATE:
|
|
|
|
case NS_FORM_INPUT_TIME:
|
|
|
|
case NS_FORM_INPUT_NUMBER:
|
|
|
|
case NS_FORM_INPUT_RANGE:
|
|
|
|
case NS_FORM_INPUT_COLOR:
|
|
|
|
return true;
|
|
|
|
#ifdef DEBUG
|
|
|
|
case NS_FORM_INPUT_RESET:
|
|
|
|
case NS_FORM_INPUT_SUBMIT:
|
|
|
|
case NS_FORM_INPUT_IMAGE:
|
|
|
|
case NS_FORM_INPUT_BUTTON:
|
|
|
|
case NS_FORM_INPUT_RADIO:
|
|
|
|
case NS_FORM_INPUT_CHECKBOX:
|
|
|
|
case NS_FORM_INPUT_FILE:
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
NS_NOTYETIMPLEMENTED("Unexpected input type in DoesAutocompleteApply()");
|
|
|
|
return false;
|
|
|
|
#else // DEBUG
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
#endif // DEBUG
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetStep() const
|
2012-06-22 19:02:20 +00:00
|
|
|
{
|
2013-01-31 23:00:08 +00:00
|
|
|
MOZ_ASSERT(DoesStepApply(), "GetStep() can only be called if @step applies");
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2013-02-06 22:56:49 +00:00
|
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::step)) {
|
|
|
|
return GetDefaultStep() * GetStepScaleFactor();
|
|
|
|
}
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2013-02-06 22:56:49 +00:00
|
|
|
nsAutoString stepStr;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::step, stepStr);
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2013-02-06 22:56:49 +00:00
|
|
|
if (stepStr.LowerCaseEqualsLiteral("any")) {
|
|
|
|
// The element can't suffer from step mismatch if there is no step.
|
|
|
|
return kStepAny;
|
|
|
|
}
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal step = StringToDecimal(stepStr);
|
2014-06-07 03:17:06 +00:00
|
|
|
if (!step.isFinite() || step <= Decimal(0)) {
|
2013-02-06 22:56:49 +00:00
|
|
|
step = GetDefaultStep();
|
2012-06-22 19:02:20 +00:00
|
|
|
}
|
|
|
|
|
2012-12-22 14:46:19 +00:00
|
|
|
return step * GetStepScaleFactor();
|
2012-06-22 19:02:20 +00:00
|
|
|
}
|
|
|
|
|
2010-08-21 18:52:49 +00:00
|
|
|
// nsIConstraintValidation
|
2010-08-18 18:28:08 +00:00
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
NS_IMETHODIMP
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetCustomValidity(const nsAString& aError)
|
2010-08-21 17:52:57 +00:00
|
|
|
{
|
2010-08-21 18:52:49 +00:00
|
|
|
nsIConstraintValidation::SetCustomValidity(aError);
|
2010-08-21 17:52:57 +00:00
|
|
|
|
2011-06-01 01:46:57 +00:00
|
|
|
UpdateState(true);
|
2010-08-21 17:52:57 +00:00
|
|
|
|
2010-08-21 18:51:38 +00:00
|
|
|
return NS_OK;
|
2010-08-21 17:52:57 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsTooLong()
|
2010-08-18 18:28:08 +00:00
|
|
|
{
|
2010-10-07 10:01:53 +00:00
|
|
|
if (!MaxLengthApplies() ||
|
|
|
|
!HasAttr(kNameSpaceID_None, nsGkAtoms::maxlength) ||
|
2011-11-16 07:50:19 +00:00
|
|
|
!mValueChanged) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 18:29:20 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
int32_t maxLength = MaxLength();
|
2010-10-07 10:02:29 +00:00
|
|
|
|
|
|
|
// Maxlength of -1 means parsing error.
|
|
|
|
if (maxLength == -1) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-10-07 10:02:29 +00:00
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t textLength = -1;
|
2010-08-18 18:28:08 +00:00
|
|
|
GetTextLength(&textLength);
|
|
|
|
|
2010-10-07 10:02:29 +00:00
|
|
|
return textLength > maxLength;
|
2010-08-18 18:28:08 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsValueMissing() const
|
2010-08-18 18:30:41 +00:00
|
|
|
{
|
2012-05-16 10:43:20 +00:00
|
|
|
// Should use UpdateValueMissingValidityStateForRadio() for type radio.
|
|
|
|
MOZ_ASSERT(mType != NS_FORM_INPUT_RADIO);
|
|
|
|
|
2010-08-18 18:30:41 +00:00
|
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::required) ||
|
|
|
|
!DoesRequiredApply()) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 18:30:41 +00:00
|
|
|
}
|
|
|
|
|
2012-05-16 10:43:20 +00:00
|
|
|
if (!IsMutable()) {
|
|
|
|
return false;
|
2010-08-18 18:30:41 +00:00
|
|
|
}
|
|
|
|
|
2012-05-16 10:43:20 +00:00
|
|
|
switch (GetValueMode()) {
|
|
|
|
case VALUE_MODE_VALUE:
|
|
|
|
return IsValueEmpty();
|
|
|
|
case VALUE_MODE_FILENAME:
|
|
|
|
{
|
2014-10-08 16:15:23 +00:00
|
|
|
const nsTArray<nsRefPtr<File>>& files = GetFilesInternal();
|
2013-08-16 10:11:29 +00:00
|
|
|
return files.IsEmpty();
|
2012-05-16 10:43:20 +00:00
|
|
|
}
|
|
|
|
case VALUE_MODE_DEFAULT_ON:
|
|
|
|
// This should not be used for type radio.
|
|
|
|
// See the MOZ_ASSERT at the beginning of the method.
|
2011-11-16 07:50:19 +00:00
|
|
|
return !mChecked;
|
2012-05-16 10:43:20 +00:00
|
|
|
case VALUE_MODE_DEFAULT:
|
2010-08-21 17:52:57 +00:00
|
|
|
default:
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 18:30:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::HasTypeMismatch() const
|
2010-08-18 18:31:54 +00:00
|
|
|
{
|
2010-08-21 17:52:57 +00:00
|
|
|
if (mType != NS_FORM_INPUT_EMAIL && mType != NS_FORM_INPUT_URL) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-21 17:52:57 +00:00
|
|
|
}
|
2010-08-18 18:31:54 +00:00
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
nsAutoString value;
|
2011-10-17 14:59:28 +00:00
|
|
|
NS_ENSURE_SUCCESS(GetValueInternal(value), false);
|
2010-08-18 18:33:37 +00:00
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
if (value.IsEmpty()) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-21 17:52:57 +00:00
|
|
|
}
|
2010-08-18 18:33:37 +00:00
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
if (mType == NS_FORM_INPUT_EMAIL) {
|
|
|
|
return HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)
|
|
|
|
? !IsValidEmailAddressList(value) : !IsValidEmailAddress(value);
|
|
|
|
} else if (mType == NS_FORM_INPUT_URL) {
|
2010-08-18 18:33:37 +00:00
|
|
|
/**
|
|
|
|
* TODO:
|
|
|
|
* The URL is not checked as the HTML5 specifications want it to be because
|
|
|
|
* there is no code to check for a valid URI/IRI according to 3986 and 3987
|
|
|
|
* RFC's at the moment, see bug 561586.
|
|
|
|
*
|
|
|
|
* RFC 3987 (IRI) implementation: bug 42899
|
|
|
|
*
|
|
|
|
* HTML5 specifications:
|
|
|
|
* http://dev.w3.org/html5/spec/infrastructure.html#valid-url
|
|
|
|
*/
|
|
|
|
nsCOMPtr<nsIIOService> ioService = do_GetIOService();
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
return !NS_SUCCEEDED(ioService->NewURI(NS_ConvertUTF16toUTF8(value), nullptr,
|
|
|
|
nullptr, getter_AddRefs(uri)));
|
2010-08-18 18:31:54 +00:00
|
|
|
}
|
|
|
|
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 18:31:54 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::HasPatternMismatch() const
|
2010-08-18 19:26:22 +00:00
|
|
|
{
|
2010-08-21 17:52:57 +00:00
|
|
|
if (!DoesPatternApply() ||
|
2012-07-05 10:03:19 +00:00
|
|
|
!HasAttr(kNameSpaceID_None, nsGkAtoms::pattern)) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 19:26:22 +00:00
|
|
|
}
|
|
|
|
|
2012-07-05 10:03:19 +00:00
|
|
|
nsAutoString pattern;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::pattern, pattern);
|
|
|
|
|
2010-08-18 19:26:22 +00:00
|
|
|
nsAutoString value;
|
2011-10-17 14:59:28 +00:00
|
|
|
NS_ENSURE_SUCCESS(GetValueInternal(value), false);
|
2010-08-18 19:26:22 +00:00
|
|
|
|
|
|
|
if (value.IsEmpty()) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 19:26:22 +00:00
|
|
|
}
|
|
|
|
|
2011-10-18 10:53:36 +00:00
|
|
|
nsIDocument* doc = OwnerDoc();
|
2010-08-18 19:26:22 +00:00
|
|
|
|
2011-04-28 17:21:37 +00:00
|
|
|
return !nsContentUtils::IsPatternMatching(value, pattern, doc);
|
2010-08-18 19:26:22 +00:00
|
|
|
}
|
|
|
|
|
2012-06-22 09:36:24 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsRangeOverflow() const
|
2012-06-22 09:36:24 +00:00
|
|
|
{
|
2013-01-31 23:00:08 +00:00
|
|
|
if (!DoesMinMaxApply()) {
|
2012-06-22 09:36:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal maximum = GetMaximum();
|
|
|
|
if (maximum.isNaN()) {
|
2012-06-22 09:36:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal value = GetValueAsDecimal();
|
|
|
|
if (value.isNaN()) {
|
2012-06-22 09:36:24 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-01-25 23:51:57 +00:00
|
|
|
return value > maximum;
|
2012-06-22 09:36:24 +00:00
|
|
|
}
|
|
|
|
|
2012-06-22 09:38:20 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsRangeUnderflow() const
|
2012-06-22 09:38:20 +00:00
|
|
|
{
|
2012-12-21 17:28:01 +00:00
|
|
|
if (!DoesMinMaxApply()) {
|
2012-06-22 09:38:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal minimum = GetMinimum();
|
|
|
|
if (minimum.isNaN()) {
|
2012-06-22 09:38:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal value = GetValueAsDecimal();
|
|
|
|
if (value.isNaN()) {
|
2012-06-22 09:38:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-01-25 23:51:57 +00:00
|
|
|
return value < minimum;
|
2012-06-22 09:38:20 +00:00
|
|
|
}
|
|
|
|
|
2012-06-22 19:02:20 +00:00
|
|
|
bool
|
2014-02-26 23:04:31 +00:00
|
|
|
HTMLInputElement::HasStepMismatch(bool aUseZeroIfValueNaN) const
|
2012-06-22 19:02:20 +00:00
|
|
|
{
|
|
|
|
if (!DoesStepApply()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal value = GetValueAsDecimal();
|
|
|
|
if (value.isNaN()) {
|
2014-02-26 23:04:31 +00:00
|
|
|
if (aUseZeroIfValueNaN) {
|
2014-06-07 03:17:06 +00:00
|
|
|
value = Decimal(0);
|
2014-02-26 23:04:31 +00:00
|
|
|
} else {
|
|
|
|
// The element can't suffer from step mismatch if it's value isn't a number.
|
|
|
|
return false;
|
|
|
|
}
|
2012-06-22 19:02:20 +00:00
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal step = GetStep();
|
2012-06-22 19:02:20 +00:00
|
|
|
if (step == kStepAny) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Value has to be an integral multiple of step.
|
2014-06-07 03:17:06 +00:00
|
|
|
return NS_floorModulo(value - GetStepBase(), step) != Decimal(0);
|
2012-06-22 19:02:20 +00:00
|
|
|
}
|
|
|
|
|
2014-01-30 12:54:12 +00:00
|
|
|
/**
|
2015-01-28 23:01:37 +00:00
|
|
|
* Takes aEmail and attempts to convert everything after the first "@"
|
|
|
|
* character (if anything) to punycode before returning the complete result via
|
|
|
|
* the aEncodedEmail out-param. The aIndexOfAt out-param is set to the index of
|
|
|
|
* the "@" character.
|
2014-01-30 12:54:12 +00:00
|
|
|
*
|
2015-01-28 23:01:37 +00:00
|
|
|
* If no "@" is found in aEmail, aEncodedEmail is simply set to aEmail and
|
|
|
|
* the aIndexOfAt out-param is set to kNotFound.
|
|
|
|
*
|
|
|
|
* Returns true in all cases unless an attempt to punycode encode fails. If
|
|
|
|
* false is returned, aEncodedEmail has not been set.
|
|
|
|
*
|
|
|
|
* This function exists because ConvertUTF8toACE() splits on ".", meaning that
|
|
|
|
* for 'user.name@sld.tld' it would treat "name@sld" as a label. We want to
|
|
|
|
* encode the domain part only.
|
2014-01-30 12:54:12 +00:00
|
|
|
*/
|
|
|
|
static bool PunycodeEncodeEmailAddress(const nsAString& aEmail,
|
|
|
|
nsAutoCString& aEncodedEmail,
|
|
|
|
uint32_t* aIndexOfAt)
|
|
|
|
{
|
|
|
|
nsAutoCString value = NS_ConvertUTF16toUTF8(aEmail);
|
2015-01-28 23:01:37 +00:00
|
|
|
*aIndexOfAt = (uint32_t)value.FindChar('@');
|
2014-01-30 12:54:12 +00:00
|
|
|
|
2015-01-28 23:01:37 +00:00
|
|
|
if (*aIndexOfAt == (uint32_t)kNotFound ||
|
|
|
|
*aIndexOfAt == value.Length() - 1) {
|
|
|
|
aEncodedEmail = value;
|
|
|
|
return true;
|
2014-01-30 12:54:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
|
|
|
|
if (!idnSrv) {
|
|
|
|
NS_ERROR("nsIIDNService isn't present!");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-28 23:01:37 +00:00
|
|
|
uint32_t indexOfDomain = *aIndexOfAt + 1;
|
|
|
|
|
|
|
|
const nsDependentCSubstring domain = Substring(value, indexOfDomain);
|
2015-01-28 23:01:33 +00:00
|
|
|
bool ace;
|
2014-01-30 12:54:12 +00:00
|
|
|
if (NS_SUCCEEDED(idnSrv->IsACE(domain, &ace)) && !ace) {
|
|
|
|
nsAutoCString domainACE;
|
|
|
|
if (NS_FAILED(idnSrv->ConvertUTF8toACE(domain, domainACE))) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-01-28 23:01:37 +00:00
|
|
|
value.Replace(indexOfDomain, domain.Length(), domainACE);
|
2014-01-30 12:54:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
aEncodedEmail = value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
HTMLInputElement::HasBadInput() const
|
|
|
|
{
|
|
|
|
if (mType == NS_FORM_INPUT_NUMBER) {
|
|
|
|
nsAutoString value;
|
|
|
|
GetValueInternal(value);
|
|
|
|
if (!value.IsEmpty()) {
|
|
|
|
// The input can't be bad, otherwise it would have been sanitized to the
|
|
|
|
// empty string.
|
|
|
|
NS_ASSERTION(!GetValueAsDecimal().isNaN(), "Should have sanitized");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsNumberControlFrame* numberControlFrame =
|
|
|
|
do_QueryFrame(GetPrimaryFrame());
|
|
|
|
if (numberControlFrame &&
|
|
|
|
!numberControlFrame->AnonTextControlIsEmpty()) {
|
|
|
|
// The input the user entered failed to parse as a number.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (mType == NS_FORM_INPUT_EMAIL) {
|
|
|
|
// With regards to suffering from bad input the spec says that only the
|
|
|
|
// punycode conversion works, so we don't care whether the email address is
|
|
|
|
// valid or not here. (If the email address is invalid then we will be
|
|
|
|
// suffering from a type mismatch.)
|
|
|
|
nsAutoString value;
|
|
|
|
nsAutoCString unused;
|
|
|
|
uint32_t unused2;
|
|
|
|
NS_ENSURE_SUCCESS(GetValueInternal(value), false);
|
|
|
|
HTMLSplitOnSpacesTokenizer tokenizer(value, ',');
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
|
|
if (!PunycodeEncodeEmailAddress(tokenizer.nextToken(), unused, &unused2)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateTooLongValidityState()
|
2010-08-21 17:52:57 +00:00
|
|
|
{
|
2010-11-23 14:17:12 +00:00
|
|
|
// TODO: this code will be re-enabled with bug 613016 and bug 613019.
|
|
|
|
#if 0
|
2010-08-21 17:52:57 +00:00
|
|
|
SetValidityState(VALIDITY_STATE_TOO_LONG, IsTooLong());
|
2010-11-23 14:17:12 +00:00
|
|
|
#endif
|
2010-08-21 17:52:57 +00:00
|
|
|
}
|
|
|
|
|
2010-12-16 19:51:59 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateValueMissingValidityStateForRadio(bool aIgnoreSelf)
|
2010-12-16 19:51:59 +00:00
|
|
|
{
|
2011-11-16 07:50:19 +00:00
|
|
|
bool notify = !mParserCreating;
|
2010-12-16 19:51:59 +00:00
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> selection = GetSelectedRadioButton();
|
2011-02-25 18:12:47 +00:00
|
|
|
|
2014-07-10 15:01:59 +00:00
|
|
|
aIgnoreSelf = aIgnoreSelf || !IsMutable();
|
|
|
|
|
2010-12-16 19:51:59 +00:00
|
|
|
// If there is no selection, that might mean the radio is not in a group.
|
|
|
|
// In that case, we can look for the checked state of the radio.
|
2011-11-16 07:50:19 +00:00
|
|
|
bool selected = selection || (!aIgnoreSelf && mChecked);
|
2011-11-16 07:50:19 +00:00
|
|
|
bool required = !aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required);
|
2010-12-16 19:51:59 +00:00
|
|
|
bool valueMissing = false;
|
|
|
|
|
2011-07-19 09:44:55 +00:00
|
|
|
nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
|
2011-05-04 12:49:59 +00:00
|
|
|
|
|
|
|
if (!container) {
|
2012-05-16 10:43:20 +00:00
|
|
|
SetValidityState(VALIDITY_STATE_VALUE_MISSING,
|
|
|
|
IsMutable() && required && !selected);
|
2011-05-04 12:49:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-02-25 18:12:47 +00:00
|
|
|
nsAutoString name;
|
2011-05-04 12:49:59 +00:00
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
|
2011-02-25 18:12:47 +00:00
|
|
|
|
|
|
|
// If the current radio is required and not ignored, we can assume the entire
|
|
|
|
// group is required.
|
2011-05-04 12:49:59 +00:00
|
|
|
if (!required) {
|
2011-02-25 18:12:47 +00:00
|
|
|
required = (aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required))
|
|
|
|
? container->GetRequiredRadioCount(name) - 1
|
|
|
|
: container->GetRequiredRadioCount(name);
|
2010-12-16 19:51:59 +00:00
|
|
|
}
|
|
|
|
|
2014-07-10 15:01:59 +00:00
|
|
|
valueMissing = required && !selected;
|
2010-12-16 19:51:59 +00:00
|
|
|
|
2011-05-04 12:49:59 +00:00
|
|
|
if (container->GetValueMissingState(name) != valueMissing) {
|
|
|
|
container->SetValueMissingState(name, valueMissing);
|
2011-05-04 12:45:47 +00:00
|
|
|
|
2011-05-04 12:53:06 +00:00
|
|
|
SetValidityState(VALIDITY_STATE_VALUE_MISSING, valueMissing);
|
2011-05-04 12:49:59 +00:00
|
|
|
|
2011-06-01 00:21:24 +00:00
|
|
|
// nsRadioSetValueMissingState will call ContentStateChanged while visiting.
|
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
2011-05-04 12:49:59 +00:00
|
|
|
nsCOMPtr<nsIRadioVisitor> visitor =
|
|
|
|
new nsRadioSetValueMissingState(this, valueMissing, notify);
|
|
|
|
VisitGroup(visitor, notify);
|
2011-02-25 18:16:04 +00:00
|
|
|
}
|
2010-12-16 19:51:59 +00:00
|
|
|
}
|
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateValueMissingValidityState()
|
2010-08-21 17:52:57 +00:00
|
|
|
{
|
2010-12-16 19:51:59 +00:00
|
|
|
if (mType == NS_FORM_INPUT_RADIO) {
|
|
|
|
UpdateValueMissingValidityStateForRadio(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
SetValidityState(VALIDITY_STATE_VALUE_MISSING, IsValueMissing());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateTypeMismatchValidityState()
|
2010-08-21 17:52:57 +00:00
|
|
|
{
|
|
|
|
SetValidityState(VALIDITY_STATE_TYPE_MISMATCH, HasTypeMismatch());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdatePatternMismatchValidityState()
|
2010-08-21 17:52:57 +00:00
|
|
|
{
|
|
|
|
SetValidityState(VALIDITY_STATE_PATTERN_MISMATCH, HasPatternMismatch());
|
|
|
|
}
|
|
|
|
|
2012-06-22 09:36:24 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateRangeOverflowValidityState()
|
2012-06-22 09:36:24 +00:00
|
|
|
{
|
|
|
|
SetValidityState(VALIDITY_STATE_RANGE_OVERFLOW, IsRangeOverflow());
|
|
|
|
}
|
|
|
|
|
2012-06-22 09:38:20 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateRangeUnderflowValidityState()
|
2012-06-22 09:38:20 +00:00
|
|
|
{
|
|
|
|
SetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW, IsRangeUnderflow());
|
|
|
|
}
|
|
|
|
|
2012-06-22 19:02:20 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateStepMismatchValidityState()
|
2012-06-22 19:02:20 +00:00
|
|
|
{
|
|
|
|
SetValidityState(VALIDITY_STATE_STEP_MISMATCH, HasStepMismatch());
|
|
|
|
}
|
|
|
|
|
2014-01-30 12:54:12 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::UpdateBadInputValidityState()
|
|
|
|
{
|
|
|
|
SetValidityState(VALIDITY_STATE_BAD_INPUT, HasBadInput());
|
|
|
|
}
|
|
|
|
|
2010-08-21 17:52:57 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateAllValidityStates(bool aNotify)
|
2010-08-21 17:52:57 +00:00
|
|
|
{
|
2011-09-29 06:19:26 +00:00
|
|
|
bool validBefore = IsValid();
|
2010-08-21 17:52:57 +00:00
|
|
|
UpdateTooLongValidityState();
|
|
|
|
UpdateValueMissingValidityState();
|
|
|
|
UpdateTypeMismatchValidityState();
|
|
|
|
UpdatePatternMismatchValidityState();
|
2012-06-22 09:36:24 +00:00
|
|
|
UpdateRangeOverflowValidityState();
|
2012-06-22 09:38:20 +00:00
|
|
|
UpdateRangeUnderflowValidityState();
|
2012-06-22 19:02:20 +00:00
|
|
|
UpdateStepMismatchValidityState();
|
2014-01-30 12:54:12 +00:00
|
|
|
UpdateBadInputValidityState();
|
2010-08-21 17:52:57 +00:00
|
|
|
|
2011-06-01 01:46:57 +00:00
|
|
|
if (validBefore != IsValid()) {
|
|
|
|
UpdateState(aNotify);
|
2010-08-21 17:52:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-10 05:08:56 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateBarredFromConstraintValidation()
|
2010-08-18 18:28:08 +00:00
|
|
|
{
|
2010-09-10 05:08:56 +00:00
|
|
|
SetBarredFromConstraintValidation(mType == NS_FORM_INPUT_HIDDEN ||
|
|
|
|
mType == NS_FORM_INPUT_BUTTON ||
|
|
|
|
mType == NS_FORM_INPUT_RESET ||
|
|
|
|
HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) ||
|
2010-09-18 21:33:16 +00:00
|
|
|
IsDisabled());
|
2010-08-18 18:28:08 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
|
|
|
|
ErrorResult& aRv)
|
|
|
|
{
|
|
|
|
aRv = GetValidationMessage(aValidationMessage);
|
|
|
|
}
|
|
|
|
|
2010-08-18 18:28:08 +00:00
|
|
|
nsresult
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
|
2013-03-28 19:41:32 +00:00
|
|
|
ValidityStateType aType)
|
2010-08-18 18:28:08 +00:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
switch (aType)
|
|
|
|
{
|
2010-08-21 17:52:57 +00:00
|
|
|
case VALIDITY_STATE_TOO_LONG:
|
2010-08-18 18:28:08 +00:00
|
|
|
{
|
|
|
|
nsXPIDLString message;
|
2013-03-28 19:41:32 +00:00
|
|
|
int32_t maxLength = MaxLength();
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t textLength = -1;
|
2010-08-18 18:28:08 +00:00
|
|
|
nsAutoString strMaxLength;
|
|
|
|
nsAutoString strTextLength;
|
|
|
|
|
|
|
|
GetTextLength(&textLength);
|
|
|
|
|
|
|
|
strMaxLength.AppendInt(maxLength);
|
|
|
|
strTextLength.AppendInt(textLength);
|
|
|
|
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t* params[] = { strMaxLength.get(), strTextLength.get() };
|
2010-08-18 18:28:08 +00:00
|
|
|
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
2010-09-23 01:44:13 +00:00
|
|
|
"FormValidationTextTooLong",
|
2012-03-09 02:22:57 +00:00
|
|
|
params, message);
|
2010-08-18 18:28:08 +00:00
|
|
|
aValidationMessage = message;
|
|
|
|
break;
|
|
|
|
}
|
2010-08-21 17:52:57 +00:00
|
|
|
case VALIDITY_STATE_VALUE_MISSING:
|
2010-08-18 18:30:41 +00:00
|
|
|
{
|
|
|
|
nsXPIDLString message;
|
2012-09-02 02:35:17 +00:00
|
|
|
nsAutoCString key;
|
2010-08-18 18:30:41 +00:00
|
|
|
switch (mType)
|
|
|
|
{
|
|
|
|
case NS_FORM_INPUT_FILE:
|
2014-05-22 03:48:51 +00:00
|
|
|
key.AssignLiteral("FormValidationFileMissing");
|
2010-08-18 18:30:41 +00:00
|
|
|
break;
|
|
|
|
case NS_FORM_INPUT_CHECKBOX:
|
2014-05-22 03:48:51 +00:00
|
|
|
key.AssignLiteral("FormValidationCheckboxMissing");
|
2010-08-18 18:30:41 +00:00
|
|
|
break;
|
|
|
|
case NS_FORM_INPUT_RADIO:
|
2014-05-22 03:48:51 +00:00
|
|
|
key.AssignLiteral("FormValidationRadioMissing");
|
2010-08-18 18:30:41 +00:00
|
|
|
break;
|
2015-02-02 20:42:40 +00:00
|
|
|
case NS_FORM_INPUT_NUMBER:
|
|
|
|
key.AssignLiteral("FormValidationBadInputNumber");
|
|
|
|
break;
|
2010-08-18 18:30:41 +00:00
|
|
|
default:
|
2014-05-22 03:48:51 +00:00
|
|
|
key.AssignLiteral("FormValidationValueMissing");
|
2010-08-18 18:30:41 +00:00
|
|
|
}
|
|
|
|
rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
|
|
|
key.get(), message);
|
|
|
|
aValidationMessage = message;
|
|
|
|
break;
|
|
|
|
}
|
2010-08-21 17:52:57 +00:00
|
|
|
case VALIDITY_STATE_TYPE_MISMATCH:
|
2010-08-18 18:31:54 +00:00
|
|
|
{
|
|
|
|
nsXPIDLString message;
|
2012-09-02 02:35:17 +00:00
|
|
|
nsAutoCString key;
|
2010-08-18 18:33:37 +00:00
|
|
|
if (mType == NS_FORM_INPUT_EMAIL) {
|
2010-09-23 01:44:13 +00:00
|
|
|
key.AssignLiteral("FormValidationInvalidEmail");
|
2010-08-18 18:33:37 +00:00
|
|
|
} else if (mType == NS_FORM_INPUT_URL) {
|
2010-09-23 01:44:13 +00:00
|
|
|
key.AssignLiteral("FormValidationInvalidURL");
|
2010-08-18 18:33:37 +00:00
|
|
|
} else {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
2010-08-18 18:31:54 +00:00
|
|
|
rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
2010-08-18 18:33:37 +00:00
|
|
|
key.get(), message);
|
2010-08-18 18:31:54 +00:00
|
|
|
aValidationMessage = message;
|
|
|
|
break;
|
|
|
|
}
|
2010-08-21 17:52:57 +00:00
|
|
|
case VALIDITY_STATE_PATTERN_MISMATCH:
|
2010-08-18 19:26:22 +00:00
|
|
|
{
|
|
|
|
nsXPIDLString message;
|
|
|
|
nsAutoString title;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
|
|
|
|
if (title.IsEmpty()) {
|
|
|
|
rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
2010-09-23 01:44:13 +00:00
|
|
|
"FormValidationPatternMismatch",
|
2010-08-18 19:26:22 +00:00
|
|
|
message);
|
|
|
|
} else {
|
2010-10-25 22:02:24 +00:00
|
|
|
if (title.Length() > nsIConstraintValidation::sContentSpecifiedMaxLengthMessage) {
|
|
|
|
title.Truncate(nsIConstraintValidation::sContentSpecifiedMaxLengthMessage);
|
|
|
|
}
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t* params[] = { title.get() };
|
2010-08-18 19:26:22 +00:00
|
|
|
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
2010-09-23 01:44:13 +00:00
|
|
|
"FormValidationPatternMismatchWithTitle",
|
2012-03-09 02:22:57 +00:00
|
|
|
params, message);
|
2010-08-18 19:26:22 +00:00
|
|
|
}
|
|
|
|
aValidationMessage = message;
|
|
|
|
break;
|
|
|
|
}
|
2012-06-22 09:36:24 +00:00
|
|
|
case VALIDITY_STATE_RANGE_OVERFLOW:
|
|
|
|
{
|
2014-06-02 13:53:56 +00:00
|
|
|
static const char kNumberOverTemplate[] = "FormValidationNumberRangeOverflow";
|
|
|
|
static const char kDateOverTemplate[] = "FormValidationDateRangeOverflow";
|
|
|
|
static const char kTimeOverTemplate[] = "FormValidationTimeRangeOverflow";
|
|
|
|
|
|
|
|
const char* msgTemplate;
|
2012-06-22 09:36:24 +00:00
|
|
|
nsXPIDLString message;
|
|
|
|
|
2012-07-06 12:40:18 +00:00
|
|
|
nsAutoString maxStr;
|
2013-02-16 12:35:57 +00:00
|
|
|
if (mType == NS_FORM_INPUT_NUMBER ||
|
|
|
|
mType == NS_FORM_INPUT_RANGE) {
|
2014-06-02 13:53:56 +00:00
|
|
|
msgTemplate = kNumberOverTemplate;
|
|
|
|
|
2012-12-21 17:26:56 +00:00
|
|
|
//We want to show the value as parsed when it's a number
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal maximum = GetMaximum();
|
|
|
|
MOZ_ASSERT(!maximum.isNaN());
|
2012-12-21 17:26:56 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
char buf[32];
|
|
|
|
DebugOnly<bool> ok = maximum.toString(buf, ArrayLength(buf));
|
|
|
|
maxStr.AssignASCII(buf);
|
|
|
|
MOZ_ASSERT(ok, "buf not big enough");
|
2013-01-31 23:00:08 +00:00
|
|
|
} else if (mType == NS_FORM_INPUT_DATE || mType == NS_FORM_INPUT_TIME) {
|
2014-06-02 13:53:56 +00:00
|
|
|
msgTemplate = mType == NS_FORM_INPUT_DATE ? kDateOverTemplate : kTimeOverTemplate;
|
2012-12-21 17:26:56 +00:00
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr);
|
|
|
|
} else {
|
2014-06-02 13:53:56 +00:00
|
|
|
msgTemplate = kNumberOverTemplate;
|
2012-12-21 17:26:56 +00:00
|
|
|
NS_NOTREACHED("Unexpected input type");
|
|
|
|
}
|
2012-06-22 09:36:24 +00:00
|
|
|
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t* params[] = { maxStr.get() };
|
2012-06-22 09:36:24 +00:00
|
|
|
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
2014-06-02 13:53:56 +00:00
|
|
|
msgTemplate,
|
2012-06-22 09:36:24 +00:00
|
|
|
params, message);
|
|
|
|
aValidationMessage = message;
|
|
|
|
break;
|
|
|
|
}
|
2012-06-22 09:38:20 +00:00
|
|
|
case VALIDITY_STATE_RANGE_UNDERFLOW:
|
|
|
|
{
|
2014-06-02 13:53:56 +00:00
|
|
|
static const char kNumberUnderTemplate[] = "FormValidationNumberRangeUnderflow";
|
|
|
|
static const char kDateUnderTemplate[] = "FormValidationDateRangeUnderflow";
|
|
|
|
static const char kTimeUnderTemplate[] = "FormValidationTimeRangeUnderflow";
|
|
|
|
|
|
|
|
const char* msgTemplate;
|
2012-06-22 09:38:20 +00:00
|
|
|
nsXPIDLString message;
|
|
|
|
|
2012-07-06 12:40:18 +00:00
|
|
|
nsAutoString minStr;
|
2013-02-16 12:35:57 +00:00
|
|
|
if (mType == NS_FORM_INPUT_NUMBER ||
|
|
|
|
mType == NS_FORM_INPUT_RANGE) {
|
2014-06-02 13:53:56 +00:00
|
|
|
msgTemplate = kNumberUnderTemplate;
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal minimum = GetMinimum();
|
|
|
|
MOZ_ASSERT(!minimum.isNaN());
|
2012-12-21 17:28:01 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
char buf[32];
|
|
|
|
DebugOnly<bool> ok = minimum.toString(buf, ArrayLength(buf));
|
|
|
|
minStr.AssignASCII(buf);
|
|
|
|
MOZ_ASSERT(ok, "buf not big enough");
|
2013-01-31 23:00:08 +00:00
|
|
|
} else if (mType == NS_FORM_INPUT_DATE || mType == NS_FORM_INPUT_TIME) {
|
2014-06-02 13:53:56 +00:00
|
|
|
msgTemplate = mType == NS_FORM_INPUT_DATE ? kDateUnderTemplate : kTimeUnderTemplate;
|
2012-12-21 17:28:01 +00:00
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr);
|
|
|
|
} else {
|
2014-06-02 13:53:56 +00:00
|
|
|
msgTemplate = kNumberUnderTemplate;
|
2012-12-21 17:28:01 +00:00
|
|
|
NS_NOTREACHED("Unexpected input type");
|
|
|
|
}
|
2012-06-22 09:38:20 +00:00
|
|
|
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t* params[] = { minStr.get() };
|
2012-06-22 09:38:20 +00:00
|
|
|
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
2014-06-02 13:53:56 +00:00
|
|
|
msgTemplate,
|
2012-06-22 09:38:20 +00:00
|
|
|
params, message);
|
|
|
|
aValidationMessage = message;
|
|
|
|
break;
|
|
|
|
}
|
2012-06-22 19:02:20 +00:00
|
|
|
case VALIDITY_STATE_STEP_MISMATCH:
|
|
|
|
{
|
|
|
|
nsXPIDLString message;
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal value = GetValueAsDecimal();
|
|
|
|
MOZ_ASSERT(!value.isNaN());
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal step = GetStep();
|
2014-06-07 03:17:06 +00:00
|
|
|
MOZ_ASSERT(step != kStepAny && step > Decimal(0));
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2012-12-22 14:46:19 +00:00
|
|
|
// In case this is a date and the step is not an integer, we don't want to
|
|
|
|
// display the dates corresponding to the truncated timestamps of valueLow
|
|
|
|
// and valueHigh because they might suffer from a step mismatch as well.
|
|
|
|
// Instead we want the timestamps to correspond to a rounded day. That is,
|
|
|
|
// we want a multiple of the step scale factor (1 day) as well as of step.
|
|
|
|
if (mType == NS_FORM_INPUT_DATE) {
|
2013-05-05 23:23:18 +00:00
|
|
|
step = EuclidLCM<Decimal>(step.floor(),
|
|
|
|
GetStepScaleFactor().floor());
|
2012-12-22 14:46:19 +00:00
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal stepBase = GetStepBase();
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal valueLow = value - NS_floorModulo(value - stepBase, step);
|
|
|
|
Decimal valueHigh = value + step - NS_floorModulo(value - stepBase, step);
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal maximum = GetMaximum();
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
if (maximum.isNaN() || valueHigh <= maximum) {
|
2012-06-22 19:02:20 +00:00
|
|
|
nsAutoString valueLowStr, valueHighStr;
|
2012-12-22 14:46:19 +00:00
|
|
|
ConvertNumberToString(valueLow, valueLowStr);
|
|
|
|
ConvertNumberToString(valueHigh, valueHighStr);
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2013-02-06 22:56:49 +00:00
|
|
|
if (valueLowStr.Equals(valueHighStr)) {
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t* params[] = { valueLowStr.get() };
|
2013-02-06 22:56:49 +00:00
|
|
|
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
|
|
|
"FormValidationStepMismatchOneValue",
|
|
|
|
params, message);
|
|
|
|
} else {
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t* params[] = { valueLowStr.get(), valueHighStr.get() };
|
2013-02-06 22:56:49 +00:00
|
|
|
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
|
|
|
"FormValidationStepMismatch",
|
|
|
|
params, message);
|
|
|
|
}
|
2012-06-22 19:02:20 +00:00
|
|
|
} else {
|
|
|
|
nsAutoString valueLowStr;
|
2012-12-22 14:46:19 +00:00
|
|
|
ConvertNumberToString(valueLow, valueLowStr);
|
2012-06-22 19:02:20 +00:00
|
|
|
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t* params[] = { valueLowStr.get() };
|
2012-06-22 19:02:20 +00:00
|
|
|
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
2013-02-06 22:56:49 +00:00
|
|
|
"FormValidationStepMismatchOneValue",
|
2012-06-22 19:02:20 +00:00
|
|
|
params, message);
|
|
|
|
}
|
|
|
|
|
|
|
|
aValidationMessage = message;
|
|
|
|
break;
|
|
|
|
}
|
2014-01-30 12:54:12 +00:00
|
|
|
case VALIDITY_STATE_BAD_INPUT:
|
|
|
|
{
|
|
|
|
nsXPIDLString message;
|
|
|
|
nsAutoCString key;
|
|
|
|
if (mType == NS_FORM_INPUT_NUMBER) {
|
|
|
|
key.AssignLiteral("FormValidationBadInputNumber");
|
|
|
|
} else if (mType == NS_FORM_INPUT_EMAIL) {
|
|
|
|
key.AssignLiteral("FormValidationInvalidEmail");
|
|
|
|
} else {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
|
|
|
key.get(), message);
|
|
|
|
aValidationMessage = message;
|
|
|
|
break;
|
|
|
|
}
|
2010-08-18 18:28:08 +00:00
|
|
|
default:
|
2010-08-21 18:52:49 +00:00
|
|
|
rv = nsIConstraintValidation::GetValidationMessage(aValidationMessage, aType);
|
2010-08-18 18:28:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
2002-03-07 20:53:40 +00:00
|
|
|
|
2010-08-18 18:31:54 +00:00
|
|
|
//static
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsValidEmailAddressList(const nsAString& aValue)
|
2010-08-18 18:31:54 +00:00
|
|
|
{
|
2012-01-04 10:08:00 +00:00
|
|
|
HTMLSplitOnSpacesTokenizer tokenizer(aValue, ',');
|
2010-08-18 18:31:54 +00:00
|
|
|
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
|
|
if (!IsValidEmailAddress(tokenizer.nextToken())) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 18:31:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-17 12:52:39 +00:00
|
|
|
return !tokenizer.separatorAfterCurrentToken();
|
2010-08-18 18:31:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//static
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsValidEmailAddress(const nsAString& aValue)
|
2010-08-18 18:31:54 +00:00
|
|
|
{
|
2013-08-30 12:13:35 +00:00
|
|
|
// Email addresses can't be empty and can't end with a '.' or '-'.
|
2014-01-30 12:54:12 +00:00
|
|
|
if (aValue.IsEmpty() || aValue.Last() == '.' || aValue.Last() == '-') {
|
2013-08-30 12:13:35 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-01-30 12:54:12 +00:00
|
|
|
uint32_t atPos;
|
|
|
|
nsAutoCString value;
|
2015-01-28 23:01:37 +00:00
|
|
|
if (!PunycodeEncodeEmailAddress(aValue, value, &atPos) ||
|
|
|
|
atPos == (uint32_t)kNotFound || atPos == 0 || atPos == value.Length() - 1) {
|
|
|
|
// Could not encode, or "@" was not found, or it was at the start or end
|
|
|
|
// of the input - in all cases, not a valid email address.
|
2013-08-30 12:13:35 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-01-30 12:54:12 +00:00
|
|
|
uint32_t length = value.Length();
|
|
|
|
uint32_t i = 0;
|
|
|
|
|
2010-08-18 18:31:54 +00:00
|
|
|
// Parsing the username.
|
2013-08-30 12:13:35 +00:00
|
|
|
for (; i < atPos; ++i) {
|
2014-01-04 15:02:17 +00:00
|
|
|
char16_t c = value[i];
|
2010-08-18 18:31:54 +00:00
|
|
|
|
|
|
|
// The username characters have to be in this list to be valid.
|
|
|
|
if (!(nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c) ||
|
|
|
|
c == '.' || c == '!' || c == '#' || c == '$' || c == '%' ||
|
|
|
|
c == '&' || c == '\''|| c == '*' || c == '+' || c == '-' ||
|
|
|
|
c == '/' || c == '=' || c == '?' || c == '^' || c == '_' ||
|
|
|
|
c == '`' || c == '{' || c == '|' || c == '}' || c == '~' )) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 18:31:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-30 12:13:35 +00:00
|
|
|
// Skip the '@'.
|
|
|
|
++i;
|
2010-08-18 18:31:54 +00:00
|
|
|
|
2013-04-10 22:05:07 +00:00
|
|
|
// The domain name can't begin with a dot or a dash.
|
|
|
|
if (value[i] == '.' || value[i] == '-') {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 18:31:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parsing the domain name.
|
|
|
|
for (; i < length; ++i) {
|
2014-01-04 15:02:17 +00:00
|
|
|
char16_t c = value[i];
|
2010-08-18 18:31:54 +00:00
|
|
|
|
|
|
|
if (c == '.') {
|
2013-04-10 22:05:07 +00:00
|
|
|
// A dot can't follow a dot or a dash.
|
|
|
|
if (value[i-1] == '.' || value[i-1] == '-') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (c == '-'){
|
|
|
|
// A dash can't follow a dot.
|
2012-02-29 22:35:47 +00:00
|
|
|
if (value[i-1] == '.') {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 18:31:54 +00:00
|
|
|
}
|
|
|
|
} else if (!(nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c) ||
|
|
|
|
c == '-')) {
|
|
|
|
// The domain characters have to be in this list to be valid.
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-08-18 18:31:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-08-18 18:31:54 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
NS_IMETHODIMP_(bool)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsSingleLineTextControl() const
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
return IsSingleLineTextControl(false);
|
2010-04-21 20:17:41 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
NS_IMETHODIMP_(bool)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsTextArea() const
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-04-21 20:17:41 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
NS_IMETHODIMP_(bool)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsPlainTextControl() const
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
|
|
|
// need to check our HTML attribute and/or CSS.
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-04-21 20:17:41 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
NS_IMETHODIMP_(bool)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::IsPasswordTextControl() const
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
|
|
|
return mType == NS_FORM_INPUT_PASSWORD;
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
NS_IMETHODIMP_(int32_t)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetCols()
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
|
|
|
// Else we know (assume) it is an input with size attr
|
|
|
|
const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::size);
|
|
|
|
if (attr && attr->Type() == nsAttrValue::eInteger) {
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t cols = attr->GetIntegerValue();
|
2010-04-21 20:17:41 +00:00
|
|
|
if (cols > 0) {
|
|
|
|
return cols;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return DEFAULT_COLS;
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
NS_IMETHODIMP_(int32_t)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetWrapCols()
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
|
|
|
return -1; // only textarea's can have wrap cols
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
NS_IMETHODIMP_(int32_t)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetRows()
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
|
|
|
return DEFAULT_ROWS;
|
|
|
|
}
|
|
|
|
|
2013-03-25 19:35:55 +00:00
|
|
|
NS_IMETHODIMP_(void)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetDefaultValueFromContent(nsAString& aValue)
|
2013-03-25 19:35:55 +00:00
|
|
|
{
|
|
|
|
nsTextEditorState *state = GetEditorState();
|
|
|
|
if (state) {
|
|
|
|
GetDefaultValue(aValue);
|
|
|
|
// This is called by the frame to show the value.
|
|
|
|
// We have to sanitize it when needed.
|
|
|
|
if (!mParserCreating) {
|
|
|
|
SanitizeValue(aValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
NS_IMETHODIMP_(bool)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::ValueChanged() const
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2011-11-16 07:50:19 +00:00
|
|
|
return mValueChanged;
|
2010-04-21 20:17:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(void)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetTextEditorValue(nsAString& aValue,
|
|
|
|
bool aIgnoreWrap) const
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-04-21 20:17:41 +00:00
|
|
|
if (state) {
|
|
|
|
state->GetValue(aValue, aIgnoreWrap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP_(void)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::InitializeKeyboardEventListeners()
|
2010-04-21 20:17:41 +00:00
|
|
|
{
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2010-04-21 20:17:41 +00:00
|
|
|
if (state) {
|
|
|
|
state->InitializeKeyboardEventListeners();
|
|
|
|
}
|
|
|
|
}
|
2010-08-21 17:52:57 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP_(void)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::OnValueChanged(bool aNotify)
|
2010-08-21 17:52:57 +00:00
|
|
|
{
|
|
|
|
UpdateAllValidityStates(aNotify);
|
2012-11-21 10:13:57 +00:00
|
|
|
|
|
|
|
if (HasDirAuto()) {
|
|
|
|
SetDirectionIfAuto(true, aNotify);
|
|
|
|
}
|
2010-08-21 17:52:57 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
NS_IMETHODIMP_(bool)
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::HasCachedSelection()
|
2011-07-29 21:31:57 +00:00
|
|
|
{
|
2011-09-29 06:19:26 +00:00
|
|
|
bool isCached = false;
|
2013-03-28 19:41:32 +00:00
|
|
|
nsTextEditorState* state = GetEditorState();
|
2011-07-29 21:31:57 +00:00
|
|
|
if (state) {
|
|
|
|
isCached = state->IsSelectionCached() &&
|
|
|
|
state->HasNeverInitializedBefore() &&
|
|
|
|
!state->GetSelectionProperties().IsDefault();
|
|
|
|
if (isCached) {
|
|
|
|
state->WillInitEagerly();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return isCached;
|
|
|
|
}
|
|
|
|
|
2010-09-18 21:33:16 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::FieldSetDisabledChanged(bool aNotify)
|
2010-09-18 21:33:16 +00:00
|
|
|
{
|
|
|
|
UpdateValueMissingValidityState();
|
|
|
|
UpdateBarredFromConstraintValidation();
|
|
|
|
|
2013-08-02 01:21:31 +00:00
|
|
|
nsGenericHTMLFormElementWithState::FieldSetDisabledChanged(aNotify);
|
2010-09-18 21:33:16 +00:00
|
|
|
}
|
|
|
|
|
2012-06-06 12:16:58 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::SetFilePickerFiltersFromAccept(nsIFilePicker* filePicker)
|
2012-06-06 12:16:58 +00:00
|
|
|
{
|
|
|
|
// We always add |filterAll|
|
|
|
|
filePicker->AppendFilters(nsIFilePicker::filterAll);
|
|
|
|
|
|
|
|
NS_ASSERTION(HasAttr(kNameSpaceID_None, nsGkAtoms::accept),
|
|
|
|
"You should not call SetFilePickerFiltersFromAccept if the"
|
|
|
|
" element has no accept attribute!");
|
|
|
|
|
|
|
|
// Services to retrieve image/*, audio/*, video/* filters
|
|
|
|
nsCOMPtr<nsIStringBundleService> stringService =
|
|
|
|
mozilla::services::GetStringBundleService();
|
|
|
|
if (!stringService) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIStringBundle> filterBundle;
|
|
|
|
if (NS_FAILED(stringService->CreateBundle("chrome://global/content/filepicker.properties",
|
|
|
|
getter_AddRefs(filterBundle)))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Service to retrieve mime type information for mime types filters
|
|
|
|
nsCOMPtr<nsIMIMEService> mimeService = do_GetService("@mozilla.org/mime;1");
|
|
|
|
if (!mimeService) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsAutoString accept;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::accept, accept);
|
|
|
|
|
|
|
|
HTMLSplitOnSpacesTokenizer tokenizer(accept, ',');
|
|
|
|
|
|
|
|
nsTArray<nsFilePickerFilter> filters;
|
|
|
|
nsString allExtensionsList;
|
|
|
|
|
2014-11-29 11:22:30 +00:00
|
|
|
bool allMimeTypeFiltersAreValid = true;
|
|
|
|
bool atLeastOneFileExtensionFilter = false;
|
2014-10-28 23:32:28 +00:00
|
|
|
|
2012-06-06 12:16:58 +00:00
|
|
|
// Retrieve all filters
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
|
|
const nsDependentSubstring& token = tokenizer.nextToken();
|
|
|
|
|
|
|
|
if (token.IsEmpty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t filterMask = 0;
|
2012-06-06 12:16:58 +00:00
|
|
|
nsString filterName;
|
|
|
|
nsString extensionListStr;
|
|
|
|
|
|
|
|
// First, check for image/audio/video filters...
|
|
|
|
if (token.EqualsLiteral("image/*")) {
|
|
|
|
filterMask = nsIFilePicker::filterImages;
|
2013-12-13 01:50:01 +00:00
|
|
|
filterBundle->GetStringFromName(MOZ_UTF16("imageFilter"),
|
2012-06-06 12:16:58 +00:00
|
|
|
getter_Copies(extensionListStr));
|
|
|
|
} else if (token.EqualsLiteral("audio/*")) {
|
|
|
|
filterMask = nsIFilePicker::filterAudio;
|
2013-12-13 01:50:01 +00:00
|
|
|
filterBundle->GetStringFromName(MOZ_UTF16("audioFilter"),
|
2012-06-06 12:16:58 +00:00
|
|
|
getter_Copies(extensionListStr));
|
|
|
|
} else if (token.EqualsLiteral("video/*")) {
|
|
|
|
filterMask = nsIFilePicker::filterVideo;
|
2013-12-13 01:50:01 +00:00
|
|
|
filterBundle->GetStringFromName(MOZ_UTF16("videoFilter"),
|
2012-06-06 12:16:58 +00:00
|
|
|
getter_Copies(extensionListStr));
|
2014-11-29 11:22:30 +00:00
|
|
|
} else if (token.First() == '.') {
|
|
|
|
extensionListStr = NS_LITERAL_STRING("*") + token;
|
|
|
|
filterName = extensionListStr + NS_LITERAL_STRING("; ");
|
|
|
|
atLeastOneFileExtensionFilter = true;
|
2012-06-06 12:16:58 +00:00
|
|
|
} else {
|
|
|
|
//... if no image/audio/video filter is found, check mime types filters
|
|
|
|
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
|
|
|
if (NS_FAILED(mimeService->GetFromTypeAndExtension(
|
|
|
|
NS_ConvertUTF16toUTF8(token),
|
|
|
|
EmptyCString(), // No extension
|
|
|
|
getter_AddRefs(mimeInfo))) ||
|
|
|
|
!mimeInfo) {
|
2014-11-29 11:22:30 +00:00
|
|
|
allMimeTypeFiltersAreValid = false;
|
2012-06-06 12:16:58 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-08-05 11:18:08 +00:00
|
|
|
// Get a name for the filter: first try the description, then the mime type
|
|
|
|
// name if there is no description
|
|
|
|
mimeInfo->GetDescription(filterName);
|
|
|
|
if (filterName.IsEmpty()) {
|
|
|
|
nsCString mimeTypeName;
|
|
|
|
mimeInfo->GetType(mimeTypeName);
|
|
|
|
CopyUTF8toUTF16(mimeTypeName, filterName);
|
|
|
|
}
|
2012-06-06 12:16:58 +00:00
|
|
|
|
|
|
|
// Get extension list
|
|
|
|
nsCOMPtr<nsIUTF8StringEnumerator> extensions;
|
|
|
|
mimeInfo->GetFileExtensions(getter_AddRefs(extensions));
|
|
|
|
|
|
|
|
bool hasMore;
|
|
|
|
while (NS_SUCCEEDED(extensions->HasMore(&hasMore)) && hasMore) {
|
|
|
|
nsCString extension;
|
|
|
|
if (NS_FAILED(extensions->GetNext(extension))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!extensionListStr.IsEmpty()) {
|
|
|
|
extensionListStr.AppendLiteral("; ");
|
|
|
|
}
|
|
|
|
extensionListStr += NS_LITERAL_STRING("*.") +
|
|
|
|
NS_ConvertUTF8toUTF16(extension);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!filterMask && (extensionListStr.IsEmpty() || filterName.IsEmpty())) {
|
|
|
|
// No valid filter found
|
2014-11-29 11:22:30 +00:00
|
|
|
allMimeTypeFiltersAreValid = false;
|
2012-06-06 12:16:58 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we arrived here, that means we have a valid filter: let's create it
|
|
|
|
// and add it to our list, if no similar filter is already present
|
|
|
|
nsFilePickerFilter filter;
|
|
|
|
if (filterMask) {
|
|
|
|
filter = nsFilePickerFilter(filterMask);
|
|
|
|
} else {
|
|
|
|
filter = nsFilePickerFilter(filterName, extensionListStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!filters.Contains(filter)) {
|
|
|
|
if (!allExtensionsList.IsEmpty()) {
|
|
|
|
allExtensionsList.AppendLiteral("; ");
|
|
|
|
}
|
|
|
|
allExtensionsList += extensionListStr;
|
|
|
|
filters.AppendElement(filter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-18 23:30:11 +00:00
|
|
|
// Remove similar filters
|
|
|
|
// Iterate over a copy, as we might modify the original filters list
|
|
|
|
nsTArray<nsFilePickerFilter> filtersCopy;
|
|
|
|
filtersCopy = filters;
|
|
|
|
for (uint32_t i = 0; i < filtersCopy.Length(); ++i) {
|
|
|
|
const nsFilePickerFilter& filterToCheck = filtersCopy[i];
|
|
|
|
if (filterToCheck.mFilterMask) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (uint32_t j = 0; j < filtersCopy.Length(); ++j) {
|
|
|
|
if (i == j) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (FindInReadable(filterToCheck.mFilter, filtersCopy[j].mFilter)) {
|
|
|
|
// We already have a similar, less restrictive filter (i.e.
|
|
|
|
// filterToCheck extensionList is just a subset of another filter
|
|
|
|
// extension list): remove this one
|
|
|
|
filters.RemoveElement(filterToCheck);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-06 12:16:58 +00:00
|
|
|
// Add "All Supported Types" filter
|
|
|
|
if (filters.Length() > 1) {
|
|
|
|
nsXPIDLString title;
|
|
|
|
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
|
|
|
"AllSupportedTypes", title);
|
|
|
|
filePicker->AppendFilter(title, allExtensionsList);
|
|
|
|
}
|
|
|
|
|
2014-10-28 23:32:28 +00:00
|
|
|
// Add each filter
|
2012-08-22 15:56:38 +00:00
|
|
|
for (uint32_t i = 0; i < filters.Length(); ++i) {
|
2012-06-06 12:16:58 +00:00
|
|
|
const nsFilePickerFilter& filter = filters[i];
|
|
|
|
if (filter.mFilterMask) {
|
|
|
|
filePicker->AppendFilters(filter.mFilterMask);
|
|
|
|
} else {
|
|
|
|
filePicker->AppendFilter(filter.mTitle, filter.mFilter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-29 11:22:30 +00:00
|
|
|
if (filters.Length() >= 1 &&
|
|
|
|
(allMimeTypeFiltersAreValid || atLeastOneFileExtensionFilter)) {
|
2012-06-06 12:16:58 +00:00
|
|
|
// |filterAll| will always use index=0 so we need to set index=1 as the
|
|
|
|
// current filter.
|
|
|
|
filePicker->SetFilterIndex(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetStepScaleFactor() const
|
2012-12-22 14:46:19 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(DoesStepApply());
|
|
|
|
|
|
|
|
switch (mType) {
|
|
|
|
case NS_FORM_INPUT_DATE:
|
|
|
|
return kStepScaleFactorDate;
|
|
|
|
case NS_FORM_INPUT_NUMBER:
|
2013-02-16 12:35:57 +00:00
|
|
|
case NS_FORM_INPUT_RANGE:
|
|
|
|
return kStepScaleFactorNumberRange;
|
2013-02-06 22:56:49 +00:00
|
|
|
case NS_FORM_INPUT_TIME:
|
|
|
|
return kStepScaleFactorTime;
|
|
|
|
default:
|
2013-04-18 20:33:14 +00:00
|
|
|
MOZ_ASSERT(false, "Unrecognized input type");
|
2013-05-05 23:23:18 +00:00
|
|
|
return Decimal::nan();
|
2013-02-06 22:56:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::GetDefaultStep() const
|
2013-02-06 22:56:49 +00:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(DoesStepApply());
|
|
|
|
|
|
|
|
switch (mType) {
|
|
|
|
case NS_FORM_INPUT_DATE:
|
|
|
|
case NS_FORM_INPUT_NUMBER:
|
2013-02-16 12:35:57 +00:00
|
|
|
case NS_FORM_INPUT_RANGE:
|
2013-02-06 22:56:49 +00:00
|
|
|
return kDefaultStep;
|
|
|
|
case NS_FORM_INPUT_TIME:
|
|
|
|
return kDefaultStepTime;
|
2012-12-22 14:46:19 +00:00
|
|
|
default:
|
2013-04-18 20:33:14 +00:00
|
|
|
MOZ_ASSERT(false, "Unrecognized input type");
|
2013-05-05 23:23:18 +00:00
|
|
|
return Decimal::nan();
|
2012-12-22 14:46:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-20 11:02:37 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateValidityUIBits(bool aIsFocused)
|
2011-01-20 11:02:37 +00:00
|
|
|
{
|
|
|
|
if (aIsFocused) {
|
|
|
|
// If the invalid UI is shown, we should show it while focusing (and
|
|
|
|
// update). Otherwise, we should not.
|
2011-11-16 07:50:19 +00:00
|
|
|
mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI();
|
2011-01-20 11:02:37 +00:00
|
|
|
|
|
|
|
// If neither invalid UI nor valid UI is shown, we shouldn't show the valid
|
|
|
|
// UI while typing.
|
2011-11-16 07:50:19 +00:00
|
|
|
mCanShowValidUI = ShouldShowValidityUI();
|
2011-01-20 11:02:37 +00:00
|
|
|
} else {
|
2011-11-16 07:50:19 +00:00
|
|
|
mCanShowInvalidUI = true;
|
|
|
|
mCanShowValidUI = true;
|
2011-01-20 11:02:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-22 09:41:32 +00:00
|
|
|
void
|
2013-03-28 19:41:32 +00:00
|
|
|
HTMLInputElement::UpdateHasRange()
|
2012-06-22 09:41:32 +00:00
|
|
|
{
|
2013-01-31 23:00:08 +00:00
|
|
|
/*
|
|
|
|
* There is a range if min/max applies for the type and if the element
|
|
|
|
* currently have a valid min or max.
|
|
|
|
*/
|
|
|
|
|
2012-06-22 09:41:32 +00:00
|
|
|
mHasRange = false;
|
|
|
|
|
2013-01-31 23:00:08 +00:00
|
|
|
if (!DoesMinMaxApply()) {
|
2012-06-22 09:41:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal minimum = GetMinimum();
|
|
|
|
if (!minimum.isNaN()) {
|
2012-07-06 12:40:18 +00:00
|
|
|
mHasRange = true;
|
|
|
|
return;
|
2012-06-22 09:41:32 +00:00
|
|
|
}
|
|
|
|
|
2013-05-05 23:23:18 +00:00
|
|
|
Decimal maximum = GetMaximum();
|
|
|
|
if (!maximum.isNaN()) {
|
2012-07-06 12:40:18 +00:00
|
|
|
mHasRange = true;
|
|
|
|
return;
|
2012-06-22 09:41:32 +00:00
|
|
|
}
|
|
|
|
}
|
2013-03-28 19:41:32 +00:00
|
|
|
|
2013-12-07 12:09:14 +00:00
|
|
|
void
|
|
|
|
HTMLInputElement::PickerClosed()
|
|
|
|
{
|
|
|
|
mPickerRunning = false;
|
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
JSObject*
|
2014-04-08 22:27:17 +00:00
|
|
|
HTMLInputElement::WrapNode(JSContext* aCx)
|
2013-03-28 19:41:32 +00:00
|
|
|
{
|
Bug 991742 part 6. Remove the "aScope" argument of binding Wrap() methods. r=bholley
This patch was mostly generated with this command:
find . -name "*.h" -o -name "*.cpp" | xargs sed -e 's/Binding::Wrap(aCx, aScope, this/Binding::Wrap(aCx, this/' -e 's/Binding_workers::Wrap(aCx, aScope, this/Binding_workers::Wrap(aCx, this/' -e 's/Binding::Wrap(cx, scope, this/Binding::Wrap(cx, this/' -i ""
plus a few manual fixes to dom/bindings/Codegen.py, js/xpconnect/src/event_impl_gen.py, and a few C++ files that were not caught in the search-and-replace above.
2014-04-08 22:27:17 +00:00
|
|
|
return HTMLInputElementBinding::Wrap(aCx, this);
|
2013-03-28 19:41:32 +00:00
|
|
|
}
|
|
|
|
|
2013-03-28 19:41:32 +00:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|
2013-11-19 19:21:29 +00:00
|
|
|
|
|
|
|
#undef NS_ORIGINAL_CHECKED_VALUE
|