Skip to content

Commit

Permalink
HTML - support for elements: <details> and <summary> (basic)
Browse files Browse the repository at this point in the history
  • Loading branch information
janekptacijarabaci committed Apr 13, 2017
1 parent 82be21d commit b2328d0
Show file tree
Hide file tree
Showing 119 changed files with 3,028 additions and 191 deletions.
2 changes: 1 addition & 1 deletion accessible/tests/mochitest/elm/test_HTMLSpec.html
Expand Up @@ -374,7 +374,7 @@
//////////////////////////////////////////////////////////////////////////
// HTML:details

todo(isAccessible("details"), "details element is not accessible");
ok(isAccessible("details"), "details element is not accessible");

//////////////////////////////////////////////////////////////////////////
// HTML:dfn contained by paragraph
Expand Down
2 changes: 2 additions & 0 deletions dom/base/nsGkAtomList.h
Expand Up @@ -1905,6 +1905,7 @@ GK_ATOM(columnSetFrame, "ColumnSetFrame")
GK_ATOM(comboboxControlFrame, "ComboboxControlFrame")
GK_ATOM(comboboxDisplayFrame, "ComboboxDisplayFrame")
GK_ATOM(deckFrame, "DeckFrame")
GK_ATOM(detailsFrame, "DetailsFrame")
GK_ATOM(fieldSetFrame, "FieldSetFrame")
GK_ATOM(flexContainerFrame, "FlexContainerFrame")
GK_ATOM(formControlFrame, "FormControlFrame") // radio or checkbox
Expand Down Expand Up @@ -1944,6 +1945,7 @@ GK_ATOM(scrollFrame, "ScrollFrame")
GK_ATOM(scrollbarFrame, "ScrollbarFrame")
GK_ATOM(sequenceFrame, "SequenceFrame")
GK_ATOM(sliderFrame, "sliderFrame")
GK_ATOM(summaryFrame, "SummaryFrame")
GK_ATOM(tableCellFrame, "TableCellFrame")
GK_ATOM(tableColFrame, "TableColFrame")
GK_ATOM(tableColGroupFrame, "TableColGroupFrame")
Expand Down
3 changes: 2 additions & 1 deletion dom/events/EventStateManager.cpp
Expand Up @@ -4447,7 +4447,8 @@ EventStateManager::CheckForAndDispatchClick(nsPresContext* aPresContext,
nsWeakFrame currentTarget = mCurrentTarget;
ret = presShell->HandleEventWithTarget(&event, currentTarget,
mouseContent, aStatus);
if (NS_SUCCEEDED(ret) && aEvent->clickCount == 2) {
if (NS_SUCCEEDED(ret) && aEvent->clickCount == 2 &&
mouseContent && mouseContent->IsInComposedDoc()) {
//fire double click
WidgetMouseEvent event2(aEvent->mFlags.mIsTrusted, NS_MOUSE_DOUBLECLICK,
aEvent->widget, WidgetMouseEvent::eReal);
Expand Down
81 changes: 81 additions & 0 deletions dom/html/HTMLDetailsElement.cpp
@@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/dom/HTMLDetailsElement.h"

#include "mozilla/dom/HTMLDetailsElementBinding.h"
#include "mozilla/dom/HTMLUnknownElement.h"
#include "mozilla/Preferences.h"

// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Details) to add pref check.
nsGenericHTMLElement*
NS_NewHTMLDetailsElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser)
{
if (!mozilla::dom::HTMLDetailsElement::IsDetailsEnabled()) {
return new mozilla::dom::HTMLUnknownElement(aNodeInfo);
}

return new mozilla::dom::HTMLDetailsElement(aNodeInfo);
}

namespace mozilla {
namespace dom {

bool
HTMLDetailsElement::IsDetailsEnabled()
{
static bool isDetailsEnabled = false;
static bool added = false;

if (!added) {
Preferences::AddBoolVarCache(&isDetailsEnabled,
"dom.details_element.enabled");
added = true;
}

return isDetailsEnabled;
}

HTMLDetailsElement::~HTMLDetailsElement()
{
}

NS_IMPL_ELEMENT_CLONE(HTMLDetailsElement)

nsIContent*
HTMLDetailsElement::GetFirstSummary() const
{
// XXX: Bug 1245032: Might want to cache the first summary element.
for (nsIContent* child = nsINode::GetFirstChild();
child;
child = child->GetNextSibling()) {
if (child->IsHTML(nsGkAtoms::summary)) {
return child;
}
}
return nullptr;
}

nsChangeHint
HTMLDetailsElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
int32_t aModType) const
{
nsChangeHint hint =
nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
if (aAttribute == nsGkAtoms::open) {
NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
}
return hint;
}

JSObject*
HTMLDetailsElement::WrapNode(JSContext* aCx)
{
return HTMLDetailsElementBinding::Wrap(aCx, this);
}

} // namespace dom
} // namespace mozilla
62 changes: 62 additions & 0 deletions dom/html/HTMLDetailsElement.h
@@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_HTMLDetailsElement_h
#define mozilla_dom_HTMLDetailsElement_h

#include "mozilla/Attributes.h"
#include "nsGenericHTMLElement.h"

namespace mozilla {
class ErrorResult;
namespace dom {

// HTMLDetailsElement implements the <details> tag, which is used as a
// disclosure widget from which the user can obtain additional information or
// controls. Please see the spec for more information.
// https://html.spec.whatwg.org/multipage/forms.html#the-details-element
//
class HTMLDetailsElement final : public nsGenericHTMLElement
{
public:
explicit HTMLDetailsElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);

static bool IsDetailsEnabled();

NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLDetailsElement, details)

nsIContent* GetFirstSummary() const;

nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode** aResult) const override;

nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
int32_t aModType) const override;

