📄 htmlelement.cpp
字号:
/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */#include "config.h"#include "HTMLElement.h"#include "CSSPropertyNames.h"#include "CSSValueKeywords.h"#include "DocumentFragment.h"#include "Event.h"#include "EventListener.h"#include "EventNames.h"#include "ExceptionCode.h"#include "Frame.h"#include "HTMLBRElement.h"#include "HTMLDocument.h"#include "HTMLElementFactory.h"#include "HTMLFormElement.h"#include "HTMLNames.h"#include "HTMLTokenizer.h" // parseHTMLDocumentFragment#include "RenderWordBreak.h"#include "Settings.h"#include "Text.h"#include "TextIterator.h"#include "XMLTokenizer.h"#include "markup.h"#include <wtf/StdLibExtras.h>namespace WebCore {using namespace HTMLNames;using std::min;using std::max;HTMLElement::HTMLElement(const QualifiedName& tagName, Document *doc) : StyledElement(tagName, doc){}HTMLElement::~HTMLElement(){}String HTMLElement::nodeName() const{ // FIXME: Would be nice to have an atomicstring lookup based off uppercase chars that does not have to copy // the string on a hit in the hash. if (document()->isHTMLDocument()) return tagQName().localName().string().upper(); return Element::nodeName();} HTMLTagStatus HTMLElement::endTagRequirement() const{ if (hasLocalName(wbrTag)) return TagStatusForbidden; if (hasLocalName(dtTag) || hasLocalName(ddTag)) return TagStatusOptional; // Same values as <span>. This way custom tag name elements will behave like inline spans. return TagStatusRequired;}int HTMLElement::tagPriority() const{ if (hasLocalName(wbrTag)) return 0; if (hasLocalName(addressTag) || hasLocalName(ddTag) || hasLocalName(dtTag) || hasLocalName(noscriptTag)) return 3; if (hasLocalName(centerTag) || hasLocalName(nobrTag)) return 5; if (hasLocalName(noembedTag) || hasLocalName(noframesTag)) return 10; // Same values as <span>. This way custom tag name elements will behave like inline spans. return 1;}bool HTMLElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const{ if (attrName == alignAttr || attrName == contenteditableAttr) { result = eUniversal; return false; } if (attrName == dirAttr) { result = hasLocalName(bdoTag) ? eBDO : eUniversal; return false; } return StyledElement::mapToEntry(attrName, result);} void HTMLElement::parseMappedAttribute(MappedAttribute *attr){ if (attr->name() == idAttr || attr->name() == classAttr || attr->name() == styleAttr) return StyledElement::parseMappedAttribute(attr); String indexstring; if (attr->name() == alignAttr) { if (equalIgnoringCase(attr->value(), "middle")) addCSSProperty(attr, CSSPropertyTextAlign, "center"); else addCSSProperty(attr, CSSPropertyTextAlign, attr->value()); } else if (attr->name() == contenteditableAttr) { setContentEditable(attr); } else if (attr->name() == tabindexAttr) { indexstring = getAttribute(tabindexAttr); if (indexstring.length()) { bool parsedOK; int tabindex = indexstring.toIntStrict(&parsedOK); if (parsedOK) // Clamp tabindex to the range of 'short' to match Firefox's behavior. setTabIndexExplicitly(max(static_cast<int>(std::numeric_limits<short>::min()), min(tabindex, static_cast<int>(std::numeric_limits<short>::max())))); } } else if (attr->name() == langAttr) { // FIXME: Implement } else if (attr->name() == dirAttr) { addCSSProperty(attr, CSSPropertyDirection, attr->value()); addCSSProperty(attr, CSSPropertyUnicodeBidi, hasLocalName(bdoTag) ? CSSValueBidiOverride : CSSValueEmbed); }// standard events else if (attr->name() == onclickAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().clickEvent, attr); } else if (attr->name() == oncontextmenuAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().contextmenuEvent, attr); } else if (attr->name() == ondblclickAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().dblclickEvent, attr); } else if (attr->name() == onmousedownAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().mousedownEvent, attr); } else if (attr->name() == onmousemoveAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().mousemoveEvent, attr); } else if (attr->name() == onmouseoutAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().mouseoutEvent, attr); } else if (attr->name() == onmouseoverAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().mouseoverEvent, attr); } else if (attr->name() == onmouseupAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().mouseupEvent, attr); } else if (attr->name() == onmousewheelAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().mousewheelEvent, attr); } else if (attr->name() == onfocusAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); } else if (attr->name() == onblurAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); } else if (attr->name() == onkeydownAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().keydownEvent, attr); } else if (attr->name() == onkeypressAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().keypressEvent, attr); } else if (attr->name() == onkeyupAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().keyupEvent, attr); } else if (attr->name() == onscrollAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().scrollEvent, attr); } else if (attr->name() == onbeforecutAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().beforecutEvent, attr); } else if (attr->name() == oncutAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().cutEvent, attr); } else if (attr->name() == onbeforecopyAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().beforecopyEvent, attr); } else if (attr->name() == oncopyAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().copyEvent, attr); } else if (attr->name() == onbeforepasteAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().beforepasteEvent, attr); } else if (attr->name() == onpasteAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().pasteEvent, attr); } else if (attr->name() == ondragenterAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().dragenterEvent, attr); } else if (attr->name() == ondragoverAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().dragoverEvent, attr); } else if (attr->name() == ondragleaveAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().dragleaveEvent, attr); } else if (attr->name() == ondropAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().dropEvent, attr); } else if (attr->name() == ondragstartAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().dragstartEvent, attr); } else if (attr->name() == ondragAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().dragEvent, attr); } else if (attr->name() == ondragendAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().dragendEvent, attr); } else if (attr->name() == onselectstartAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().selectstartEvent, attr); } else if (attr->name() == onsubmitAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().submitEvent, attr); } else if (attr->name() == onerrorAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().errorEvent, attr); } else if (attr->name() == onwebkitanimationstartAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().webkitAnimationStartEvent, attr); } else if (attr->name() == onwebkitanimationiterationAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().webkitAnimationIterationEvent, attr); } else if (attr->name() == onwebkitanimationendAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().webkitAnimationEndEvent, attr); } else if (attr->name() == onwebkittransitionendAttr) { setInlineEventListenerForTypeAndAttribute(eventNames().webkitTransitionEndEvent, attr); }}String HTMLElement::innerHTML() const{ return createMarkup(this, ChildrenOnly);}String HTMLElement::outerHTML() const{ return createMarkup(this);}PassRefPtr<DocumentFragment> HTMLElement::createContextualFragment(const String &html){ // the following is in accordance with the definition as used by IE if (endTagRequirement() == TagStatusForbidden) return 0; if (hasLocalName(colTag) || hasLocalName(colgroupTag) || hasLocalName(framesetTag) || hasLocalName(headTag) || hasLocalName(styleTag) || hasLocalName(titleTag)) return 0; RefPtr<DocumentFragment> fragment = new DocumentFragment(document()); if (document()->isHTMLDocument()) parseHTMLDocumentFragment(html, fragment.get()); else { if (!parseXMLDocumentFragment(html, fragment.get(), this)) // FIXME: We should propagate a syntax error exception out here. return 0; } // Exceptions are ignored because none ought to happen here. int ignoredExceptionCode; // we need to pop <html> and <body> elements and remove <head> to // accommodate folks passing complete HTML documents to make the // child of an element. RefPtr<Node> nextNode; for (RefPtr<Node> node = fragment->firstChild(); node; node = nextNode) { nextNode = node->nextSibling(); if (node->hasTagName(htmlTag) || node->hasTagName(bodyTag)) { Node *firstChild = node->firstChild(); if (firstChild) nextNode = firstChild; RefPtr<Node> nextChild; for (RefPtr<Node> child = firstChild; child; child = nextChild) { nextChild = child->nextSibling(); node->removeChild(child.get(), ignoredExceptionCode); ASSERT(!ignoredExceptionCode); fragment->insertBefore(child, node.get(), ignoredExceptionCode); ASSERT(!ignoredExceptionCode); } fragment->removeChild(node.get(), ignoredExceptionCode); ASSERT(!ignoredExceptionCode); } else if (node->hasTagName(headTag)) { fragment->removeChild(node.get(), ignoredExceptionCode); ASSERT(!ignoredExceptionCode); } } return fragment.release();}static inline bool hasOneChild(ContainerNode* node){ Node* firstChild = node->firstChild(); return firstChild && !firstChild->nextSibling();}static inline bool hasOneTextChild(ContainerNode* node){ return hasOneChild(node) && node->firstChild()->isTextNode();}static void replaceChildrenWithFragment(HTMLElement* element, PassRefPtr<DocumentFragment> fragment, ExceptionCode& ec){ if (!fragment->firstChild()) { element->removeChildren(); return; } if (hasOneTextChild(element) && hasOneTextChild(fragment.get())) { static_cast<Text*>(element->firstChild())->setData(static_cast<Text*>(fragment->firstChild())->string(), ec); return; } if (hasOneChild(element)) { element->replaceChild(fragment, element->firstChild(), ec); return; } element->removeChildren(); element->appendChild(fragment, ec);}static void replaceChildrenWithText(HTMLElement* element, const String& text, ExceptionCode& ec){ if (hasOneTextChild(element)) { static_cast<Text*>(element->firstChild())->setData(text, ec); return; } RefPtr<Text> textNode = new Text(element->document(), text); if (hasOneChild(element)) { element->replaceChild(textNode.release(), element->firstChild(), ec); return; } element->removeChildren(); element->appendChild(textNode.release(), ec);}void HTMLElement::setInnerHTML(const String& html, ExceptionCode& ec){ RefPtr<DocumentFragment> fragment = createContextualFragment(html); if (!fragment) { ec = NO_MODIFICATION_ALLOWED_ERR; return; } replaceChildrenWithFragment(this, fragment.release(), ec);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -