I want to check if the node inside the TinyMCE has a class starting with word 'border'. I tried to retrieve classes of the node, using
tinyMCE.activeEditor.dom.getClasses();
but it returned null.
Is there any way to do this ? I need to find if the node has any class staring with word 'border', if it has then replace that class with other.
No problem. Assuming you have only one node inside your editor it is:
class_string = tinyMCE.activeEditor.getBody().firstChild.class;
class_string_array = class_string.split(" ");
for (i=0; i < class_string_array.length; i++){
if (class_string_array[i].search("border") !== -1) {
alert("class found!");
class_string_array[i] = "new_class";
class_string = class_string_array.join(" ");
tinyMCE.activeEditor.getBody().firstChild.setAttribute('class',class_string);
break;
}
}
It is much easier to use jQuery:
node = tinyMCE.activeEditor.getBody().firstChild;
if ( $(node).hasClass("border_xxx") ){ // need to check for explicit className
$(node).removeClass("border_xxx");
$(node).addClass("new_class");
}
EDIT: If you want to check for every node inside the content you will need to go through the body-domtree recursivly and check for each node:
function getTextNodesValues(tinymce,node) {
if ( $(node).hasClass("border_xxx") ){ // need to check explicit className
$(node).removeClass("border_xxx");
$(node).addClass("new_class");
}
for (var i=0; i<node.childNodes.length; i++) {
el = node.childNodes[i];
if ( $(node).hasClass("border_xxx") ){ // need to check explicit className
$(node).removeClass("border_xxx");
$(node).addClass("new_class");
}
if (el.childNodes.length > 0) getTextNodesValues(tinymce,el);
}
}
getTextNodesValues(tinymce, getTextNodesValues(tinymce,node) );
Should get you all Classes inside the Editor:
tinyMCE.activeEditor.dom.getClasses();
but it is not easy to replace them with that info.
Related
I have a working web app that reads local .txt files and displays the content in a div element. I create a span element out of each word because I need to be able to select any word in the document and create an EEI (Essential Elements of Information) from the text. I then register a click handler on the containing div and let the event bubble up. The three functions below show reading the file, and parsing it, and populating the text div with spans:
function readInputFile(evt) {
reset();
var theFile = evt.target.files[0];
if(theFile) {
$("#theDoc").empty(); //Clean up any old docs loaded
var myReader = new FileReader();
var ta = document.getElementById("theDoc");
myReader.onload = function(e) {
parseTheDoc(e.target.result);
initialMarkup();
};
myReader.readAsText(theFile);
} else {
alert("Can not read input file: readInputFile()");
}
}
function parseTheDoc(docContents) {
var lines = docContents.split("\n");
var sentWords =[];
for(var i = 0; i < lines.length; i++) {
sentWords = lines[i].split(" ");
words = words.concat(sentWords);
words.push("<br>");
}
//examineWords(words);
createSpans(words);
}
function createSpans() {
for (var i = 0; i < words.length; i++) {
var currentWord = words[i];
if(currentWord !== "<br>") {
var $mySpan = $("<span />");
$mySpan.text(currentWord + " ");
$mySpan.attr("id", "word_" + i);
$("#theDoc").append($mySpan);
buildDocVector(currentWord, i, $mySpan);
}
else {
var $myBreak = $("<br>");
$myBreak.attr("id", "word_" + i);
$("#theDoc").append($myBreak);
buildDocVector("br", i, $myBreak);
}
}
//console.log("CreateSpans: Debug");
}
So basically a simple fileReader, split on \n, then tokenize on white space. I then create a span for each word, and a br element for each \n. It's not beautiful, but it satisfies the requirement, and works. My question is, is there a more efficient way of doing this? It just seems expensive to create all these spans, but my requirement is to annotate the doc and map any selected word to a data model/ontology. I can't think of a way to allow the user to select any word, or combination of words (control click) and then perform operations on them. This works, but with large docs (100 pages) I start having performance/memory issues. I understand this is more a design question and may not be appropriate, but I'd really like to know if there are more performant solutions.
I am trying to find a specific element from my page using ExtJS 4 so I can do modifications on it.
I know its id so it should not be a problem BUT
-I tried Ext.getCmp('theId') and it just return me undefined
-I tried to use down('theId') method by passing through the view and I still get a nullresponse.
As I know the id of the element I tried again the two methods by setting manually the id and it didn't work neither.
Do these two methods not function?
How should I do?
Here is the concerned part of the code :
listeners: {
load: function(node, records, successful, eOpts) {
var ownertree = records.store.ownerTree;
var boundView = ownertree.dockedItems.items[1].view.id;
var generalId = boundView+'-record-';
// Add row stripping on leaf nodes when a node is expanded
//
// Adding the same feature to the whole tree instead of leaf nodes
// would not be much more complicated but it would require iterating
// the whole tree starting with the root node to build a list of
// all visible nodes. The same function would need to be called
// on expand, collapse, append, insert, remove and load events.
if (!node.tree.root.data.leaf) {
// Process each child node
node.tree.root.cascadeBy(function(currentChild) {
// Process only leaf
if (currentChild.data.leaf) {
var nodeId = ""+generalId+currentChild.internalId;
var index = currentChild.data.index;
if ((index % 2) == 0) {
// even node
currentChild.data.cls.replace('tree-odd-node', '')
currentChild.data.cls = 'tree-even-node';
} else {
// odd node
currentChild.data.cls.replace('tree-even-node', '')
currentChild.data.cls = 'tree-odd-node';
}
// Update CSS classes
currentChild.triggerUIUpdate();
console.log(nodeId);
console.log(ownertree.view.body);
console.log(Ext.getCmp(nodeId));
console.log(Ext.getCmp('treeview-1016-record-02001001'));
console.log(ownertree.view.body.down(nodeId));
console.log(ownertree.view.body.down('treeview-1016-record-02001001'));
}
});
}
}
You can see my console.log at the end.
Here is what they give me on the javascript console (in the right order):
treeview-1016-record-02001001
The precise id I am looking for. And I also try manually in case...
h {dom: table#treeview-1016-table.x-treeview-1016-table x-grid-table, el: h, id: "treeview-1016gridBody", $cache: Object, lastBox: Object…}
I checked every configs of this item and its dom and it is exactly the part of the dom I am looking for, which is the view containing my tree. The BIG parent
And then:
undefined
undefined
null
null
Here is the item I want to access:
<tr role="row" id="treeview-1016-record-02001001" ...>
And I checked there is no id duplication anywhere...
I asked someone else who told me these methods do not work. The problem is I need to access this item to modify its cls.
I would appreciate any idea.
You are looking for Ext.get(id). Ext.getCmp(id) is used for Ext.Components, and Ext.get(id) is used for Ext.dom.Elements. See the docs here: http://docs.sencha.com/extjs/4.2.1/#!/api/Ext-method-get
Ok so finally I used the afteritemexpand listener. With the ids I get the elements I am looking for with your Ext.get(id) method kevhender :).
The reason is that the dom elements where not completely loaded when I used my load listener (it was just the store) so the Ext.get(id) method couldn't get the the element correctly. I first used afterlayout listener, that was correct but too often called and the access to the id was not so easy.
So, here is how I did finally :
listeners: {
load: function(node, records, successful, eOpts) {
var ownertree = records.store.ownerTree;
var boundView = ownertree.dockedItems.items[1].view.id;
var generalId = boundView+'-record-';
if (!node.tree.root.data.leaf) {
// Process each child node
node.tree.root.cascadeBy(function(currentChild) {
// Process only leaf
if (currentChild.data.leaf) {
var nodeId = ""+generalId+currentChild.internalId;
var index = currentChild.data.index;
if ( (index % 2) == 0 && ids.indexOf(nodeId) == -1 ) {
ids[indiceIds] = nodeId;
indiceIds++;
}
console.log(ids);
}
});
}
},
afteritemexpand: function( node, index, item, eOpts ){
/* This commented section below could replace the load but the load is done during store loading while afteritemexpand is done after expanding an item.
So, load listener makes saving time AND makes loading time constant. That is not the case if we just consider the commented section below because
the more you expand nodes, the more items it will have to get and so loading time is more and more important
*/
// var domLeaf = Ext.get(item.id).next();
// for ( var int = 0; int < node.childNodes.length; int++) {
// if (node.childNodes[int].data.leaf && (int % 2) == 0) {
// if (ids.indexOf(domLeaf.id) == -1) {
// ids[indiceIds] = domLeaf.id;
// indiceIds++;
// }
// }
// domLeaf = domLeaf.next();
// }
for ( var int = 0; int < ids.length; int++) {
domLeaf = Ext.get(ids[int]);
if (domLeaf != null) {
for ( var int2 = 0; int2 < domLeaf.dom.children.length; int2++) {
if (domLeaf.dom.children[int2].className.search('tree-even-node') == -1){
domLeaf.dom.children[int2].className += ' tree-even-node';
}
}
}
}
},
With ids an Array of the ids I need to set the class.
Thank you for the method.
I got a Ext.form.Basic with the trackResetOnLoad:true config.
When I call reset() on a field it gets its values from the form setValues() method.
How do I reset my fields now?
When I just do field.setValue('') the form marks it as invalid because the field is required.
Thanks in advance.
You have to manually reset all of the originValues of all fields (and some other)
This snipped will do this
var items = form.getForm().getFields().items,
i = 0,
len = items.length;
for(; i < len; i++) {
var c = items[i];
c.value = '';
if(c.mixins && c.mixins.field && typeof c.mixins.field['initValue'] == 'function'){
c.mixins.field.initValue.apply(c);
c.wasDirty = false;
}
}
working example
What works for me is to take a copy of the values just after the form is created using something like var originalValues = myForm.getFieldValues(); then I can later restore those values using myForm.setValues(originalValues); instead of calling myForm.reset(...);
I am trying to find a string in a javascript array in the transformer of a mirth channel. Mirth throws an error when I try to use indexOf function. My understanding is that indexOf is something that browsers add in, rather than a native part of the javascript language itself. ( How do I check if an array includes an object in JavaScript? )
So is array.indexOf just not supported in Mirth? Is there any way to use .indexOf in Mirth? Maybe an alternate syntax? Or do I need to just loop thru the array to search?
This is how I search arrays in a Mirth js transformer:
var Yak = [];
Yak.push('test');
if(Yak.indexOf('test') != -1)
{
// do something
}
Does this give you error?
Mirth uses the Rhino engine for Javascript, and on some earlier versions of the JVM, indexOf appeared to not be supported on arrays. Since upgrading our JVM to 1.6.23 (or higher), indexOf has started working. However, we still have legacy code that, when searching arrays of strings, I just use a loop each time:
var compareString = "blah";
var index = -1;
for (var i = 0; i < myArray.length; ++i)
{
if (myArray[i] == compareString)
{
index = i;
break;
}
}
If you need to do this frequently, you should be able to use a code template to manually add the indexOf function to Array.
Set the code template to global access, and try out something like this (untested code):
Array.prototype.indexOf = function(var compareObject)
{
for (var i = 0; i < myArray.length; ++i)
{
// I don't think this is actually the right way to compare
if (myArray[i] == compareObject)
{
return i;
}
}
return -1;
}
var arr = ['john',1,'Peter'];
if(arr.indexOf('john') > -1)
{
//match. what to do?
console.log("found");
}
else
{
console.log("not found");//not found .. do something
}
var i = ['a', 'b', 'c']
if(i.indexOf('a') > -1)
{
///do this, if it finds something in the array that matches what inside the indexOf()
}
else
{
//do something else if it theres no match in array
}
I'm writing a tinyMce plugin which contains a section of code, replacing one element for another. I'm using the editor's dom instance to create the node I want to insert, and I'm using the same instance to do the replacement.
My code is as follows:
var nodeData =
{
"data-widgetId": data.widget.widgetKey(),
"data-instanceKey": "instance1",
src: "/content/images/icon48/cog.png",
class: "widgetPlaceholder",
title: data.widget.getInfo().name
};
var nodeToInsert = ed.dom.create("img", nodeData);
// Insert this content into the editor window
if (data.mode == 'add') {
tinymce.DOM.add(ed.getBody(), nodeToInsert);
}
else if (data.mode == 'edit' && data.selected != null) {
var instanceKey = $(data.selected).attr("data-instancekey");
var elementToReplace = tinymce.DOM.select("[data-instancekey=" + instanceKey + "]");
if (elementToReplace.length === 1) {
ed.dom.replace(elementToReplace[0], nodeToInsert);
}
else {
throw new "No element to replace with that instance key";
}
}
TinyMCE breaks during the replace, here:
replace : function(n, o, k) {
var t = this;
if (is(o, 'array'))
n = n.cloneNode(true);
return t.run(o, function(o) {
if (k) {
each(tinymce.grep(o.childNodes), function(c) {
n.appendChild(c);
});
}
return o.parentNode.replaceChild(n, o);
});
},
..with the error Cannot call method 'replaceChild' of null.
I've verified that the two argument's being passed into replace() are not null and that their parentNode fields are instantiated. I've also taken care to make sure that the elements are being created and replace using the same document instance (I understand I.E has an issue with this).
I've done all this development in Google Chrome, but I receive the same errors in Firefox 4 and IE8 also. Has anyone else come across this?
Thanks in advance
As it turns out, I was simply passing in the arguments in the wrong order. I should have been passing the node I wanted to insert first, and the node I wanted to replace second.