Adding a header to MultiColumnListModel - user-interface

I am working with Spec library in Pharo 3 and I have found no way to add a header to a multi column list. However, adding headers is feasible through TreeColumnModel and TreeModel like this:
| m col1 col2 |
m := TreeModel new.
m roots: #(#a #b #c #d).
m rootNodeHolder: [ :item |
TreeNodeModel new
content: item;
icon: Smalltalk ui icons smallConfigurationIcon ].
m openWithSpec.
col1 := TreeColumnModel new
displayBlock: [ :node | node content asString ];
headerLabel: 'Character'.
col2 := TreeColumnModel new
displayBlock: [ :node | (Character value: node content asString first asciiValue + 1) asString ];
headerLabel: 'Character +1';
headerIcon: Smalltalk ui icons smallBackIcon.
m
columns: {col1. col2};
acceptDropBlock: [ :transfer :event :source :receiver | self halt ].
col2
headerLabel: 'Character +2';
headerIcon: Smalltalk ui icons smallBackIcon;
displayBlock: [ :node | (Character value: node content asString first asciiValue + 2) asString ].
m rootNodeHolder: [ :item |
TreeNodeModel new
content: (Character value: (item asString first asciiValue + 5)) asSymbol;
icon: Smalltalk ui icons smallFullscreenIcon ].
How could I get a header in the following MultiColumnListModel?
MultiColumnListModel new
items: {$a. $b. $c. $d. $f.};
displayBlock: [:e | {e asString. e isVowel asString} ];
openWithSpec.

Will this work for you?
model := MultiColumnListModel new
items: { {'Letter'. 'isVowel'.}. $a. $b. $c. $d. $f.};
displayBlock: [:e |
e isArray
ifTrue:[{e first asString. e last asString} ]
ifFalse:[
{e asString. e isVowel asString} ]].
model
whenSelectionChanged:[
model getIndex = 1 ifTrue:[
model setIndex:0].
];
openWithSpec.

Related

How to Replace Substring in all Elements of Object without Destroying it

I need to replace substrings of all elements in an object.
E.g. replace all 'X' in val1 and val2:
{
"input": [
{
"val1": "008 X 148",
"val2": "SOME X DATA"
},
{
"val1": "X 005 5PM",
"val2": "SOME X DATA"
},
{
"val1": "MODTOX",
"val2": "X SOME X DATA"
}
]
}
My first intention was to use $map and then $each, like this:
$map(input, function($i)
{ $each($i, function($s)
{ $replace($s, "X", "Y" )
})
})
, but as expected, this destroys the object.
Any suggestion? Finally 'input' should still be of same structure.
You need to use the transform operator to modify a copy of the input data:
$ ~> | input | $each(function($v, $n){{$n: $replace($v, "X", "Y") }} ) ~> $merge() |
See https://try.jsonata.org/yeKAKg_U_

Replace an image with Ajax on seaside

I have been working on Seaside 3.1 for a couple of days and I'm trying to design a simple TicTacToe with Ajax.
It works great without ajax with this code:
renderContentOn: html
html heading: 'Tictactoe'.
html
form: [
1 to: 3 do: [ :row |
1 to: 3 do: [ :col |
html imageButton
url: (tictactoe imageCase: row * 10 + col);
callback: [ tictactoe playsX: row playsY: col ] ].
html break ] ]
and with ajax it doesn't work at all, though the page doesn't refresh as expected. The imageButton never changes for a simple image with another url.
The goal is just to swap the imageButton for an image with another url when I click on it.
Here's where I am with my code:
renderContentOn: html
html heading: 'Tictactoe'.
1 to: 3 do: [ :row |
1 to: 3 do: [ :col |
html imageButton
url: (tictactoe imageCase: row * 10 + col);
id: 'case' , row asString , col asString;
onClick:
(html scriptaculous updater
id: 'case' , row asString , col asString;
callback: [ :r |
tictactoe playsX: row playsY: col.
r render: (html image url: (tictactoe imageCase: row * 10 + col)) ];
return: false) ].
html break ]
I am new and not very good with this technology, therefore I am ready to hear any answer, advice or guidance.
I would like to thank you in advance, have a good day.
My first suggestion would be to drop Scriptaculous and use JQuery instead, the former isn't developed anymore while JQuery is maintained daily and is supported by Seaside as well.
renderContentOn: html
html heading: 'Tictactoe'.
1 to: 3 do: [ :row |
1 to: 3 do: [ :col |
html imageButton
id: 'case' , row asString , col asString;
url: (tictactoe imageCase: row * 10 + col);
onClick:
(html jQuery ajax
callback: [ tictactoe playsX: row playsY: col ];
script: [ :s |
s
<<
((html jQuery id: 'case' , row asString , col asString)
replaceWith: [ :h |
h image url: (tictactoe imageCase: row * 10 + col) ]) ])].
html break ]
The key is in the onClick: handler, where you pass a JQuery Ajax object that executes a callback on the server and then returns a script (JS) whose content have the instructions to replace an element with certain id (an imageButton with id 'case' , row asString , col asString) by what is rendered by the replaceWith: render block..
You can even go a little further and merge both the callback: and script: into a single call as follows:
onClick:
(html jQuery ajax
script: [ :s |
tictactoe playsX: row playsY: col.
s << ((html jQuery id: 'case' , row asString , col asString)
replaceWith: [ :h |
h image url: (tictactoe imageCase: row * 10 + col) ]) ])].

Number of string value occurrences for distinct another column value

I have a model Counter which returns the following records:
name.....flowers.....counter
vino.....rose.........1
vino.....lily.........1
gaya.....rose.........1
rosi.....lily.........1
vino.....lily.........1
rosi.....rose.........1
rosi.....rose.........1
I want to display in the table like:
name | Rose | Lily |
---------------------
Vino | 1 | 2 |
---------------------
Gaya | 1 | 0 |
---------------------
Rosi | 2 | 1 |
I want to display the count of flowers for each distinct name. I have tried the following and wondering how can I do it elegantly?
def counter_results
#counter_results= {}
Counter.each do |name|
rose = Counter.where(flower: 'rose').count
lily= Counter.where(flower: 'lily').count
#counter_results['name'] = name
#counter_results['rose_count'] = rose
#counter_results['lily_count'] = lily
end
return #counter_results
end
which I don't get the hash values.
This will give you slightly different output, but I think it is probably closer to what you want than what you showed.
You can use the query:
Counter.group([:name, :flowers]).sum(:counter)
To get a result set that looks like:
{ ["vino", "rose"] => 1, ["vino", "lily"] => 2, ["gaya", "rose"] => 1, ["gaya", "lily"] => 0, ... }
And you can do something like this to generate your hash:
def counter_results
#counter_results = {}
Counter.group([:name, :flowers]).sum(:counter).each do |k, v|
#counter_results[k.join("_")] = v
end
#counter_results
end
The resulting hash would look like this:
{
"vino_rose" => 1,
"vino_lily" => 2,
"gaya_rose" => 1,
"gaya_lily" => 0,
...
}
Somebody else may have a better way to do it, but seems like that should get you pretty close.

Building a tree/outliner like graphical interface in Pharo/Smalltalk using Moose Glamorous Toolkit

