Spec - I want to replace the first presenter in a SpPanedLayout - smalltalk

Is that possible without needed to rebuild the whole presenter?
I am trying this code, but it does not work correctly:
self layout remove: (self layout children first).
self layout add: aNewPresenter.
It actually removes the presenter, but the new presenter is not placed at the first place but at the end.

In Spec2, all layouts are dynamic (meaning they can be modified at runtime), but each layout has different API and hence they need to be modified in different ways. In particular, SpPanedLayout has just two children: first and second (they can be displayed vertically -top to bottom- or horizontally -left to right-).
This means that unlike SpBoxLayout, in SpPanedLayout the use of #add: and #remove: messages are not necesary and will not always produce the desired result, and since #add: will try to add the presenter at the end of the list, in case it succeeds it will always be the second.
Instead, you can just set the children, and you will be effectively replace the presenter at the place you want.
Assuming you have the gtk backend installed, this code:
presenter := SpPresenter new.
presenter application: (SpApplication new useBackend: #Gtk).
presenter layout: (SpPanedLayout newHorizontal
first: (presenter newLabel label: 'I will replace this');
second: (presenter newLabel label: 'Powered by Pharo');
yourself).
presenter openWithSpec title: 'Example replace paned presenter'.
presenter layout
first: (presenter newImage image: (presenter application iconNamed: #pharoBig)).
Will replace the label "I will replace this" with the pharo logo in runtime.
And it will produce this output:

Related

I want JAWS to tell the user what kind of node they are in while navigating the dijit.Tree

We have a dijit.Tree that indicates a node type by using an icon. The icon is a unique indicator that tells the person this node is a "book" or a "DVD" or a "magazine" for example.
dijit renders the icon as a background image in CSS which we know screen readers do not see.
I tried overriding the getTooltip method to provide a tooltip saying "book" or "DVD". It successfully adds the "title" attribute to the "dijitTreeRow". If I mouse over the node, I see the text. This is not ever focused on when the user moves down to get from one node to the next.
When navigating the tree, the up and down arrows traverse the nodes. The span with the visible text is focused on and that string is read. You can see the dotted line focus as well as hear this with JAWS in the most basic of examples: https://dojotoolkit.org/reference-guide/1.10/dijit/Tree.html
What I have not been able to figure out is how to create an indicator that the screen reader will pick up on that will read "Book" alongside "The Great Gatsby".
Does anyone have any tips on how they made this dijit widget accessible for the screen reader when the images are an indicator that should be heard by the blind user?
The tree supports HTML labels, via setting the labelType property on the model you give it.
Assuming you don't want to change the store data (or override the getLabel method), you can reimplement dijit/Tree.getLabel and produce the HTML label, and wrap it with a span with an aria-label.
(code lifted from the dijit.Tree reference).
var myModel = new ObjectStoreModel({
store: myStore,
labelType: "html", // Hack to tell the tree node to render as HTML
query: {id: 'world'}
});
var tree = new Tree({
model: myModel,
getLabel: function(item) {
var label = this.model.getLabel(item);
// dojo.string
return dstring.substitute("<span aria-label='dvd ${0}'>${0}</span>", [label]);
}
});
If your data might contain HTML-ish characters that you don't want to render, escape the characters in getLabel too.

Change plain line to arrow line in infovis

How to change plain line to arrow line in infovis?
Currently there are some lines between blocks, I found some css files, but I cannot find which content describing the line behaviour such that I can change the plain line to arrow line.
Thanks.
Generally spoken: You can't (and shouldn't) change it via CSS. Define such properties during the setup.
Here's a brief explanation:
The Code that generates and Edge (which is a line in network visualizations) is generated by the Edge method/function which sits inside Options.Edge.js.
The function Edge is a property/module of the $jit object and works like this:
var viz = new $jit.Viz({
Edge: {
overridable: true,
type: 'line',
color: '#fff',
CanvasStyles: {
: '#ccc',
shadowBlur: 10
}
}
} );
It's important that you define overridable as true as you else can't override anything. The parameter that you're searching for is type. The allowed values are line, hyperline, arrow and I'm pretty sure that bezier will work as well - not sure if this is true for every type of graph. You can as well define custom graph Edge types - an example is missing in the documentation.
To change the Line/Edge style, there's another function that triggers before rendering. You just have to define it during the graph registration $jit.Viz( { /* add here */ } ); - code from the example/Spacetree here:
// This method is called right before plotting
// an edge. It's useful for changing an individual edge
// style properties before plotting it.
// Edge data proprties prefixed with a dollar sign will
// override the Edge global style properties.
onBeforePlotLine: function(adj){
if (adj.nodeFrom.selected && adj.nodeTo.selected) {
adj.data.$color = "#eed";
adj.data.$lineWidth = 3;
}
else {
delete adj.data.$color;
delete adj.data.$lineWidth;
}
}
The final step would now be to inspect what add.data can deliver and then either add the style you want or define a new one using a closure.
There might be another way to go on this: Example for a ForceDirected graph. Take a look at the documentation here.
$jit.ForceDirected.Plot.plotLine( adj, canvas, animating );
Maybe you could even use something like this:
var edge = viz.getEdge('Edge_ID');
edge.setData( property, value, type );
Disclaimer: I got no working copy of theJit/InfoViz library around, so I can't help more than that unless you add a JSFiddle example with your code.
Edit
As I just read that you only want to change to the default arrow type, just enter this type during the configuration of the graph.

extjs 4.1.0 how to get textfield values without using their id

I have one Textfield, Combo and a Radio. I want to get values of these 3 fields on clicking one button. How I can get the values of above 3 without using Ext.getCmp('id').getValue();
Is there any other method is their to get the values,
please let me know.
It depends on how you have contained your fields and the button you want to click to get their values.
You can navigate up and down your containers
var TheComponent = this.up('form').down('#MyTextField')
This climbs up your container hierarchy until it finds a 'form' container (doesn't matter what its Id or name is) and them climbs down until it finds a component with the id: 'MyTextField'
If your radio button is in a radio button group container you can retrieve an object that has all your 'on' key/values.
If your container is a form you can use the method proposed by lzhaki and retrieve an object that contains all the values on your form. Just remember that combo boxes behave differently to text boxes.
Each of these methods will return either a single value or an object containing a group of values.
In ExtJS 4.1, I found the prior example was close, but incorrect:
var TheComponent = this.up('form').down('#MyTextField')
There is no "down" method in the form object (apparently form fields aren't included in the down method's navigation logic).
Here's what worked for me to set initial focus on an edit field within a form.
var theForm = this.down('form').getForm();
var theField = theForm.findField('idEditVolname');
theField.focus();
You still must use getForm() to get the embedded form object, followed by findField() to locate the specific field - at least that's what works for me.
I don't know if this is still relevant, but here goes.
First of all, in Extjs4 and up, you use Ext.ComponentQuery.query() instead of Ext.getCmp().
What this allows you to do is access any xtype you have directly, just like the up, and down methods mentioned in other answers, but this method doesn't need any anchors as it searches the entire component hierarchy. Since you have only one of each element on the page that would be very easy to achieve without using id's.
I would name the main panel that contains the fields, but that's just for convenience.
Look at this fiddle
The code is really simple:
var panel = Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
name: 'myForm',
title: 'Sample Test',
layout: 'anchor',
height: 200,
items: [{
xtype:'textfield',
fieldLabel: 'text',
value: 'Oh yeah!'
}]
});
var myVal = Ext.ComponentQuery.query('panel[name=myForm] textfield')[0];
alert (myVal.getValue());
The same can be done with the radio and combo fields, and you don't need a form for that, though it is more logical that way.

Sencha Touch: Removing an item then updating view on orientation change etc

thanks for the reply, looks like we might be getting somewhere. I have created a new view thats plain and in a simple form. See below:
var homePanelTop = new Ext.Panel({ id:'topCont',
cls:'topCont'
});
var homePanelBtm = new Ext.Panel({
id:'btmCont',
cls:'btmCont'
});
App.views.HomeIndex = Ext.extend(Ext.Panel, {
id:'mainlayout',
fullscreen : true,
layout: {
type: 'vbox',
align: 'stretch',
},
defaults:{flex:1},
items: [homePanelTop, homePanelBtm],
suspendLayout: true,
monitorOrientation: true,
orientationchange: this.onOrientationChange,
onOrientationChange: function(orientation, w, h){
this.suspendLayout = false;
if(orientation === 'portrait'){
console.log('P: ' + orientation);
this.add(homePanelTop, true);
} else {
console.log('L: ' + orientation);
this.remove(homePanelTop, false);
}
this.doLayout();
}
});
Ext.reg('HomeIndex', App.views.HomeIndex);
What i expect to see with the above view is on first load and portrait, there will be two panels, the top panel(yellow) and a bottom panel (blue). When I rotate as normal I still get the same effect.
But what I am after is that when I rotate to landscape the top panel (yellow) is removed and the bottom panel (blue) fills the rest of the space.
Then when I rotate back to portrait I get both panels back at their design sizes (flex:1)
Whats happening using the code above (testing in chrome) is that the top panel (yellow) remains at the top but slightly smaller in height and does not disappear like it should
Anyway notice the two console trace commands I have and these are showing the following readings on rotation:
After first load, I then rotate to landscape and the output is:
L: landscape
L: landscape
Attempted to remove a component that does not exist. Ext.Container: remove takes an argument of the component to remove. cmp.remove() is incorrect usage.
L: landscape
Attempted to remove a component that does not exist. Ext.Container: remove takes an argument of the component to remove. cmp.remove() is incorrect usage.
L: landscape
Attempted to remove a component that does not exist. Ext.Container: remove takes an argument of the component to remove. cmp.remove() is incorrect usage.
The when I rotate back to portrait I get the following output:
L: landscape
Attempted to remove a component that does not exist. Ext.Container: remove takes an argument of the component to remove. cmp.remove() is incorrect usage.
L: landscape
Attempted to remove a component that does not exist. Ext.Container: remove takes an argument
of the component to remove. cmp.remove() is incorrect usage.
P: portrait
P: portrait
So looking at this on the lanscape rotation it actually some how fires the onorientationchange function 4 times, the first one is ok the other three with an error as the first one already removed it so thats what the warnings are for I believe.
Then with the portrait ones I get two registering as lanscape calls then two hits registering portrait calls.
All this with one movement, so is this somehow causing the remove and add code's not to work as predicted and how to prevent the orientation being called four times on rotation??
If anyone has an idea on the development of this feel free to join in.
Thanks for the help so far
Si
Many years later... and more for someone like me that stumbles on to this looking for help.
Two things.
1) The message "Attempted to remove a component that does not exist" is found only in the "development" version of the ExtJS library and I don't know that it is a reliable indicator of a problem.
2) If you can upgrade to ExtJS 4.1x. It will give you access to better debugging tools. I am thinking specifically of the 'Ext JS Page Analyzer'. This will help you see what the layout engine is doing as apposed to what you hope it is doing.
See: http://www.sencha.com/blog/optimizing-ext-js-4-1-based-applications

