libxml2: xpath relative to sub node - xpath

Given the xml file
<a>
<b>
<d>v</d>
</b>
<c>
<d>v</d>
</c>
</a>
And the xpath "//d/text()"
I want to apply the xpath only to c and not to the whole document.
This has to work with libxml2 2.7.6
Doing this does not work;
xmlNodePtr node = <node pointer to c>
xmlXPathContextPtr xpathCtx = xmlXPathNewContext( node->doc );
xpathCtx->node = node;
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression ( "//d/text()", xpathCtx);
Returned xpathObj contains refences to both /a/b/d and /a/c/d. Only /a/c/d was expected.

Use the path .//d or .//d/text() if you want to find descendants relative to another node. A path starting with //d searches all d descendant elements of the root node (also called document node).

Solved with:
xmlNodePtr node = <node pointer to c>
xmlXPathContextPtr xpathCtx = xmlXPathNewContext( node->doc );
//Update the document to set node as root
xmlNodePtr myParent = node->parent;
xmlNodePtr originalRootElement = xmlDocGetRootElement( node->doc );
xmlDocSetRootElement( node->doc, node );
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression ( "//d/text()", xpathCtx);
//xpathObj contains only /a/c/d, as expected
//restore the xml document
xmlDocSetRootElement( originalRootElement->doc, originalRootElement );
xmlAddChild( myParent, node );
Tested with valdrind.
The above example gives just the idea. In the following the complete implementation (thanks to Julo for his comment):
//Update Doc to support xpath on logical root node and restore the document structure at scope exit
class XmlDoc_UpdateDocAndRestoreAtScopeExit {
public:
XmlDoc_UpdateDocAndRestoreAtScopeExit( _xmlDoc* doc, _xmlNode* logicalRootNode) :
_doc ( doc ),
_logicalRootNode ( logicalRootNode ),
_originalRootElement( 0 ),
_refParent ( 0 ),
_refPrevSibling ( 0 ),
_refNextSibling ( 0 ),
_toRestore(false)
{
_originalRootElement = xmlDocGetRootElement( doc );
_refParent = _logicalRootNode->parent;
_refPrevSibling = _logicalRootNode->prev;
_refNextSibling = _logicalRootNode->next;
if ( _logicalRootNode != _originalRootElement ) {
xmlDocSetRootElement( _doc, _logicalRootNode );
_toRestore = true;
}
}
~XmlDoc_UpdateDocAndRestoreAtScopeExit() {
if ( _toRestore ) {
//Restore the root node
xmlDocSetRootElement( _doc, _originalRootElement );
//Restore the node at its original place
if ( 0 != _refPrevSibling ) {
xmlAddNextSibling( _refPrevSibling, _logicalRootNode );
} else if ( 0 != _refNextSibling ) {
xmlAddPrevSibling( _refNextSibling, _logicalRootNode );
} else {
xmlAddChild( _refParent, _logicalRootNode );
}
}
}
private:
XmlDoc_UpdateDocAndRestoreAtScopeExit() ; // not implemented
XmlDoc_UpdateDocAndRestoreAtScopeExit(const XmlDoc_UpdateDocAndRestoreAtScopeExit &) ; // not implemented
XmlDoc_UpdateDocAndRestoreAtScopeExit & operator= (const XmlDoc_UpdateDocAndRestoreAtScopeExit &) ; // not implemented
private:
_xmlDoc* _doc;
_xmlNode* _logicalRootNode;
_xmlNode* _originalRootElement;
_xmlNode* _refParent;
_xmlNode* _refPrevSibling;
_xmlNode* _refNextSibling;
bool _toRestore;
};
//Somewhere in the code...
xmlNodePtr node = <node pointer to c>
xmlXPathContextPtr xpathCtx = xmlXPathNewContext( node->doc );
//Here set the _rootNodePtr as the root of the document to use xpath on your "logical" root
//At scope exit the document's structure will be restored.
XmlDoc_UpdateDocAndRestoreAtScopeExit xmlDoc_UpdateDocAndRestoreAtScopeExit( node->doc, node );
xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression ( "//d/text()", xpathCtx);
//xpathObj contains only /a/c/d, as expected

Related

How to change color of each controlP5 dropdown list entry individually?