// HTMLDetailsElement WebIDL
bool Open() const { return GetBoolAttr(nsGkAtoms::open); }

void SetOpen(bool aOpen, ErrorResult& aError)
{
// TODO: Bug 1225412: Need to follow the spec to fire "toggle" event.
SetHTMLBoolAttr(nsGkAtoms::open, aOpen, aError);
}

void ToggleOpen()
{
ErrorResult rv;
SetOpen(!Open(), rv);
rv.SuppressException();
}

protected:
virtual ~HTMLDetailsElement();

virtual JSObject* WrapNode(JSContext* aCx) override;
};

} // namespace dom
} // namespace mozilla

#endif /* mozilla_dom_HTMLDetailsElement_h */
99 changes: 99 additions & 0 deletions dom/html/HTMLSummaryElement.cpp
@@ -0,0 +1,99 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/dom/HTMLSummaryElement.h"

#include "mozilla/dom/HTMLDetailsElement.h"
#include "mozilla/dom/HTMLElementBinding.h"
#include "mozilla/dom/HTMLUnknownElement.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Preferences.h"

// Expand NS_IMPL_NS_NEW_HTML_ELEMENT(Summary) to add pref check.
nsGenericHTMLElement*
NS_NewHTMLSummaryElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser)
{
if (!mozilla::dom::HTMLDetailsElement::IsDetailsEnabled()) {
return new mozilla::dom::HTMLUnknownElement(aNodeInfo);
}

return new mozilla::dom::HTMLSummaryElement(aNodeInfo);
}

namespace mozilla {
namespace dom {

HTMLSummaryElement::~HTMLSummaryElement()
{
}

NS_IMPL_ELEMENT_CLONE(HTMLSummaryElement)

nsresult
HTMLSummaryElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
{
nsresult rv = NS_OK;
if (!aVisitor.mPresContext) {
return rv;
}

if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
return rv;
}

auto toggleDetails = false;
auto* event = aVisitor.mEvent;

if (event->HasMouseEventMessage()) {
auto* mouseEvent = event->AsMouseEvent();
toggleDetails = mouseEvent->IsLeftClickEvent();
}

// Todo: Bug 634004: Implement toggle details by keyboard.

if (!toggleDetails || !IsMainSummary()) {
return rv;
}

auto* details = GetDetails();
MOZ_ASSERT(details, "Expected to find details since this is the main summary!");

// When dispatching a synthesized mouse click event to a details with
// 'display: none', both Chrome and Safari do not toggle the 'open' attribute.
// We follow them by checking whether details has a frame or not.
if (details->GetPrimaryFrame()) {
details->ToggleOpen();
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
}

return rv;
}

bool
HTMLSummaryElement::IsMainSummary() const
{
HTMLDetailsElement* details = GetDetails();
if (!details) {
return false;
}

return details->GetFirstSummary() == this || IsRootOfNativeAnonymousSubtree();
}

HTMLDetailsElement*
HTMLSummaryElement::GetDetails() const
{
return HTMLDetailsElement::FromContentOrNull(GetParent());
}

JSObject*
HTMLSummaryElement::WrapNode(JSContext* aCx)
{
return HTMLElementBinding::Wrap(aCx, this);
}

} // namespace dom
} // namespace mozilla
49 changes: 49 additions & 0 deletions dom/html/HTMLSummaryElement.h
@@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_HTMLSummaryElement_h
#define mozilla_dom_HTMLSummaryElement_h

