How to get the id of an maxGraph cell's content - javascript

I've created a graph and am setting cells onto it via drag and drop. However when a drop or click happens I cannot find the clicked cell's html for use.
For instance I'm trying to get the ID of the dragged element within the mxEvent.CLICK.
graph.addListener(mxEvent.CLICK, function(sender, evt){
var cell = evt.properties.cell;
// cell.id is the cell id, not an id of html that's inside of it.
if(cell) {
var outer = cell.value.outerHTML; // I can see the HTML here encoded
}
})
UPDATES:
So I add the html to the cell with value.setAttribute('htmlLabel', label); when my draggable items are created. However htmlLabel does not seem to be a key anywhere in the evt object.

I've been working with MxGraph for a few months now on a large project, and while it's a great library, it's a bit cumbersome to use in some areas.
Getting at the HTML is one of those areas.
First off, you need to grab the objects of the event using the "MxGraph" tool set, as follows:
graph.addListener(mxEvent.CLICK, function(sender, event){
var mouseEvent = event.getProperty('event');
var selectedCell = event.getProperty('cell');
});
As you've already worked out, you can get the cell ID from the selected cell, via it's ID property, but other than that, there's not a great deal of other things on that object.
To go deeper, you need to drill down in the mouse event that you also get.
It's just a normal HTML event and as such has the regular properties on it you would expect to find.
In your case
mouseEvent.currentTarget.innerHTML
Will get you the HTML of the element you clicked on (You may need to explore different paths in your debugger, but that certainly works for me in the latest version of chrome)
One thing you need to be aware of though, MxGraph renders ALL of it's output using SVG and as far as I can see there is NO standard HTML ID attribute on the rendered tag, in fact none of the rendered graph elements appear to have ID's on them.
I hit this problem a week ago when I was trying to grab the output generated by MxGraph to do some image manipulation, and because I couldn't reliably grab a single image, I had to resort to using Base64 encoded strings and manipulating the cell stylesheets using MxGraph's API.