Using the following MWE:
import controlP5.*;
import java.util.*;
ControlP5 cp5;
void setup() {
size(400, 400);
cp5 = new ControlP5(this);
List l = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
/* add a ScrollableList, by default it behaves like a DropdownList */
cp5.addScrollableList("dropdown")
.setPosition(100, 100)
.setSize(200, 100)
.setBarHeight(20)
.setItemHeight(20)
.addItems(l)
// .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
;
}
void draw() {
background(240);
}
How can I change the font color of each list entry separately? I assume I'll have to use a for loop of some kind like the following
for (int i =0; i < myarray.length; i++){
dropdown.setColorActive(elementDetermine(myarray[i]));
}
Where elementDetermine() takes an integer and returns a color. Unfortunately, when I run this loop in either the setup or the draw function, the dropdown list doesn't change without error message.
Unfortunately there's no easy readily available method to change the font color of each list entry separately.
As you can see in the documentation the available methods access the main caption which applies to all items.
In fact, the same Label component is re-used accross all list items and simply re-rendered once per item (changing current text/colours) as you can see in the source code
If you really really need to change the font color you can, but that will be quite a few OOP hoops to jump through (since there is no array of Label instances per item):
you'd need to make a custom ControllerView< ScrollableList > to override it's display() method
for the custom display() to work the same as the original ScrollableList you need to pretty much replicate the super class
the ScrollableList super class has a bunch of private properties that can easily be accessed from the ScrollableListView class since it's part of ScrollableList, however in our case all those private / protected properties that need to be accessed in display() need to be accessible. To do this a ScrollableList subclass is implemenented (PopUpScrollableList) which mainly replicates it's superclass behaviours wherever those private/protected properties are used in display() and also makes them available.
Finally the custom scrollable list can have a color[] which can store the custom colours so they can be accessed and rendered in the overriden display() method:
import controlP5.*;
// used by the custom scrollable list view
import static controlP5.ControlP5.b;
import java.util.*;
ControlP5 cp5;
void setup() {
size(400, 400);
cp5 = new ControlP5(this);
List l = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");
/* add a custom ScrollableList, by default it behaves like a DropdownList */
PopUpScrollableList dropdown = addPopUpScrollableList("dropdown");
dropdown.setPosition(100, 100)
.setSize(200, 100)
.setBarHeight(20)
.setItemHeight(20)
.addItems(l)
// .setType(ScrollableList.LIST) // currently supported DROPDOWN and LIST
;
// a list of (random) colourr: a colour per item
color[] textColors = new color[l.size()];
for(int i = 0 ; i < textColors.length; i++){
textColors[i] = color(255, random(255), random(255), random(255));
}
// set custom text colours: this is a bit hacky: normally you'd check if items.size() matches textColors.length, etc.
dropdown.textColors = textColors;
// set a custom view for the list
dropdown.setView(makeCustomScrollListView());
}
void draw() {
background(240);
}
// simply adds our custom scrollable list
PopUpScrollableList addPopUpScrollableList( final String theName ) {
PopUpScrollableList myController = new PopUpScrollableList(cp5, theName);
return myController;
}
ControllerView< ScrollableList > makeCustomScrollListView(){
// make an custom scrollable list view on the fly and access the fileds it needs
return new ControllerView< ScrollableList >() {
// tweaked version of https://github.com/sojamo/controlp5/blob/1f7cb649865eb8657495b5cfeddd0dbe85d70cac/src/controlP5/ScrollableList.java#L391
public void display( PGraphics g , ScrollableList c ) {
// setHeight( -200 ); /* UP */
PopUpScrollableList d = (PopUpScrollableList)c;
g.noStroke( );
if ( c.isBarVisible( ) ) {
boolean b = d.itemHover() == -1 && d.isInside() && !d.isDragged();
g.fill( b ? c.getColor( ).getForeground( ) : c.getColor( ).getBackground( ) );
g.rect( 0 , 0 , c.getWidth( ) , c.getBarHeight() );
g.pushMatrix( );
g.translate( c.getWidth( ) - 8 , c.getBarHeight() / 2 - 2 );
g.fill( c.getColor( ).getCaptionLabel( ) );
if ( c.isOpen( ) ) {
g.triangle( -3 , 0 , 3 , 0 , 0 , 3 );
} else {
g.triangle( -3 , 3 , 3 , 3 , 0 , 0 );
}
g.popMatrix( );
c.getCaptionLabel( ).draw( g , 4 , c.getBarHeight() / 2 );
}
if ( c.isOpen( ) ) {
int bar = ( c.isBarVisible( ) ? c.getBarHeight() : 0 );
int h = ( ( d.updateHeight( ) ) );
g.pushMatrix( );
// g.translate( 0 , - ( h + bar +
// c.itemSpacing ) ); /* UP */
g.fill( c.getBackgroundColor( ) );
g.rect( 0 , bar , c.getWidth( ) , h );
g.pushMatrix( );
g.translate( 0 , ( bar == 0 ? 0 : ( c.getBarHeight() + d.itemSpacing() ) ) );
/* draw visible items */
c.updateItemIndexOffset( );
int m0 = d.itemIndexOffset;
List items = c.getItems();
int m1 = items.size( ) > d.itemRange() ? ( d.itemIndexOffset + d.itemRange() ) : items.size( );
for ( int i = m0 ; i < m1 ; i++ ) {
Map< String , Object > item = (Map< String , Object >) items.get( i );
CColor itemColor = ( CColor ) item.get( "color" );
g.fill( ( b( item.get( "state" ) ) ) ? itemColor.getActive( ) : ( i == d.itemHover() ) ? ( c.isMousePressed() ? itemColor.getActive( ) : itemColor.getForeground( ) ) : itemColor.getBackground( ) );
float boxY = d.itemHeight() - 1;
g.rect( 0 , 0 , c.getWidth( ) , boxY );
Label label = c.getValueLabel( );
// finally set custom text colour
if(d.textColors != null){
label.setColor(d.textColors[i]);
}
label.set( item.get( "text" ).toString( ) ).draw( g , 4 , d.itemHeight() / 2 );
g.translate( 0 , d.itemHeight() );
}
g.popMatrix( );
if ( c.isInside() ) {
int m = items.size( ) - d.itemRange();
if ( m > 0 ) {
g.fill( c.getColor( ).getCaptionLabel( ) );
g.pushMatrix( );
int s = 4; /* spacing */
int s2 = s / 2;
g.translate( c.getWidth( ) - s , c.getBarHeight() );
int len = ( int ) PApplet.map( ( float ) Math.log( m * 10 ) , 0 , 10 , h , 0 );
int pos = ( int ) ( PApplet.map( d.itemIndexOffset , 0 , m , s2 , h - len - s2 ) );
g.rect( 0 , pos , s2 , len );
g.popMatrix( );
}
}
g.popMatrix( );
}
}
};
}
// a custom ScrollableList subclass: mainly it needs to expose properties the custom view (via setView()) can't access in display()
class PopUpScrollableList extends ScrollableList{
private int itemIndexOffset = 0;
private int _myType = DROPDOWN;
protected boolean isOpen = true;
public color[] textColors;
PopUpScrollableList(ControlP5 cp5, String name){
super(cp5, name);
println("custom PopUpScrollableList named " + name + " constructed");
}
public boolean isOpen( ) {
return isOpen;
}
public ScrollableList open( ) {
return setOpen( true );
}
public ScrollableList close( ) {
return setOpen( false );
}
public ScrollableList setOpen( boolean b ) {
isOpen = b;
return this;
}
public int itemHover(){
return itemHover;
}
public int itemSpacing(){
return 1;
}
public int itemRange(){
return itemRange;
}
public int itemHeight(){
return itemHeight;
}
public boolean isInside(){
return isInside;
}
public boolean isDragged(){
return isDragged;
}
public int barHeight(){
return barHeight;
}
protected int updateHeight( ) {
itemRange = ( PApplet.abs( getHeight( ) ) - ( isBarVisible( ) ? barHeight : 0 ) ) / itemHeight;
return itemHeight * ( items.size( ) < itemRange ? items.size( ) : itemRange );
}
public List< Map< String , Object > > items(){
return items;
}
#Override protected void onRelease( ) {
if ( !isDragged ) {
if ( getPointer( ).y( ) >= 0 && getPointer( ).y( ) <= barHeight ) {
setOpen( !isOpen( ) );
} else if ( isOpen ) {
double n = Math.floor( ( getPointer( ).y( ) - barHeight ) / itemHeight );
// n += itemRange; /* UP */
int index = ( int ) n + itemIndexOffset;
updateIndex( index );
}
}
}
private void updateIndex( int theIndex ) {
if ( theIndex >= items.size( ) ) {
return;
}
Map m = items.get( theIndex );
switch ( _myType ) {
case ( LIST ):
super.setValue( theIndex );
for ( Object o : items ) {
( ( Map ) o ).put( "state" , false );
}
m.put( "state" , !ControlP5.b( m.get( "state" ) ) );
break;
case ( DROPDOWN ):
super.setValue( theIndex );
setOpen( false );
getCaptionLabel( ).setText( ( m.get( "text" ).toString( ) ) );
break;
case ( CHECKBOX ):
m.put( "state" , !ControlP5.b( m.get( "state" ) ) );
break;
}
}
public ScrollableList setValue( float theValue ) {
updateIndex( ( int ) ( theValue ) );
return this;
}
#Override protected void onDrag( ) {
scroll( getPointer( ).dy( ) );
}
#Override protected void onScroll( int theValue ) {
scroll( theValue );
}
private void scroll( int theValue ) {
if ( isOpen() ) {
itemIndexOffset += theValue;
itemIndexOffset = ( int ) ( Math.floor( Math.max( 0 , Math.min( itemIndexOffset , items.size( ) - itemRange ) ) ) );
itemHover = -2;
}
}
#Override protected void onLeave( ) {
itemHover = -1;
}
#Override protected void onEnter( ) {
updateHover( );
}
#Override protected void onMove( ) {
updateHover( );
}
#Override protected void onEndDrag( ) {
updateHover( );
}
private void updateHover( ) {
if ( getPointer( ).y( ) > barHeight ) {
double n = Math.floor( ( getPointer( ).y( ) - barHeight ) / itemHeight );
itemHover = ( int ) ( itemIndexOffset + n );
} else {
itemHover = -1;
}
}
public void updateItemIndexOffset( ) {
int m1 = items.size( ) > itemRange ? ( itemIndexOffset + itemRange ) : items.size( );
int n = ( m1 - items.size( ) );
if ( n >= 0 ) {
itemIndexOffset -= n;
}
}
}

