summaryrefslogtreecommitdiffstats
path: root/dom/html/HTMLMenuElement.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /dom/html/HTMLMenuElement.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/html/HTMLMenuElement.cpp')
-rw-r--r--dom/html/HTMLMenuElement.cpp268
1 files changed, 268 insertions, 0 deletions
diff --git a/dom/html/HTMLMenuElement.cpp b/dom/html/HTMLMenuElement.cpp
new file mode 100644
index 000000000..098590f1b
--- /dev/null
+++ b/dom/html/HTMLMenuElement.cpp
@@ -0,0 +1,268 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/HTMLMenuElement.h"
+
+#include "mozilla/BasicEvents.h"
+#include "mozilla/EventDispatcher.h"
+#include "mozilla/dom/HTMLMenuElementBinding.h"
+#include "mozilla/dom/HTMLMenuItemElement.h"
+#include "nsIMenuBuilder.h"
+#include "nsAttrValueInlines.h"
+#include "nsContentUtils.h"
+#include "nsIURI.h"
+
+#define HTMLMENUBUILDER_CONTRACTID "@mozilla.org/content/html-menu-builder;1"
+
+NS_IMPL_NS_NEW_HTML_ELEMENT(Menu)
+
+namespace mozilla {
+namespace dom {
+
+enum MenuType : uint8_t
+{
+ MENU_TYPE_CONTEXT = 1,
+ MENU_TYPE_TOOLBAR,
+ MENU_TYPE_LIST
+};
+
+static const nsAttrValue::EnumTable kMenuTypeTable[] = {
+ { "context", MENU_TYPE_CONTEXT },
+ { "toolbar", MENU_TYPE_TOOLBAR },
+ { "list", MENU_TYPE_LIST },
+ { nullptr, 0 }
+};
+
+static const nsAttrValue::EnumTable* kMenuDefaultType =
+ &kMenuTypeTable[2];
+
+enum SeparatorType
+{
+ ST_TRUE_INIT = -1,
+ ST_FALSE = 0,
+ ST_TRUE = 1
+};
+
+
+
+HTMLMenuElement::HTMLMenuElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+ : nsGenericHTMLElement(aNodeInfo), mType(MENU_TYPE_LIST)
+{
+}
+
+HTMLMenuElement::~HTMLMenuElement()
+{
+}
+
+NS_IMPL_ISUPPORTS_INHERITED(HTMLMenuElement, nsGenericHTMLElement,
+ nsIDOMHTMLMenuElement, nsIHTMLMenu)
+
+NS_IMPL_ELEMENT_CLONE(HTMLMenuElement)
+
+NS_IMPL_BOOL_ATTR(HTMLMenuElement, Compact, compact)
+NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLMenuElement, Type, type,
+ kMenuDefaultType->tag)
+NS_IMPL_STRING_ATTR(HTMLMenuElement, Label, label)
+
+
+NS_IMETHODIMP
+HTMLMenuElement::SendShowEvent()
+{
+ NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
+
+ nsCOMPtr<nsIDocument> document = GetComposedDoc();
+ if (!document) {
+ return NS_ERROR_FAILURE;
+ }
+
+ WidgetEvent event(true, eShow);
+ event.mFlags.mBubbles = false;
+ event.mFlags.mCancelable = false;
+
+ nsCOMPtr<nsIPresShell> shell = document->GetShell();
+ if (!shell) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<nsPresContext> presContext = shell->GetPresContext();
+ nsEventStatus status = nsEventStatus_eIgnore;
+ EventDispatcher::Dispatch(static_cast<nsIContent*>(this), presContext,
+ &event, nullptr, &status);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+HTMLMenuElement::CreateBuilder(nsIMenuBuilder** _retval)
+{
+ NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
+
+ nsCOMPtr<nsIMenuBuilder> builder = CreateBuilder();
+ builder.swap(*_retval);
+ return NS_OK;
+}
+
+already_AddRefed<nsIMenuBuilder>
+HTMLMenuElement::CreateBuilder()
+{
+ if (mType != MENU_TYPE_CONTEXT) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIMenuBuilder> builder = do_CreateInstance(HTMLMENUBUILDER_CONTRACTID);
+ NS_WARNING_ASSERTION(builder, "No builder available");
+ return builder.forget();
+}
+
+NS_IMETHODIMP
+HTMLMenuElement::Build(nsIMenuBuilder* aBuilder)
+{
+ NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_DOM_SECURITY_ERR);
+
+ if (!aBuilder) {
+ return NS_OK;
+ }
+
+ BuildSubmenu(EmptyString(), this, aBuilder);
+
+ return NS_OK;
+}
+
+
+bool
+HTMLMenuElement::ParseAttribute(int32_t aNamespaceID,
+ nsIAtom* aAttribute,
+ const nsAString& aValue,
+ nsAttrValue& aResult)
+{
+ if (aNamespaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::type) {
+ bool success = aResult.ParseEnumValue(aValue, kMenuTypeTable,
+ false);
+ if (success) {
+ mType = aResult.GetEnumValue();
+ } else {
+ mType = kMenuDefaultType->value;
+ }
+
+ return success;
+ }
+
+ return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
+ aResult);
+}
+
+void
+HTMLMenuElement::BuildSubmenu(const nsAString& aLabel,
+ nsIContent* aContent,
+ nsIMenuBuilder* aBuilder)
+{
+ aBuilder->OpenContainer(aLabel);
+
+ int8_t separator = ST_TRUE_INIT;
+ TraverseContent(aContent, aBuilder, separator);
+
+ if (separator == ST_TRUE) {
+ aBuilder->UndoAddSeparator();
+ }
+
+ aBuilder->CloseContainer();
+}
+
+// static
+bool
+HTMLMenuElement::CanLoadIcon(nsIContent* aContent, const nsAString& aIcon)
+{
+ if (aIcon.IsEmpty()) {
+ return false;
+ }
+
+ nsIDocument* doc = aContent->OwnerDoc();
+
+ nsCOMPtr<nsIURI> baseURI = aContent->GetBaseURI();
+ nsCOMPtr<nsIURI> uri;
+ nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri), aIcon, doc,
+ baseURI);
+
+ if (!uri) {
+ return false;
+ }
+
+ return nsContentUtils::CanLoadImage(uri, aContent, doc,
+ aContent->NodePrincipal());
+}
+
+void
+HTMLMenuElement::TraverseContent(nsIContent* aContent,
+ nsIMenuBuilder* aBuilder,
+ int8_t& aSeparator)
+{
+ nsCOMPtr<nsIContent> child;
+ for (child = aContent->GetFirstChild(); child;
+ child = child->GetNextSibling()) {
+ nsGenericHTMLElement* element = nsGenericHTMLElement::FromContent(child);
+ if (!element) {
+ continue;
+ }
+
+ if (child->IsHTMLElement(nsGkAtoms::menuitem)) {
+ HTMLMenuItemElement* menuitem = HTMLMenuItemElement::FromContent(child);
+
+ if (menuitem->IsHidden()) {
+ continue;
+ }
+
+ nsAutoString label;
+ menuitem->GetLabel(label);
+ if (label.IsEmpty()) {
+ continue;
+ }
+
+ nsAutoString icon;
+ menuitem->GetIcon(icon);
+
+ aBuilder->AddItemFor(menuitem, CanLoadIcon(child, icon));
+
+ aSeparator = ST_FALSE;
+ } else if (child->IsHTMLElement(nsGkAtoms::hr)) {
+ aBuilder->AddSeparator();
+ } else if (child->IsHTMLElement(nsGkAtoms::menu) && !element->IsHidden()) {
+ if (child->HasAttr(kNameSpaceID_None, nsGkAtoms::label)) {
+ nsAutoString label;
+ child->GetAttr(kNameSpaceID_None, nsGkAtoms::label, label);
+
+ BuildSubmenu(label, child, aBuilder);
+
+ aSeparator = ST_FALSE;
+ } else {
+ AddSeparator(aBuilder, aSeparator);
+
+ TraverseContent(child, aBuilder, aSeparator);
+
+ AddSeparator(aBuilder, aSeparator);
+ }
+ }
+ }
+}
+
+inline void
+HTMLMenuElement::AddSeparator(nsIMenuBuilder* aBuilder, int8_t& aSeparator)
+{
+ if (aSeparator) {
+ return;
+ }
+
+ aBuilder->AddSeparator();
+ aSeparator = ST_TRUE;
+}
+
+JSObject*
+HTMLMenuElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return HTMLMenuElementBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace dom
+} // namespace mozilla