I used xml to create the diagram:
...
<mxCell id="start" value="Start" style="start" vertex="1" parent="1"><mxGeometry x="0" y="0" width="30" height="30" as="geometry"/></mxCell>
...
So I get the ID with this code:
graph.addListener(mxEvent.CLICK, function (sender, evt) {
var cell = evt.getProperty("cell");
var id = cell.id;
}
Version 3.9.11

in version 3.9.8
I tried to use the above code, but found error with (graph), with more search and try, I found the suitable is (mxGraph.prototype), so this code should be:
mxGraph.prototype.addListener(mxEvent.CLICK, function(sender, event){
var mouseEvent = event.getProperty('event');
var selectedCell = event.getProperty('cell');
});

Related

Custom properties and select/drop down menus

I'm customising mxGraph and am looking into custom properties. I'm using the mxDraw template. Creating custom properties for a shape is easy enough such as the below (modifying diagrameditor.xml):
<add as="rectangle">
<Rect label="Rectangle" href="" new_property="hi there">
<mxCell vertex="1">
<mxGeometry as="geometry" width="80" height="40"/>
</mxCell>
</Rect>
</add>
When using mxDraw these properties are immediately visible and all is well, except I want to be able to choose a value for this property using a drop-down menu.
I'm having trouble finding an example of this elsewhere on the internet, and I'm not really sure what my options are here, or where to start.
In my mind there are a few options, but am hoping I can get some guidance on where to even start here...
Disregard custom properties like the above and instead use a separate DIV, an event listener for selected shape and use HTML forms to capture properties/values
Modify diagrameditor.xml like the above code snippet and somehow modify existing javascript library
Some sort of hybrid of the above 2?
Eventually the resulting graph XML/data will be POSTed to the web server for storage, which can then merge/correlate data accordingly.
I know SO has some experienced mxGraph programmers so hoping to get some thoughts from those more experienced than I, so I can go and research. I can't seem to find what I'm looking for so far (in terms of guidance, examples or others attempting a similar thing).
Any help appreciated, thanks.
I kept researching and found a solution that suits me.
Update diagrameditor.xml and create custom data fields. Example shown in my original post
Create a new DIV on the page
Setup a listener for cell selection, add some HTML forms then use mxGraph calls to update the property values
To be done: disable the right-click menu so it cannot be updated manually using the text field, to ensure inputs are valid
Below is the starting code for the HTML page.
<div id="customdata" style="position:relative;padding-left:100px;padding-top:10px;">
<script>
var selectedCell;
mxGraph.prototype.addListener(mxEvent.CLICK, function(sender, event){
selectedCell = event.getProperty('cell');
//update DIV content example. Show cell ID and a drop-down to update a custom data field called 'new_property' (as created in diagrameditor.xml)
var newhtml = "Cell ID is: ";
newhtml += selectedCell.getId();
newhtml += `<select><option id="selectmenu" value="one">one</option><option value="two">two</option></select>`
newhtml += `<button onclick="updateCustomData();">save</button>`
document.getElementById("customdata").innerHTML = newhtml;
//Can also iterate through a multiple-selection and do more things, if need be
/*
for (var i = 0; i < sender.getSelectionCount(); i++) {
//example, alert showing the label of the cell at this array index i
alert(sender.getSelectionCells()[i].getAttribute('label', ''));
}
*/
});
function updateCustomData() {
selectedCell.setAttribute("new_property", document.getElementById("selectmenu").value);
}
</script>
div content
</div>
I hope this question can be left here to serve as potential help for others. I'm still a new SO user, great community. Hope this can be my little contribution.

Linking XML elements to page items in InDesign

I can check the XML of selected text like this:
app.selection[0].associatedXMLElements[0];
But in my research, I am still left scratching my head about how to do the most basic thing with XML using script: how do I assign XML to items? I can manually do this by opening the structure pane, then dragging the element over the desired frame on the page. If it's possible the old fashioned way, I imagine it's possible with script.
How do I link an existing XML element to an existing page item?
The above code only seems to work on selected text. If I select a graphic, it won't run.
How can I link XML to a selected graphic?
You can reference your xml node and your text frame and use placeXML
myXMl = myDoc.xmlElements[0];
var myXmlNode = myXMl.evaluateXPathExpression("/myXML/node1")[0];
var myFrame = app.activeDocument.pages[0].textFrames[0];
myXmlNode.placeXML(myFrame);
The advantage of this approach is that any aid:pstyle or aid:cstyle will be linked to existing matching style automaticaly
The alternative is to select the value of the node as text and place it into the text frame at insertion point:
myXMl = myDoc.xmlElements[0];
var myText = myXMl.xpath("/myXML/node1[1]/text()");
var myFrame = app.activeDocument.pages[0].textFrames[0];
myFrame.parentStory.insertionPoints[-1].contents = myText + '\r';
there are two specific properties. AssociatedXMLElement is for pageItems including textFrames and may be null if no tag is applied. AssociatedXMLElements only applies to text objects (characters, words…) because they can have several tags applied. Note that a non tagged text return an empty array and not null.
Associating tags to pageItems require that you first create or target existing xmlElements then use myInDesignObject.markup ( myXMLElement ).
EvaluateXPathExpression as Nicolai suggested is interesting once you want to browse through your XML structure. But it's sometimes quicker indeed to investigate associated XMLElement from the object rather than investigating the xml structure.
FWIW

Listen to specific changes on contenteditable?

Warning: not duplicate with existing questions, read through
I know I can have an event listen on changes on an contenteditable element.
What I would like is to be able to know what the changes are.
For example:
inserted "This is a sentence." at position X.
deleted from position X to Y.
formatted from X to Y with <strong>
Is that possible? (other than by doing a diff I mean)
The reason for this is to make a WYSIWYG editor of other languages than HTML, for example Markdown.
So I'd like to apply the changes to the Markdown source (instead of having to go from HTML to Markdown).
You may be able to do something with MutationObservers (falling back to DOM Mutation events in older browsers, although IE <= 8 supports neither) but I suspect it will still be hard work to achieve what you want.
Here's a simple example using MutationObservers:
http://jsfiddle.net/timdown/4n2Gz/
Sorry, but there is no way to find out what the changes are without doing a diff between the original content and the modified one when changes occur.
Are you looking for this
var strong=document.createElement("strong");
var range=window.getSelection().toString().getRangeAt(0);
range.surroundContents(strong);
this was for third part
You just need to select what you want to surround using real User interaction.
If you wanna do it dynamically
var range=document.createRange();
range.setStart(parentNode[textNode],index to start[X])
range.setEnd(parentNode[textNode],index to end[Y])
range.surroundContents(strong);
For 2nd Part
range.deleteContents()
1st part can be done by using simple iteration
var textnode=// node of the Element you are working with
textnode.splitText(offset)
offset- position about which text node splitting takes place[here==X]
Two child Nodes have been created of the parent editable Element
Now use simple insertBefore() on parent editable Element Node.
hope you will find it useful
The API you're looking for does not exist, as DOM nodes do not store their previous states.
The data / events you're wishing to get back are not native implementations in any browser Ive come across, and I struggle to think of a datatype that would be able to generically handle all those cases. perhaps something like this:
function getChanges() {
/* do stuff here to analyse changes */
var change = {
changeType : 'contentAdded',
changeStart : 50, /* beginning character */
changeContent : 'This is a sentence'
}
return change;
}
Since you're trying to get custom events / data, you're probably going to need a custom module or micro-library. Either way, to look at the changes of something, you need somehow be aware of what has changed, which can only be done by comparing what it was to what it is now.

JavaScript seem just to react after MouseMove

probably the strangst thing I've ever seen: I want to load a grid after the document is loaded. Since the grid (infragistics) seems to delay, I set a interval, in the interval I try to get the needed element, if I cant find it, I wait another 500 ms:
function trySetEditMode(obj) {
var testObj = $('#' + obj.btnId).parents("tr[type='row']").get(0);
if (testObj && testObj._object){
clearInterval(_intervalId);
The funny thing is: Even if I see the with the IE debugging tool the row is there, it justdoenst find it. It works just when I move arround with the mouse. This effect seems totally random.
Has anyone an idea how this is possible? I tried to tinker arorund with .focus, .blur etc, but nothing seems to work.
btw: obj is a custom object from me, the button id is the clientid of the button and is there. For example:
$('#' + obj.btnId).parents('tr').length
returns a length.
Can this be a bug from the infragistics control? If yes, how could I simulate this mouseMove?
Best regards
Matthias
Creating the row objects is costly on the client and as such they are created on demand to avoid a large performance hit if all row objects were created initially. The actual creation of these objects is on mouse over or when you use the get_row() method that is provided as part of the client side object model. As such the recommended approach is to use the client side object model to get a reference to the row, for example the following will get the first row:
var grid = $find("webDataGrid1");
var row = grid.get_rows().get_row(0);
probably someoneelse will have this problem as well with infragistics webdatagrid:
Sidenote: I cant believe the ig support couldnt tell me that:
The Grid is kinda lazyLoaded, the dom gets loaded but the ig relevant attributes AND the object behind just get loaded when you go with the mouse over. So it didnt matter how long I waited, the object wasnt just there.
Since I had no time to get a proper solution, I basically fired manually the mouse over event on a cell. It doesnt matter on what you do this, but I tested it with the first one and it worked proper.
//The grid doesnt load data (except the first row) until the mouse did hover over it
//Get a cell, and hover over it
var parentTd = btn.parents('td').first();
var cell = parentTd.siblings()[0];
var rows = $find('dgrRoles').get_rows();
if (cell && rows) {
cell.target = cell;
rows._onMouseOver(cell);
}

JavaScript - How to get the current selection 'index' within a document

My code here returns a JavaScript selection object from within an iFrame (the iFrame page is within the same domain, so no xss issue).
What I need to know is the index of the selection within the raw html code (not the dom).
UPDATE:
E.g.
If you have an html doc:
<html><body>ABC</body></html>
And in the UI, the user uses their mouse to select the text 'ABC', I want to be able to use JavaScript to determine the postion of the selected text in the html source. In this case the index of ABC is 13.
UPDATE 2
The reason I'm persisting with this madness, is that I need to create a tool that can revisit a page and pull text based on a selected text the user has identified at an earlier time. The user tells the system where the text is, and the system from that point on uses regular expressions to pull the text. Now, if the dom is not the same as the raw html, and there's no way to pinpoint the selection in the raw html - it's really difficult to know what reg ex to generate. I don't think there's another way around this.
// Returns the raw selection object currently
// selected in the UI
function getCurrentSelection() {
var selection = null;
var iFrame = document.getElementById('uc_iFrameGetPriceData');
try {
if (window.getSelection) { // Gecko
selection = iFrame.contentWindow.getSelection();
}
else { // IE
var iframeDoc = iFrame.contentWindow.document;
if (iframeDoc.selection) {
selection = iframeDoc.selection;
}
else {
selection = iframeDoc.contentWindow.getSelection();
}
}
}
catch (err) {
alert( 'Error: getCurrentSelection() - ' + err.description )
}
return selection;
}
You can access the index and offset of your selection by using selection.anchorOffset and selection.focusOffset.
Take a look at this:
http://help.dottoro.com/ljjmnrqr.php
And here's another well explaned article:
http://www.quirksmode.org/dom/range_intro.html
update to your update: I'm not sure why you're trying to get the index of the raw HTML code. But you can walk the DOM based on the selection kinda like this:
selection.anchorNode.nodeValue.replace(selection.anchorNode.nodeValue.substring(selection.anchorOffset, selection.focusOffset), 'replace value')
Note that it's still possible that anchorOffset is before focusOffset, based on whether you selected the text from left to right or from right to left.
If I understand correctly, you're looking to move around in the DOM. In that case, you can use these methods/properties:
parentNode
getChildNodes()
firstChild and lastChild
...and these links might help:
http://www.codingforums.com/archive/index.php/t-81035.html
http://www.sitepoint.com/forums/showthread.php?t=586034
The fastest way is probably
var node = document.getElementById('myElement');
alert(node.parentNode.indexOf(node));
(Sorry, for some reason the formatting buttons aren't showing up in my "Your Answer" area...)
I would be surprised if that information was available.
No DOM API is going to let you distinguish between
<html><body>ABC</body></html>
and
<html ><body >ABC</body></html>
The index in the raw HTML is different in each case, but the constructed DOM is identical.
You can't do this sensibly: the only possible method is to re-download the page's HTML via Ajax, parse the HTML and match the resulting DOM against the current DOM, which may itself have been altered by JavaScript. Besides, it's not a useful number anyway because once the page has been loaded, the original HTML string simply no longer exists in the DOM so offsets within that string have no meaning in JavaScript. Getting the selection in terms of nodes and offsets is much more sensible.

Categories

Resources