#include "mozilla/Attributes.h"
#include "nsGenericHTMLElement.h"

namespace mozilla {
class EventChainPostVisitor;
namespace dom {
class HTMLDetailsElement;

// HTMLSummaryElement implements the <summary> tag, which is used as a summary
// or legend of the <details> tag. Please see the spec for more information.
// https://html.spec.whatwg.org/multipage/forms.html#the-details-element
//
class HTMLSummaryElement final : public nsGenericHTMLElement
{
public:
explicit HTMLSummaryElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);

NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLSummaryElement, summary)

nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode** aResult) const override;

nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;

// Return true if this is the first summary element child of a details or the
// default summary element generated by DetailsFrame.
bool IsMainSummary() const;

// Return the details element which contains this summary. Otherwise return
// nullptr if there is no such details element.
HTMLDetailsElement* GetDetails() const;

protected:
virtual ~HTMLSummaryElement();

virtual JSObject* WrapNode(JSContext* aCx) override;
};

} // namespace dom
} // namespace mozilla

#endif /* mozilla_dom_HTMLSummaryElement_h */
4 changes: 4 additions & 0 deletions dom/html/moz.build
Expand Up @@ -56,6 +56,7 @@ EXPORTS.mozilla.dom += [
'HTMLContentElement.h',
'HTMLDataElement.h',
'HTMLDataListElement.h',
'HTMLDetailsElement.h',
'HTMLDivElement.h',
'HTMLFieldSetElement.h',
'HTMLFontElement.h',
Expand Down Expand Up @@ -97,6 +98,7 @@ EXPORTS.mozilla.dom += [
'HTMLSourceElement.h',
'HTMLSpanElement.h',
'HTMLStyleElement.h',
'HTMLSummaryElement.h',
'HTMLTableCaptionElement.h',
'HTMLTableCellElement.h',
'HTMLTableColElement.h',
Expand Down Expand Up @@ -132,6 +134,7 @@ UNIFIED_SOURCES += [
'HTMLContentElement.cpp',
'HTMLDataElement.cpp',
'HTMLDataListElement.cpp',
'HTMLDetailsElement.cpp',
'HTMLDivElement.cpp',
'HTMLElement.cpp',
'HTMLFieldSetElement.cpp',
Expand Down Expand Up @@ -175,6 +178,7 @@ UNIFIED_SOURCES += [
'HTMLSourceElement.cpp',
'HTMLSpanElement.cpp',
'HTMLStyleElement.cpp',
'HTMLSummaryElement.cpp',
'HTMLTableCaptionElement.cpp',
'HTMLTableCellElement.cpp',
'HTMLTableColElement.cpp',
Expand Down
2 changes: 2 additions & 0 deletions dom/html/nsGenericHTMLElement.h
Expand Up @@ -1728,6 +1728,7 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(Content)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Mod)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Data)
NS_DECLARE_NS_NEW_HTML_ELEMENT(DataList)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Details)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Div)
NS_DECLARE_NS_NEW_HTML_ELEMENT(FieldSet)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Font)
Expand Down Expand Up @@ -1764,6 +1765,7 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(Shadow)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Source)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Span)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Style)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Summary)
NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCaption)
NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCell)
NS_DECLARE_NS_NEW_HTML_ELEMENT(TableCol)
Expand Down
2 changes: 2 additions & 0 deletions dom/tests/mochitest/general/test_interfaces.html
Expand Up @@ -466,6 +466,8 @@
"HTMLDataElement",
// IMPORTANT: Do not change this list without review from a DOM peer!
"HTMLDataListElement",
// IMPORTANT: Do not change this list without review from a DOM peer!
"HTMLDetailsElement",
// IMPORTANT: Do not change this list without review from a DOM peer!
"HTMLDirectoryElement",
// IMPORTANT: Do not change this list without review from a DOM peer!
Expand Down

0 comments on commit b2328d0

Please sign in to comment.