Cloning a THREE.Group hierarchy

I have a hierarchy of groups, A -> B -> C. I wish to create a clone of this hierarchy, A2 -> B2 -> C2.
But Object3D.clone() removes the parent reference of the group.
Other than manually setting the parent for each of the child-groups after cloning, what other way is there?
If the hierarchy is deep this could get take to compute.
Thanks for the help!
Maybe you can check out this question Will three.js Object3D.clone() create a deep copy of the geometry?
I extends the copyand clone methods in Object3D to deep clone mesh materials.
And in your case , this should works too.
First,extends two new methods in THREE:
THREE.Object3D.prototype.deepClone = function ( recursive ) {
return new this.constructor().deepCopy( this, recursive );
},
THREE.Object3D.prototype.deepCopy = function( source, recursive ) {
if ( recursive === undefined ) recursive = true;
this.name = source.name;
this.up.copy( source.up );
this.position.copy( source.position );
this.quaternion.copy( source.quaternion );
this.scale.copy( source.scale );
this.matrix.copy( source.matrix );
this.matrixWorld.copy( source.matrixWorld );
if(source.material){
//changed
this.material = source.material.clone()
}
if(source.geometry){
//changed
this.geometry = source.geometry.clone()
}
this.matrixAutoUpdate = source.matrixAutoUpdate;
this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
this.layers.mask = source.layers.mask;
this.visible = source.visible;
this.castShadow = source.castShadow;
this.receiveShadow = source.receiveShadow;
this.frustumCulled = source.frustumCulled;
this.renderOrder = source.renderOrder;
this.userData = JSON.parse( JSON.stringify( source.userData ) );
if ( recursive === true ) {
for ( var i = 0; i < source.children.length; i ++ ) {
var child = source.children[ i ];
this.add( child.deepClone() ); //changed
}
}
return this;
}
Second,when you want to deep clone a Object3D or Scene named originalObj.just do var newObj = originalObj.deepClone()