I'm trying to build a tree/outliner like graphical interface in Pharo/Smalltalk using Moose Glamorous Toolkit. So, far I have got this mockup:
Outliner mockup http://www.enlightenment.org/ss/e-53e3dee6777744.68598023.jpg
For that I'm using the following code:
| browser mainTree |
mainTree := UbakyeNode new.
mainTree becomeDefaultTree.
browser := GLMTabulator new.
browser
column: #tree;
column: [ :c |
c
row: #body;
row: #plugins ].
(browser transmit)
to: #tree;
andShow: [ :a |
(a tree)
title: mainTree header;
children: [ :eachNode |
eachNode children. ] "Children must return a collection" ].
(browser transmit)
to: #body;
from: #tree;
andShow: [ :a | a text title: 'Cuerpo | Body ' ].
(browser transmit)
to: #plugins;
from: #tree port: #selectionPath;
andShow: [ :a | a text title: 'Plugins | Extensiones' ].
browser openOn: mainTree children.
So I have now a browser which shows a tree made of UbakyeNodes (a tree like data structure I defined), but I would like not to show the Ubakye Nodes, but the titles of each node (headers) and the contents (bodies) of them when selected. With the help of the Pharo/Moose community I have understood that I need to pass the collection of all children (not just the headers of them), but I don't know who to sellect something particular in that collection to be shown on the browser, like headers of nodes in the #tree panel or bodies in the #body panel.
I would like to change also the size of each panel to be more like the shown in the screenshot, instead of the default one and be relative to window size. Is this possible?
Ok, thanks to Peter Kenny in the Pharo-users Community mailing list, now I have the answer. The issue is related with the "format:" keyword message, which was missing. Using it, is possible to tell Moose/Pharo how to display information taken from the children. Here is the modified working code:
| browser mainTree |
mainTree := UbakyeNode new.
mainTree becomeDefaultTree.
browser := GLMTabulator new.
browser
column: #tree;
column: [ :c |
c
row: #body;
row: #plugins ].
(browser transmit)
to: #tree;
andShow: [ :a |
(a tree)
title: mainTree header;
children: [ :eachNode |
(eachNode children) isNil
ifTrue: [ #() ]
ifFalse:[ eachNode children ] ];
format:[:eachNode |
(eachNode header) isNil
ifTrue: [ '' ]
ifFalse: [ eachNode header ] ].
"Children must return a collection" ].
(browser transmit)
to: #body;
from: #tree;
andShow: [ :a |
(a text)
title: 'Cuerpo | Body ';
format:[:eachNode |
(eachNode body) isNil
ifTrue: [ '' ]
ifFalse: [ eachNode body ] ]
].
(browser transmit)
to: #plugins;
andShow: [ :a | a text title: 'Plugins | Extensiones' ].
browser openOn: mainTree children.
And setting the relative width and height you do by using
row: #result span: 2;
for the row/column that should be twice as wide. So something like
browser
column: #tree;
column: [ :c |
c row: #body span: 3;
row: #plugins ] span: 3.

SQL Query for Updating Rows with New Values from Temporary Table in Laravel/Eloquent

I wish to update table B based on source table A so that if a new record is found, we can insert it otherwise update the record if any values have changed. How would I write the query in laravel 4 using eloquent?
Table A Table B
======= =======
Name | Color Name | Color
---------------------- ----------------------
Mickey Mouse | grey Mickey Mouse | red
Donald Duck2 | green Donald Duck | blue
Donald Duck | blue Minnie | red
Goofy | black
Minnie | red
In this example table B should be inserted with the rows Goofy and Donald Duck2 and the row mickey mouse should be updated with the new color grey.
This should work:
$a = A::all();
foreach($a as $current)
{
$b = B::where("name", "=", $current->name)->first();
if(!$b) $b = new B;
if($b->name != $current->name)
{
$b->name = $current->name;
$b->save();
}
}
Or more optimized:
$a = A::all();
// using this script: http://stackoverflow.com/questions/12050892/array-mapping-in-php-w ith-keys
$aFolded = array_reduce($a, function(&$result, $item){
$result[$item->name] = $item->color;
return $result;
}, array());
// so we now have array ( name => color, name2 => color2 )
$b = B::with("a", "name")->get(); // might recheck with laravel doc
foreach($b as $updateMe)
{
if($updateMe->color != $aFolded[$b->name])
{
$updateMe->color = $aFolded[$b->name];
$updateMe->save();
unset($aFolded[$b->name]);
}
}
// after this $aFolded will only contain the names which do not exist in b so we can just insert them all (maybe the insert query could be better)
foreach($aFolded as $name => $color)
{
DB::table("B")->insert(array("name" => $name, "color" => $color));
}

Resources