Check if Dojo's content pane is available or not

I have a requirement where I need to create a dojox.layout.ContentPane programmatically.
function constructContentPane(methodToBeCalled){
var testCntPane=new dojox.layout.ContentPane({
href: "some url",
executeScripts: true,
cleanContent: true,
onDownloadEnd: methodToBeCalled
}).placeAt("testContentPaneId");
testCntPane.startup();
}
This places the content pane inside testContentPaneId and calls methodToBeCalled method once the content pane is created.
I have two questions.
How do I check if the content pane is already created or not? I tried to check using the code below
if(dijit.byId("testContentPaneId") == undefined) {
//then don't create again
}
But this did not work. Each time it creates the content pane with the id dojox_layout_ContentPane_0. The last digit gets incremented each time.
Is this the right way to pass the onComplete method as argument? This is how I invoke this
constructContentPane(thisMethodWillBeCalled);
Is there any better way to do this? How do I invoke that method? I tried using eval(methodToBeCalled), but that did not work.
When you use the placeAt() method then the widget will be placed as a child to the specified dom node. I think in your case you should pass the dom directly to the constructor of the content pane.
Try doing like this instead:
var testCntPane=new dojox.layout.ContentPane({
href:"some url",
executeScripts:true,
cleanContent:true,
onDownloadEnd:methodToBeCalled
}, "testContentPaneId");
This will also make sure that the id of the content pane is testContentPaneId