how to use lockf with xerces-c

I am new to programming and I am trying to use lockf to lock a XML file. I using xerces-c to parse the XML file and I need to lock the file. The function is similar the the example below:
void GetConfig::readConfigFile(string& configFile)
throw( std::runtime_error )
{
// Configure DOM parser.
m_ConfigFileParser->setValidationScheme( XercesDOMParser::Val_Never );
m_ConfigFileParser->setDoNamespaces( false );
m_ConfigFileParser->setDoSchema( false );
m_ConfigFileParser->setLoadExternalDTD( false );
try
{
m_ConfigFileParser->parse( configFile.c_str() );
// no need to free this pointer - owned by the parent parser object
DOMDocument* xmlDoc = m_ConfigFileParser->getDocument();
// Get the top-level element: NAme is "root". No attributes for "root"
DOMElement* elementRoot = xmlDoc->getDocumentElement();
if( !elementRoot ) throw(std::runtime_error( "empty XML document" ));
// Parse XML file for tags of interest: "ApplicationSettings"
// Look one level nested within "root". (child of root)
DOMNodeList* children = elementRoot->getChildNodes();
const XMLSize_t nodeCount = children->getLength();
// For all nodes, children of "root" in the XML tree.
for( XMLSize_t xx = 0; xx < nodeCount; ++xx )
{
DOMNode* currentNode = children->item(xx);
if( currentNode->getNodeType() && // true is not NULL
currentNode->getNodeType() == DOMNode::ELEMENT_NODE ) // is element
{
// Found node which is an Element. Re-cast node as element
DOMElement* currentElement
= dynamic_cast< xercesc::DOMElement* >( currentNode );
if( XMLString::equals(currentElement->getTagName(), TAG_ApplicationSettings))
{
// Already tested node as type element and of name "ApplicationSettings".
// Read attributes of element "ApplicationSettings".
const XMLCh* xmlch_OptionA
= currentElement->getAttribute(ATTR_OptionA);
m_OptionA = XMLString::transcode(xmlch_OptionA);
const XMLCh* xmlch_OptionB
= currentElement->getAttribute(ATTR_OptionB);
m_OptionB = XMLString::transcode(xmlch_OptionB);
break; // Data found. No need to look at other elements in tree.
}
}
}
}
}
So, can anyone help me to implement lockf in this function?

