JointJS - how to change the content of a joint.elementTools.Button when clicked - jointjs

I used the example code to create an info button (https://resources.jointjs.com/tutorial/element-tools). But I would like it to change when clicked. (I actually modified the example to show a "+" instead of a blue info circle, by using text and textContent instead of a path in the markup definition. But I would be happy to learn how to make the original example change when clicked, too.)
So when you click it I want it to show some info and change to a "-". And then if you click the "-", change back to a "+". I don't see how to change the textContent of the elementTools.Button programmatically or in an event. It was easy enough to change the label of the associated Rectangle. Inside the event I just did this.model.attr("label/text", "whatever"). But how to do it to the element tool Button?
There is an example that's pretty good, using a custom element containing subelements not tools (halfway through https://resources.jointjs.com/tutorial/events). Does it mean I can't use an element tool, that element tools can't change on an event?

The behaviour of the Button tool can be adjusted in the callback function in options.action.
joint.elementTools.InfoButton = joint.elementTools.Button.extend({
name: 'info-button',
options: {
action: function(evt, elementView, buttonView) {
// your action
}
}
});
Although, in your case I would probably go with the example using custom events you linked in your question. It is probably more flexible to work with an element rather than a tool in this instance.

Related

OrchardCMS: How to access Content Menu Item boolean field in cshtml view

In orchard, I've added a boolean field called "IsDone" to the built in Content Menu Item content part via that Admin interface. I've then picked an item in Navigation and set the option to "yes" for the corresponding field i added.
In my custom theme, I've copied over MenuItem.cshtml.
How would I get the value of my custom "IsDone" field here?
I've tried something like
dynamic item = Model.ContentItem;
var myValue = item.MenuItem.IsDone.Value;
but I'm pretty sure my syntax is incorrect (because i get null binding errors at runtime).
thanks in advance!
First i suggest you use the shape alternate MenuItemLink-ContentMenuItem.cshtml instead of MenuItem.cshtml to target the content menu item directly.
Secondly, the field is attached to the ContentPart of the menu item. The following code retrieves the boolean field from this content part:
#using Orchard.ContentManagement;
#using System.Linq;
#{
Orchard.ContentManagement.ContentItem lContentItem = Model.Content.ContentItem;
var lBooleanField = lContentItem
.Parts
.Where(p => p.PartDefinition.Name == "ContentMenuItem") // *1
.SelectMany(p => p.Fields.Where(f => f.Name == "IsDone"))
.FirstOrDefault() as Orchard.Fields.Fields.BooleanField;
if (lBooleanField != null)
{
bool? v = lBooleanField.Value;
if (v.HasValue)
{
if (v.Value)
{
#("done")
}
else
{
#("not done")
}
}
else
{
#("not done")
}
}
}
*1
Sadly you cannot simply write lContentItem.As<Orchard.ContentManagement.ContentPart>() here as the first part in the part list is derived from this type, thus you would receive the wrong part.
While #ViRuSTriNiTy's answer is probably correct, it doesn't take advantage of the power of the dynamic objects that Orchard provides.
This is working for me but is a much shorter version:
#Model.Text
#{
bool? IsDone = Model.Content.ContentMenuItem.IsDone.Value;
var IsItDoneThough = (IsDone.HasValue ? IsDone.Value : false);
}
<p>Is it done? #IsItDoneThough</p>
You can see that in the first line I pull in the IsDone field using the dynamic nature of the Model.
For some reason (I'm sure there is a good one somewhere) the BooleanField uses a bool? as its backing value. This means that if you create the new menu item and just leave the checkbox blank it will be null when you query it. After you have saved it as checked it will be true and then if you go back and uncheck it then it will have the value false.
The second line that I've provided IsItDoneThough checks if it has a value yet. If it does then it uses that, otherwise it assumes it to be false.
Shape Alternate
#ViRuSTriNiTy's other advice, to change it to use the MenuItemLink-ContentMenuItem.cshtml instead of MenuItem.cshtml is also important.
The field doesn't exist on other menu items so it will crash if you try to access it. Just rename the .cshtml file to fix this.
Dynamic Model
Just to wrap this up with a little bit of insight as to how I got there (I'm still learning this as well) the way I figured it out is as follows:
.Content is a way of casting the current content item to dynamic, so you can use the dynamic advantages with the rest of line;
When you add the field in the admin panel it looks like it should be right there on the ContentItem, however it actually creates an invisible ContentPart to contain them and calls it whatever the ContentItem's type is.
So if you had added this field to a Page content type you would have used Model.Content.Page.IsDone.Value. If you had made a new content type called banana it would be Model.Content.Banana.IsDone.Value, etc.
Once you are inside the "invisible" part which holds the fields you can finally get at IsDone. This won't give you the actual value yet though. Each Field has its own properties which you can look up in the source code. the IsDone is actually a BooleanField and it exposes its data via the Value property.
Try doing a solution-wide search for : ContentField to see the classes for each of the fields you have available.
Hopefully this will have explained things clearly but I have actually written about using fields in a blog post and as part of my getting started with modules course over on the official docs (its way down in part 3 if you're curious).
Using built-in features instead of IsDone
This seems like a strange approach to do it this way. If you have a Content Item like a Page then you can just use the "Show on a menu" setting on the page.
Go to admin > content > open the page > down near the bottom you will find "Show on a menu":
This will automatically put it into your navigation and then you can move it around to where you want:
After it "IsDone" you can just go back and untick the "Show on a menu" option.
Setting up the alternative .cshtml
To clarify your comments about how to use the alternative, you need to
Copy the file you have at Orchard.Core/Shapes/Views/MenuItem.cshtml over to your theme's view folder so its /Views/MenuItem.cshtml
Rename the copy in your theme to MenuItem-ContentMenuItem.cshtml
Delete probably everything in it and paste in my sample at the start of this post. You don't want most of the original MenuItem.cshtml code in there as it is doing some special tricks to change itself into a different shape which isn't what you want.
Reset your original Orchard.Core/Shapes/Views/MenuItem.cshtml back to the factory default, grab it from the official Orchard repository
Understanding the view names
From your comments you asked about creating more specific views (known as alternates). You can use something call the Shape Tracer to view these. The name of them follows a certain pattern which makes them more and more specific.
You can learn about the alternates on the official docs site:
Accessing and Rendering Shapes
Alternates
To figure out what shape is being used and what alternates are available you can use the shape tracing module which is documented here:
Getting Started with Shape Tracing

How can we use ONLY client side script for "hide/whens"?

I am working on a large, worldwide application, which includes access from areas of low bandwidth. As such, I want to use a minimum of SSJS or partial refreshes for all the complex hide/when calculations. Here is what I have so far for a simple "hide/when":
A Yes/No radio button, with CSJS to show a panel ("Yes") or hide the
panel ("No").
The panel has a formTable inside it, and the values are shown or hidden, as per #1.
In the XPage's onClientLoad, the following code is run:
// "getRadioValue" is a simple script to return the value of a radio button
var v_value = getRadioValue("#{id:radioButton}");
v_div = '#{javascript:getClientId("radioButtonPanel")}';
// show or hide div simply use dojo to change the display of the panel
if (v_value == 'Yes') {
showDiv(v_div);
} else {
hideDiv(v_div);
};
For a new document, the onClientLoad script will hide the "radioButtonPanel" successfully. Changing the radio button to "Yes" will show the radioButtonPanel, just as clicking "No" will hide it. It works great! :-)
Once the document is saved and reopened in read mode, though, the onClientLoad CSJS event should read the saved value in the document, and decide to show the panel or not. When the document is opened in edit mode, the onClientLoad fires, reads the radioButton value and successfully shows or hides the panel.
This is what I've tried so far, to get it to work in read mode:
In CSJS, using "#{javascript:currentDocument.getItemValueString('radioButton'}" to get the value,
Doing some calculations in the "rendered" or "visible" properties, but that's SSJS and, if hidden, prevents any of the "show/hideDiv" CSJS visibility style changes.
Adding an old fashioned "div" to compute the style (which is what I used to do before XPages), but since I can't do pass-thru html any more, I can't seem to get a CSJS calculation for the style. Ideally, I can do something like this:
<div id="radioButtonPanel" style="<ComputedValue>">
Where the ComputedValue would read the back end value of the document, and decide to add nothing or "display:none".
Note that I don't want to use viewScopes, since this long form would need many of them for all the other hide/when's.
Is there any way to make this 100% CSJS? I feel like I'm very close, but I wonder if there's something I'm just missing in this whole process.
First, rather than computing style, I'd recommend computing the CSS class instead -- just define a class called hidden that applies the display:none; rule. Then toggling visibility becomes as simple as a call to dojo.addClass or dojo.removeClass.
Second, I see that you're using the #{id:component} syntax to get the client ID of the radio button but using SSJS to get the client ID of the panel. Use the id: syntax for both; this is still just a server-side optimization, but if there are many instances of these calculations, it adds up. Similarly, replace #{javascript:currentDocument.getItemValueString('radioButton'} with #{currentDocument.radioButton}. Both will return the same value, but the latter will be faster.
Finally, any attribute of a pass-thru tag (any component with no namespace, like xp: or xc:) can still be computed, but you'll need to populate the expression by hand, since the editor doesn't know which attributes for valid for these tags, and therefore doesn't provide a graphical expression editor. So if the ideal way to evaluate the initial display is by wrapping the content in a div, the result might look something like this:
<div class="#{javascript:return (currentDocument.getValue('radioButton') == 'Yes' ? 'visible' : 'hidden');}">
<xp:panel>
...
</xp:panel>
</div>

How to click a strange link looks like button in watir

I want to use the Watir to click a link that looks like a button attached the image.
I use the following method,but doesn't works:
#browser.div(:id,"NetworkAnalysisTabPanel").div(:index,1).div(:index,1).ul(:index,1).li(:index,1).link(:index,2).click
Note:
#browser.div(:id,"NetworkAnalysisTabPanel").div(:index,1).div(:index,1).ul(:index,1).li(:index,1).link(:index,2).flash
is working fine but click is not working in IE and FF
Link looks like this:
And HMTL like this:
Note: I am able to click on the element using selenium IDE with clickAt method
Try this (not tested):
browser.link(:class => "x-tab-strip-menu").click
If you can flash the link, but click does not do what you want, see this: How to find out which JavaScript events fired?
FYI what you have are links that are using standard background images controlled via CSS magic that keys on the class of the link to know what background to set. That's where the image comes from, and why you don't see it as part of the link in the HTML.
In that control, each tab is a list item element (li) in an unordered list (ul), and each list item has an ID, so that's the easiest way to tell it which tab you are trying to click inside.
Try identifying things starting with the LI that is the tab container, as within that container there is only one instance of each link of a given class. Of the 4 links, only one is without any kind of easy identifier, and if you need to click that one you'd need to use :index, but for the other 3 links using :class ought to work. This should result in code that is less brittle and subject to being broken if the order of tabs changes, or the page is refactored.
#browser.li(:id,"NetworkAnalysisTabPanel__ext-comp-1038").link(:class, "x-tab-strip-menu").click
If the number at the end of the ID is subject to change, you can try a regular expression to match the part you can predict and is unique from the others
#browser.li(:id,/NetworkAnalysisTabPanel__ext-comp-/).link(:class, "x-tab-strip-menu").click
If you can reliably identify the object and use .flash but .click does not seem to do anything, you may have to use .fire_event('onclick') instead or .click.
#browser.li(:id,/NetworkAnalysisTabPanel__ext-comp-/).link(:class, "x-tab-strip-menu").fire_event('onclick')
If that does not work, then you need to start experimenting with likely events that the control might be looking for (which will not necessarily show up in the HTML btw.. it may be in javascript or CSS etc)
UPDATE
This is where having an live example of the control that we can interact with is critical. doing some googling on the class names I was able to find one here and that let me play with it a little, and what I discovered is that it is looking for onmousedown. so, on that site, this works
browser.li(:id, 'TabPanel1__ctl07').link(:class, 'x-tab-strip-menu').fire_event('onmousedown')
Now since those ID's may not be the best identifier, a bit more digging (using .text on the li that holds the tab parts) found me some text, which in a menu like that ought to be unique.. SO, we can change this to make things a bit more robust and clearer as to what tab I'm clicking on (this will also be less subject to breaking if the tabs change around.
browser.li(:text, 'Menu 1').link(:class, 'x-tab-strip-menu').fire_event('onmousedown')
Lastly, since the click is causing client side code to execute, you may need a brief pause (a one or two second sleep) to wait for that portion of the page to re-render etc.

Watir : How do we capture the subitems displayed by doing mouseover on a particular item

I am trying to work with mouseover on a particular Item in my application by using the following command
{
ie.text_field(:xpath, "//a[contains(text(),'Deal')]").fire_event('onmouseover')
}
On doing mouseover on a item, two subitems are displayed.
Is there any way to capture the sub items which are part of the Item by doing mouseover with which we can report that our test is pass or fail.
Please suggest.
Additional Information :
If we take example,On the StackOver flow page, If i do mouseover on my name, i get a window where i see activity, privileges, Logout and other stuff. This is really what i was looking for. Is there a way to capture the items displayed on the window on doing mouseover.
I also tried to capture the subitems with the following :
{
text=ie.text_field(:xpath, "//a[contains(text(),'Deal')]").fire_event('onmouseover')
puts(text.inspect)
}
On doing this "text" value is displayed as 'nil'.
My general tactic for such things is a combination of using IRB and the IE Developer tool, or Firebug.
using IRB, type out (or cut and paste) the watir statement to fire the onmouseover command to the proper element on the page.
Then have the developer tool rescan the DOM (there's a little refresh icon you can click) The use the tool to point to an element to point to one of the items in the stuff exposed by the onmouseover. Using the info from that, you can then figure out how to address those elements to get the text from the proper div, etc.
If I do that here to the info that opens up when I float the mouse over my name I can find out that it is a table of class "profile-recent-summary" Furthermore I can then look at the way the table is made up and see for example that the 'today' reputation value is in the second cell on that row.. The row also has the text 'reputation' in it.. so
browser.table(:class, 'profile-recent-summary').row(:text, /reputation/).cell(:index, 2).flash
Should flash the cell I want (index might be 1 if using firewatir or webdriver) I can then replace the .flash with something else like .text if I want to get the text from that cell (which is actually inside a link that sits in the cell)..
without seeing your code, I would 'inspect' the element that you are trying to verify and when_present (text) assert that its true

how to get rid of text selection in wxwidget combobox component?

In my program I want the user to be able to choose between some options so I was using wxChoice component. Unfortunately after user interaction (clicking a button) I have to show custom text (not from my predefined list). Everything works fine if I use wxCombobox control but the drawback of this approach is that each time user selects an element from a list, selected text is highlited. It is annoying. I want the component to be read-only like. How to achieve this ?
Some code to visualize my question:
wxComboBox* viewAngle = wxDynamicCast( owner->FindWindow
( ID_CHOICE_3D_VIEWANGLE ), wxComboBox );
viewAngle->SetSelection( wxNOT_FOUND );
viewAngle->SetValue(_("Custom View"));
EDIT:
This control is used to set camera view in 3D object viewer application. Possible options are like: top, left, right, etc. It is also possible that the user moves 3D object using mouse. In that case I want my combobox to display "custom view" string. However "custom view" should not be a part of combobox list because selecting this option does nothing.
wxWidgets default implementation alwasy marks selected text. Which might be misleading for the user because he might think that he is expected to input any text.
IMHO, the custom text should be added to the wxComboBox control, the program could just ignore it when user selects that option.
Also, the wxComboBox's wxCB_READONLY style could be used to avoid the highlighting thing.

Resources