@Test public void clone_Deep() { // Arrange AnchorElement child = Document.get().createAnchorElement(); child.setInnerText("child inner text"); child.getStyle().setBackgroundColor("black"); n.appendChild(child); // Act DivElement newNode = n.cloneNode(true).cast(); // Assert assertEquals(Node.ELEMENT_NODE, newNode.getNodeType()); DivElement source = n.cast(); assertEquals(source.getInnerText(), newNode.getInnerText()); assertEquals(source.getInnerHTML(), newNode.getInnerHTML()); assertEquals(source.toString(), newNode.toString()); assertNull(newNode.getParentNode()); assertEquals(n.getChildNodes().getLength(), newNode.getChildNodes().getLength()); assertEquals(Node.ELEMENT_NODE, newNode.getChildNodes().getItem(0).getNodeType()); AnchorElement childElement = newNode.getChildNodes().getItem(0).cast(); assertEquals("child inner text", childElement.getInnerText()); Style newStyle = childElement.getStyle(); assertTrue(newStyle != child.getStyle()); assertEquals("black", newStyle.getBackgroundColor()); }
private Element getLastChildElement(Element parent) { Node lastTab = parent.getLastChild(); while (lastTab.getNodeType() != Node.ELEMENT_NODE) { lastTab = lastTab.getPreviousSibling(); } return Element.as(lastTab); }
/** * Inserts a paragraph before or after the table containing the selection. * * <p>We decided to use Control/Meta+UpArrow for inserting a paragraph before a table and * Control/Meta+DownArrow for inserting a paragraph after a table. Here's the rationale: * * <ul> * <li>We can't reliably detect if the user can place the caret before of after a table. Our * playground is the DOM tree which we fully control but in the end the browser decides how * to render each node. The table can have previous siblings or previous nodes in the DOM * tree but they may not be rendered at all (as it happens with HTML garbage like empty * elements) or not rendered before/after the table (as it happens with absolute positioned * elements). So we have to insert the paragraph each time. * <li>We can't use the same key to insert a paragraph before and after the table because we can * have a table with just one empty cell. So we can't rely on the Enter key. * <li>We can't use just the navigation keys because they would insert a paragraph before/after * the table even when the user can navigate outside of the table. * </ul> * * We can replace the Ctrl with Alt. The idea is to use the Up/Down arrow keys with a modifier. * They will work form any table cell. * * @param event the native event that was fired * @param before {@code true} to insert a paragraph before the table, {@code false} to insert a * paragraph after the table */ protected void navigateOutsideTableCell(Event event, boolean before) { // Navigate only if the Control or Meta modifiers are pressed along with the Up/Down arrow keys. if (event.getAltKey() || event.getShiftKey() || !(event.getCtrlKey() ^ event.getMetaKey())) { return; } Selection selection = getTextArea().getDocument().getSelection(); if (selection.getRangeCount() == 0) { return; } else { selection.collapseToStart(); } Range range = selection.getRangeAt(0); Node ancestor = domUtils.getFirstAncestor(range.getStartContainer(), "table"); if (ancestor == null) { return; } event.xPreventDefault(); Document document = getTextArea().getDocument(); Node paragraph = document.createPElement(); paragraph.appendChild(document.createTextNode("")); if (before) { ancestor.getParentNode().insertBefore(paragraph, ancestor); } else { domUtils.insertAfter(paragraph, ancestor); } range.selectNodeContents(paragraph.getFirstChild()); selection.removeAllRanges(); selection.addRange(range); }
/** * Overwrites the default rich text area behavior when the Tab key is being pressed. * * @param event the native event that was fired */ protected void onTab(Event event) { Selection selection = getTextArea().getDocument().getSelection(); if (selection.getRangeCount() == 0) { return; } // Prevent the default browser behavior. event.xPreventDefault(); // See in which context the tab key has been pressed. Range range = selection.getRangeAt(0); List<String> specialTags = Arrays.asList(new String[] {LI, TD, TH}); Node ancestor = range.getStartContainer(); int index = specialTags.indexOf(ancestor.getNodeName().toLowerCase()); while (ancestor != null && index < 0) { ancestor = ancestor.getParentNode(); if (ancestor != null) { index = specialTags.indexOf(ancestor.getNodeName().toLowerCase()); } } // Handle the tab key depending on the context. switch (index) { case 0: onTabInListItem(event, ancestor); break; case 1: case 2: onTabInTableCell(event, (TableCellElement) ancestor); break; default: onTabDefault(event); break; } }
/** * Tab key has been pressed inside a table cell. * * @param event the native event that was fired * @param cell The table cell in which the tab key has been pressed. */ protected void onTabInTableCell(Event event, TableCellElement cell) { Node nextCell = event.getShiftKey() ? cell.getPreviousCell() : cell.getNextCell(); if (nextCell == null) { if (event.getShiftKey()) { return; } else { getTextArea().getCommandManager().execute(new Command("insertrowafter")); nextCell = cell.getNextCell(); } } Selection selection = getTextArea().getDocument().getSelection(); Range range = selection.getRangeAt(0); // Place the caret at the beginning of the next cell. Node leaf = domUtils.getFirstLeaf(nextCell); if (leaf == nextCell || leaf.getNodeType() == Node.TEXT_NODE) { range.setStart(leaf, 0); } else { range.setStartBefore(leaf); } range.collapse(true); selection.removeAllRanges(); selection.addRange(range); }
/** * @param parent the parent node * @param child the child node * @return the position of the child node within the array of children or -1 if there is no parent * child relationship */ public static int indexOf(Node parent, Node child) { for (int i = 0; i < parent.getChildCount(); i++) { if (child.equals(parent.getChild(i))) { return i; } } return -1; }
@PatchMethod static Element getFirstChild(Element elem) { Node firstChild = elem.getFirstChildElement(); if (firstChild != null) { return firstChild.cast(); } else { return null; } }
private void getEmptyPseudo(JsNodeArray previousMatch, JsNodeArray matchingElms) { Node previous; for (int q = 0, qlen = previousMatch.size(); q < qlen; q++) { previous = previousMatch.getNode(q); if (!previous.hasChildNodes()) { matchingElms.addNode(previous); } } }
@Test public void is() { // Arrange NodeList<OptionElement> list = JavaScriptObjects.newNodeList(); // Act & Assert assertFalse("null is not a DOM node", Node.is(null)); assertFalse("NodeList is not a DOM node", Node.is(list)); assertTrue("AnchorElement is a DOM node", Node.is(Document.get().createAnchorElement())); }
/** * @param root the root node * @param node the node to start from * @return a list of nodes starting with the parent closest to the root and ending with the given * node */ private List<Node> getParents(Element root, Node node) { ArrayList<Node> result = new ArrayList<Node>(); while ((node != null) && !node.equals(root)) { result.add(node); node = node.getParentNode(); } Collections.reverse(result); return result; }
private static void getSiblingNodes( JsNodeArray matchingElms, JsObjectArray<String> nextTag, JsRegexp nextRegExp, Node prevRef) { while (JsUtils.truth(prevRef = SelectorEngine.getNextSibling(prevRef)) && prevRef.getNodeType() != Node.ELEMENT_NODE) {} if (JsUtils.truth(prevRef)) { if (!JsUtils.truth(nextTag) || nextRegExp.test(prevRef.getNodeName())) { matchingElms.addNode(prevRef); } } }
private static void getDescendantNodes( JsNodeArray matchingElms, String nextTagStr, Node prevRef) { NodeList<Element> children = getElementsByTagName(nextTagStr, prevRef); for (int k = 0, klen = children.getLength(); k < klen; k++) { Node child = children.getItem(k); if (child.getParentNode() == prevRef) { matchingElms.addNode(child); } } }
public void setTag(String category) { assert category != null; assert rootElement.getChild(1) != null; Node node = rootElement.getChild(1); node.removeAllChildren(); Node text = JSFunctions.createTextNode(category); node.insertFirst(text); assert rootElement.getChild(1) != null; assert rootElement.getChild(1).getChild(0) != null; }
@Test public void isOrHasChild_hasChild() { // Arrange Element a = Document.get().createAnchorElement(); Element div = Document.get().createDivElement(); div.appendChild(a); n.appendChild(div); // Act & Assert assertTrue(n.isOrHasChild(a)); }
/** {@inheritDoc} */ @Override public void assertHealthy(ContentElement paragraph) { ContentView renderedContent = paragraph.getRenderedContentView(); if (renderedContent.getFirstChild(paragraph) != null) { Node child = paragraph.getImplNodelet().getFirstChild(); while (child != null) { assert !isSpacer(child) : "Non-empty paragraph should not have spacer"; child = child.getNextSibling(); } } super.assertHealthy(paragraph); }
@Test public void getParentNode() { // Pre-Assert assertNull(n.getParentNode()); // Arrange BaseElement be = Document.get().createBaseElement(); n.appendChild(be); // Act & assert assertEquals(n, be.getParentNode()); }
@Test public void hasChildNodes() { // Pre-Assert assertFalse("New element should not have child nodes", n.hasChildNodes()); // Arrange BaseElement be = Document.get().createBaseElement(); n.appendChild(be); // Act & Assert assertTrue("Element should have a child node", n.hasChildNodes()); }
@Test public void nodeValue_Element() { // Arrange Node doucmentNode = Document.get().getDocumentElement(); // Pre-Assert assertNull(doucmentNode.getNodeValue()); // Act doucmentNode.setNodeValue("node"); // Assert assertNull(doucmentNode.getNodeValue()); }
/** Improves splitter visibility. */ private void tuneSplitter() { NodeList<Node> nodes = splitLayoutPanel.getElement().getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.getItem(i); if (node.hasChildNodes()) { com.google.gwt.dom.client.Element el = node.getFirstChild().cast(); if ("gwt-SplitLayoutPanel-HDragger".equals(el.getClassName())) { tuneSplitter(el); return; } } } }
@Test public void getPreviousSibling() { // Pre-Assert assertNull(n.getPreviousSibling()); // Arrange ButtonElement be0 = Document.get().createPushButtonElement(); ButtonElement be1 = Document.get().createPushButtonElement(); n.appendChild(be0); n.appendChild(be1); // Act & Assert assertEquals(be0, be1.getPreviousSibling()); }
private void commitPosition(int pos) { lastElementX_ = pos; // check to see if we're overlapping with another tab for (int i = 0; i < dragTabsHost_.getChildCount(); i++) { // skip non-element DOM nodes Node node = dragTabsHost_.getChild(i); if (node.getNodeType() != Node.ELEMENT_NODE) { continue; } // skip the current candidate (no point in testing it for swap) if (i == candidatePos_) { continue; } // skip the element we're dragging and elements that are not tabs Element ele = (Element) node; if (ele == dragElement_ || ele.getClassName().indexOf("gwt-TabLayoutPanelTab") < 0) { continue; } int left = DomUtils.leftRelativeTo(dragTabsHost_, ele); int right = left + ele.getClientWidth(); int minOverlap = Math.min(initDragWidth_ / 2, ele.getClientWidth() / 2); // a little complicated: compute the number of overlapping pixels // with this element; if the overlap is more than half of our width // (or the width of the candidate), it's swapping time if (Math.min(lastElementX_ + initDragWidth_, right) - Math.max(lastElementX_, left) >= minOverlap) { dragTabsHost_.removeChild(dragPlaceholder_); if (candidatePos_ > i) { dragTabsHost_.insertBefore(dragPlaceholder_, ele); } else { dragTabsHost_.insertAfter(dragPlaceholder_, ele); } candidatePos_ = i; // account for the extra element when moving to the right of the // original location if (dragElement_ != null && startPos_ != null) { destPos_ = startPos_ <= candidatePos_ ? candidatePos_ - 1 : candidatePos_; } else { destPos_ = candidatePos_; } } } }
@PatchMethod static void setNodeValue(Node node, String nodeValue) { switch (node.getNodeType()) { case Node.DOCUMENT_NODE: // nothing to do break; case Node.ELEMENT_NODE: // nothing to do break; case Node.TEXT_NODE: Text text = node.cast(); text.setData(nodeValue); break; } }
@PatchMethod static String getNodeValue(Node node) { switch (node.getNodeType()) { case Node.DOCUMENT_NODE: return null; case Node.ELEMENT_NODE: return null; case Node.TEXT_NODE: Text text = node.cast(); return text.getData(); default: throw new GwtTestDomException( "Invalid Node type (not a Document / Element / Text : " + node.getNodeType()); } }
@Test public void removeChild() { // Arrange BaseElement c0 = Document.get().createBaseElement(); ButtonElement c1 = Document.get().createPushButtonElement(); n.appendChild(c0); n.appendChild(c1); // Act n.removeChild(c1); // Assert assertEquals(1, n.getChildNodes().getLength()); assertEquals(c0, n.getChildNodes().getItem(0)); }
@PatchMethod static Node getNextSibling(Node node) { Node parent = node.getParentNode(); if (parent == null) return null; List<Node> list = getChildNodeList(parent); for (int i = 0; i < list.size(); i++) { Node current = list.get(i); if (current.equals(node) && i < list.size() - 1) { return list.get(i + 1); } } return null; }
@Test public void isOrHasChild_notChild() { // Arrange Element a = Document.get().createAnchorElement(); // Act & Assert assertFalse(n.isOrHasChild(a)); }
/** * Specific function which does not inspect deep. * * @param tag * @return */ private static NodeList<Element> getElementByTagName(TableElement e, String tagName) { NodeList<Node> childs = e.getChildNodes(); List<Element> list = new ArrayList<Element>(); for (int i = 0; i < childs.getLength(); i++) { Node n = childs.getItem(i); if (Element.is(n)) { Element childElement = n.cast(); if (tagName.equalsIgnoreCase(childElement.getTagName())) { list.add(childElement); } } } return JavaScriptObjects.newNodeList(list); }
/** * @param container A block level element containing the start of the given range. * @param range A DOM range. * @return true if the start of the given range is at the beginning of its block level container. */ protected boolean isAtStart(Node container, Range range) { if (!container.hasChildNodes()) { return true; } if (range.getStartOffset() > 0) { return false; } return domUtils.getFirstLeaf(container) == domUtils.getFirstLeaf(range.getStartContainer()); }
private static void setupChildNodes(Node newNode, Node oldNode, boolean deep) { List<Node> childs = getChildNodeList(oldNode); if (deep) { // copy all child nodes for (Node child : childs) { appendChild(newNode, cloneNode(child, true)); } } else { // only copy the TextNode if exists for (Node child : childs) { if (Node.TEXT_NODE == child.getNodeType()) { appendChild(newNode, Document.get().createTextNode(child.getNodeValue())); break; } } } }
@PatchMethod static String getNodeName(Node node) { switch (node.getNodeType()) { case Node.DOCUMENT_NODE: return "#document"; case Node.ELEMENT_NODE: Element e = node.cast(); return e.getTagName(); case Node.TEXT_NODE: return "#text"; case com.google.gwt.xml.client.Node.ATTRIBUTE_NODE: return JavaScriptObjects.getString(node, JsoProperties.XML_ATTR_NAME); default: throw new GwtTestDomException( "Invalid Node type (not a Document / Element / Text / Attribute) : " + node.getNodeType()); } }