Column in gwt celltable doesn't sort

I want to add sorting for column in celltable with help of ListHandler. But it doesn't sort. I don't understand why it doesn't work. My code is based on GWT tutorial.
Please suggest me something.
Contract.java
public class Contract implements Serializable {
private int contId;
private String contOrgName;
//getters and setters...
}
Main.java
TextColumn<Contract> orgNameColumn = new TextColumn<Contract>() {
#Override
public String getValue(Contract contract) {
return contract.getcontOrgName();
}};
orgNameColumn.setSortable(true);
CellTable<Contract> tableContract = new CellTable<Contract>();
tableContract.addColumn(orgNameColumn, "OrgName");
ListDataProvider<Contract> contractDataProvider = new ListDataProvider<Contract>();
contractDataProvider.addDataDisplay(tableContract);
GetContractsServiceAsync getContractsService = GWT.create(GetContractsService.class);
getContractsService.getContracts(new AsyncCallback<List<Contract>>() {
public void onFailure(Throwable caught) {
// Show the RPC error message to the user
}
public void onSuccess(List<Contract> result) {
contractDataProvider.getList().clear();
contractDataProvider.getList().addAll(result);
ListHandler<Contract> columnSortHandler = new ListHandler<Contract>(result);
columnSortHandler.setComparator(orgNameColumn, new Comparator<Contract>() {
public int compare(Contract o1, Contract o2) {
if (o1 == o2) {
return 0;
}
if (o1 != null) {
return (o2 != null) ? o1.getcontOrgName().compareTo(o2.getcontOrgName()) : 1;
}
return -1;
}
});
tableContract.addColumnSortHandler(columnSortHandler);
table.getColumnSortList().push(orgNameColumn);
}
});
Hey I was also facing the same issue a long back..Then I got to know that the object reference id is different than the one I have added into table. Once i got the reason it was very easy to find the solution.
Also please register your ListHandler before adding column to CellTable.
Note the edit for your comment :
There is nothing wrong with the comparator. The problem is still same. It reflects the wrong the object in comparator compared to in CellTable.
Please try replace the code as below :
contractDataProvider.getList().addAll(result);
ListHandler<Contract> columnSortHandler = new ListHandler<Contract>(contractDataProvider.getList());
Try to move the creation of your columnSortHandler out of the onSuccess Method. Place it right after you created your column.
At the moment you are adding the results before you add the columnSortHandler. I think that is the wrong order.
i my case, i did my sorting like this:
private void sortColumn( List<CModel> list ) {
int count = listOfColumns.size(); //upon adding the columns, i have created a list that will hold all the columns
if ( list.size() <= 0 ) {
for ( int i = 0; i < count; i++ ) {
listOfColumns.get(i).setSortable( false );
}
} else {
for ( int i = 0; i < count; i++ ) {
sort( i );
dg.redrawHeaders();
}
}
}
private void sort(int i) {
String[] listColHead = { /** list of column headers */ };
Column<CModel,?> column = listCheckoutColumns.get( i );
final String valueToCompare = listColHead[i];
final ListDataProvider<CModel> dataProvider = new ListDataProvider<CModel>();
// Connect the table to the data provider
dataProvider.addDataDisplay( dg );
// Add the data to the data provider, which automatically pushes it to the widget
List<CModel> list = dataProvider.getList();
for ( CModel product : listCheckout ) {
list.add( product );
}
column.setSortable( true );
// Add a ColumnSortEvent.ListHandler to connect sorting to the List
ListHandler<CModel> columnSortHandler = new ListHandler<CModel>( list );
columnSortHandler.setComparator( column, new Comparator<CModel>() {
public int compare( CModel p1, CModel p2 ) {
if ( p1 == p2 ) {
return 0;
}
// Compare the columns.
if ( p1 != null ) {
if ( valueToCompare.equals( "code" ) ) {
return ( p2 != null ) ? p1.getFproductid().compareTo( p2.getFproductid() ) : 1;
}
else if ( valueToCompare.equals( "desc" ) ) {
return ( p2 != null ) ? p1.getFproduct_name().compareTo( p2.getFproduct_name() ) : 1;
}
else if ( valueToCompare.equals( "type" ) ) {
return ( p2 != null ) ?
uec.computeTypeLabel( p1 ).compareTo( uec.computeTypeLabel( p2 ) ) : 1;
}
else if ( valueToCompare.equals( "maxex" ) ) {
return ( p2 != null ) ? uec.exQtyLabel( p1 ).compareTo( uec.exQtyLabel( p2 ) ) : 1;
}
else if ( valueToCompare.equals( "unit" ) ) {
return ( p2 != null ) ? p1.getFuom().compareTo( p2.getFuom() ) : 1;
}
else if ( valueToCompare.equals( "status" ) ) {
return ( p2 != null ) ? uec.qtyLabel( p1 ).compareTo( uec.qtyLabel( p2 ) ) : 1;
}
else if ( valueToCompare.equals( "qty" ) ) {
return ( p2 != null ) ? Double.compare( p1.getFqty(), p2.getFqty() ) : 1;
}
else if ( valueToCompare.equals( "price" ) ) {
return ( p2 != null ) ? uec.extPriceLabel( p1 ).compareTo( uec.extPriceLabel( p2 ) ) : 1;
}
else if ( valueToCompare.equals( "total" ) ) {
return ( p2 != null ) ? Double.compare( p1.getFtotal_line(), p2.getFtotal_line() ) : 1;
}
}
return -1;
}
});
dg.addColumnSortHandler( columnSortHandler );
dg.getColumnSortList().push( column );
}
everytime, i'll set the data for my DataGrid list,
dgCheckout.redraw();
dgCheckout.setRowCount( lengthOfList, true );
dgCheckout.setRowData( 0, newList );
sortColumn( newList );

