Dom4j detach node, Jython - xpath

I am using Dom4j to detach a node, like below:
<div name="divName">
Some Text Here
<span>Some Text Here</span>
</div>
I am selecting the div node by name and then using the detach method to remove it:
xpathValue = "//*[contains(#name, 'divName')]"
xpath = dom.createXPath(xpathValue)
if xpath != None:
nodes = xpath.selectNodes(dom)
if len(nodes) > 0:
for node in nodes:
node.detach()
This seems to remove the div fine, I noticed that it also removes elements and text within that div also. What I am looking to achive is removing the div without removing the elements and text inside the div, resulting in this:
Some Text Here
<span>Some Text Here</span>
Is it possible to achive this with dom4j? If not any suggestions on how to go about this?
Cheers
Eef
Update:
#alamar
I have achived what I wanted by taking your code and editing it a little and this is what I have come up with:
xpathValue = "//*[contains(#name, 'divName')]"
xpath = dom.createXPath(xpathValue)
if xpath != None:
nodes = xpath.selectNodes(dom)
if len(nodes) > 0:
for node in nodes:
parent = node.getParent()
nodeContents = node.content()
if len(nodeContents) > 0:
for subNode in nodeContents:
parent.add(subNode.clone().detach())
node.detach()
This seems to work, but adds the nodes to the end of the parent node in the below situation:
<div name="parent">
<div name="divName">
Some Text Here
<span>Some Text Here</span>
</div>
<div name="keep"></div>
</div>
The result is this:
<div name="parent">
<div name="keep"></div>
Some Text Here
<span>Some Text Here</span>
</div>
I am trying to figure out how to get the contents of the removed node to stay in its original position, before thed div named "keep", instead of being added after the div with the name "keep". I have tried a few thing but can not seem achive this, could anyone help?
Eef

If you want to keep the order of elements, you should really ask parent for its content().
In that content (which is a List backed by parent element) collection, you should find your div and replace it with that div's content().
I don't remember idiomatic way to do that in python, frankly.
probably
if xpath != None:
nodes = xpath.selectNodes(dom)
if len(nodes) > 0:
for node in nodes:
parent = node.getParent()
index = parent.indexOf(node)
siblings = parent.content()
nodeContents = node.content()
if len(nodeContents) > 0:
for subNode in nodeContents:
siblings.add(subNode.clone().detach(), index++)
node.detach()

Try:
if xpath != None:
nodes = xpath.selectNodes(dom)
if len(nodes) > 0:
for div in nodes:
parent = div.getParent()
div.detach()
for(child in node.content())
child.detach()
parent.add(child)
I believe it would do the trick.
I.e. after detaching every div, you should reattach every div's child into div's parent.

i had a similar problem and solved it with the following function (works fine for me)
What is it doing: it will simply remove that parent tag and includes every element and node inside the element to the parent at that position.
private void _replaceTagByContent(Element element) {
Element parent = element.getParent();
List elements = parent.elements();
int insertPosition = elements.indexOf(element);
// add them all to the parent again
for (int i = 0, size = elements.size(); i < size; i++) {
Node node = (Node) elements.get(i);
if (i == insertPosition) {
// if we are here, then this has to be an element, since
// wo do only replace elements ...
for (int j = element.nodeCount() - 1; j >= 0; j--) {
Node theNode = element.node(j);
theNode.detach();
elements.add(i, theNode);
}
// finally remove this node
elements.remove(node);
}
}
}
enjoy cnsntrk

Related

AMCharts - Dynamically add children to tree map

I am thoroughly enjoying AMChart's many features but I couldn't find any way to dynamically add some children to a treemap.
I am trying to load additional children on "hit" for each element
for (var i = 0; i < this.maxDepthLevel; i++) {
const series = this.chart.seriesTemplates.create(i);
series.columns.template.events.on("hit", async function(ev) {
const data = ev.target.dataItem.dataContext;
children = await api.getChildrenOf(data.id);
ev.target.dataItem.treeMapDataItem.children.values.push(...children);
});
}
^ this doesn't work and when doing this and then zooming out, I get
I even tried changing the underlying data and then calling
this.chart.invalidateRawData();
but to no avail.
Does anyone have any experience with adding such dynamic children to a tree map?
I cannot simply load everything upfront, there are far too many possible layers of depth unfortunately and the request will be too large!
Rather than directly pushing child items to children values you need to do it like this :
for(var index=0; index < children.length; index++){
var newChildDataItem = new am4charts.TreeMapDataItem();
newChildDataItem.value = children[index].value;
newChildDataItem.name = children[index].name;
newChildDataItem.color = ev.target.dataItem.dataContext.color;
ev.target.dataItem.dataContext.children.insert(newChildDataItem);
}

Iterate over child nodes on a Telerik MVC TreeView

I have a Telerik MVC Treeview that i am trying to get the child nodes for using JQuery. I'm using the "hasChildren" property to tell me if the node has any children and that's working fine. But I can't seem to figure out the node property that will let me iterate over the child nodes. "nodes[i].children.view()" gives me an empty array but it should be an array of the child nodes according to this Kendo doc.
var productTreeView = $("#treeviewProducts").data("kendoTreeView");
var nodes = productTreeView.dataSource.view();
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].hasChildren) {
var childrenNodes = nodes[i].children.view();
for (var x = 0; x < childrenNodes.length; x++) {
...
}
}
}
UPDATE: The code above works fine if the node with children is expanded but does not work when the node with children is collapsed because LazyLoading for child nodes was enabled (thanks DontVoteMeDown). Either turn that off or expand all nodes before running the code (productTreeView.expand(".k-item");).

Add a class to the 'Nearest' TD from my cursor in a plugin

I'm trying to create a plugin to add some preset style to a table cell.
Step-by-step:
User click in a cell.
User click on my plugin button in the toolbar
Select a style
A class attribute is add to the closest TD
I'm having a hard time with the 4th point. How can I know where my cursor is in the source? How can I select the closest TD? The cursor must be between a <td> </td>. If there is no TD around nothing happen.
The cursor can be between any <Tag> as long as they are in a <td>.
// nearest element that surrounds your cursor
var el = editor.getSelection().getStartElement();
while (el) {
// if element is <td>, set class attribute and break loop
if (el.getName() == 'td') {
el.setAttribute('class', 'myClass');
break;
}
// otherwise, continue with parent element
// until you find <td> or there are no more elements
el = el.getParent();
}

document.querySelectorAll("span + a") didn't work?

I have a HTML like this.
<span class="vm-video-side-notification-text-item">
Includes copyrighted content
</span>
I use
var x = document.querySelectorAll("span + a");
alert(x.length);
the alert is "0"... I don't know why.
I see the w3school says
element+element
div + p
Selects all <p> elements that are placed immediately after <div> elements
so I try span + a. Can anyone correct my mistake?
You're conflating elements with tags.
While the start tag of the a is directly after the start tag of the span indeed, the a element is inside the span element.
So, in order for your example to work, you can either
change the query selector to "span > a" for "any a directly inside a span"
var x = document.querySelectorAll("span > a");
alert(x.length);
or change the html to have the a element after the span element
<span class="vm-video-side-notification-text-item">
</span>
Includes copyrighted content
(... but not both!)

Get current style information in CKEditor

How can I get information about the states of styles present on the toolbar, at the current cursor position.
The documentation is completely silent on this issue. As far as I can tell from digging into the source code, CKEditor doesn't keep an internal log of what the styles are at the current position. It simply recalculates them on an as-needed basis, namely whenever it needs to add new styles to a selection.
Please keep in mind that CKEditor is actually building and modifying an entire DOM tree, and so the styles it applies cascade down the nodes. It appears that the only way you can pull the style information is to traverse up the DOM tree from your current cursor position, recording the style information from each ancestor until you reach the body node of the editor.
The following code should get you started traversing up the ancestor nodes:
//Or however you get your current editor
var editor = CKEDITOR.currentInstance;
//This will pull the minimum ancestor that encompasses the entire selection,
//so if you just want to use the cursor it will give you the direct parent
//node that the cursor is inside
var node = editor.getSelection().getCommonAncestor();
//This is all the ancestors, up to the document root
var ancestors = node.getParents();
//This is the editors body node; you don't want to go past this
var editor_body = editor.getBody();
var body_ancestors = editor_body.getParents();
//The ancestors list descends from the root node, whereas we want
//to ascend towards the root
for (var i = ancestors.length - 1; i >= 0; i--;) {
//Pull the node
var a = ancestors[i];
//You've hit the body node, break out of the loop
if (a.getText() == editor_body.getText()) break;
//This is a node between the cursor's node and the editor body,
//pull your styling information from the node here
}
Thanks to the customizability of CKEditors style interface, there isn't a single set of styles that can be checked for, nor do they follow the same form (for instance, some will be CSS styles, while others will be span elements with a particular class).
My suggestion is to check for just those styles which you actually care about, and ignore the rest. It'll make the code much simpler.
Here is another way (based on a few attached links).
You can get the current element position by editor.getSelection().getStartElement() - (editor is CKEDITOR.instances.%the editor instance%.
Now, you can then wrap the actual element for jquery (or use the jquery adapter..):
$(editor.getSelection().getStartElement().$)
This will give you an access to use the following plugin which resolves all the styles of a given element (both inline and inherited):
/*
* getStyleObject Plugin for jQuery JavaScript Library
* From: http://upshots.org/?p=112
*
* Copyright: Unknown, see source link
* Plugin version by Dakota Schneider (http://hackthetruth.org)
*/
(function($){
$.fn.getStyleObject = function(){
var dom = this.get(0);
var style;
var returns = {};
if(window.getComputedStyle){
var camelize = function(a,b){
return b.toUpperCase();
}
style = window.getComputedStyle(dom, null);
for(var i=0;i<style.length;i++){
var prop = style[i];
var camel = prop.replace(/\-([a-z])/g, camelize);
var val = style.getPropertyValue(prop);
returns[camel] = val;
}
return returns;
}
if(dom.currentStyle){
style = dom.currentStyle;
for(var prop in style){
returns[prop] = style[prop];
}
return returns;
}
return this.css();
}
})(jQuery);
(Taken from: jQuery CSS plugin that returns computed style of element to pseudo clone that element?)
All that is left to do is:
$(editor.getSelection().getStartElement().$).getStyleObject()
Now you can check for any style asigned to the element.
Another small tip will be - what are the styles for the current cursor position, every time the position or styles are changed:
In which case you can use attachStyleStateChange callback (which is pretty atrophied by itself since is can only return boolean indication for weather or not a certain style is applied to current position).
The good thing about it is - callback is being recieved when ever the style state is changed - that is - whenever the cursor position is moved to a position with different style attributes - Any different attribute and not just the attribute the listener was ment to verify (Taken from the API http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.editor.html#attachStyleStateChange)
Combining everything together to figure out what is the current applied styles on the current cursor position Every time something is changed:
editor.on('instanceReady', function () {
//editor.setReadOnly(true);
var styleBold = new CKEDITOR.style(CKEDITOR.config.coreStyles_bold);
editor.attachStyleStateChange(styleBold, function (state) {
var currentCursorStyles = $(editor.getSelection().getStartElement().$).getStyleObject();
// For instance, the font-family is:
var fontFamily = currentCursorStyles.fontFamily;
});
});

Resources