extract content method of range skips tags in CKEditor

I want to make sidebar plugin in CKEditor.when I select text with bold and itallic tag ,than extract content skip that tags ,and returns just text .I want all selected text including all tags.
This is my code:
function sidebar(editor){
var selection = editor.getSelection();
if (selection.getSelectedText() != "") {
var ranges = selection.getRanges();
var pNode = editor.document.createElement('p');
var extractedContent = ranges[0].extractContents();
pNode.append(extractedContent);
var customNode = editor.document.createElement('cdl:sidebar');
customNode.append(pNode);
var sidebarHolder = editor.document.createElement("sidebarholder");
sidebarHolder.append(customNode);
var nodeHtml = sidebarHolder.getHtml();
selection.selectRanges(ranges);
editor.insertHtml(nodeHtml);
}
else {
showErrorMessage("Selection is not proper");
}
}
You can get multi selection text using ckeditor walk.
// Walker searching for guardElements.
var walker = new CKEDITOR.dom.walker( range );
var start = bookmarks[ i ].startNode,
end = bookmarks[ i++ ].endNode;
walker.evaluator = function( node )
{
return !! ( node.type == CKEDITOR.NODE_ELEMENT
&& node.getName() in guardElements
&& !( node.getName() == ( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' )
&& node.getParent().type == CKEDITOR.NODE_ELEMENT
&& node.getParent().getName() == 'blockquote' )
// Element must be fully included in the range as well. (#6485).
&& node.getPosition( start ) & CKEDITOR.POSITION_FOLLOWING
&& ( ( node.getPosition( end ) & CKEDITOR.POSITION_PRECEDING + CKEDITOR.POSITION_CONTAINS ) == CKEDITOR.POSITION_PRECEDING ) );
};
Use walker.js
http://docs.cksource.com/ckeditor_api/symbols/src/core_dom_walker.js.html

Resources