MiServer: navigating with jsTree
5 posts
• Page 1 of 1
MiServer: navigating with jsTree
I have navigation working from a jsTree using the following JS, which I'm trying to replicate using the Dyalog plugin classes:
Seems to me in MiServerthat's:
But I don't seem to be getting reactions to the select_node.jstree events.
If I omit the delegate 'li' I get an event and APLJax fires, but the id returned is #navtree, not the individual list item.
Anyone been here before me?
- Code: Select all
$(document).ready(function () {
$("#navtree").jstree(
{"plugins" : [ "themes", "html_data", "ui", "cookies" ]}
).on("select_node.jstree", function (event, data) {
$.post("",
{
what: data.rslt.obj.attr("id")
},
function(data,status) {
$("#browser").html(status==='success'?data:'<p class="error">Server error</p>');
});
})
;
});
Seems to me in MiServerthat's:
- Code: Select all
plugins←'"plugins" : [ "themes", "html_data", "ui", "cookies" ]'
html,←req #.JQO.jsTree 'navtree' levels Items plugins
html,←req #.JQ.On ('#navtree' 'li') 'select_node.jstree' ('attr' 'id') '#browser'
But I don't seem to be getting reactions to the select_node.jstree events.
If I omit the delegate 'li' I get an event and APLJax fires, but the id returned is #navtree, not the individual list item.
Anyone been here before me?
-
StephenTaylor - Posts: 31
- Joined: Thu May 28, 2009 8:20 am
Re: MiServer: navigating with jsTree
It's nice to see people making use of some of MiServer's jQuery-based widget interfaces.
As it turns out, jsTree binds the listener for the select_node.jstree event at the tree level, not the node level.
That's why using the 'li' delegate in the JQ.On selector parameter wasn't firing.
One common jQuery event handling convention is to pass data to the handler using the event object and that's what JQ.On was coded to expect.
After a bit of investigation, I found that jsTree uses a separate data object that JQ.On wasn't picking up.
http://old.jstree.com/documentation/core describes the data object...
I've updated the MiServer zip file at http://tools.dyalog.com/library/ with this change.
Here's a page that demonstrates how to access the node level id attribute when a node is clicked.
JQ.On's third parameter specifies any additional data you want to be sent to the server when the event is triggered.
On the server side, we just display this to the APL session (you'd probably want to do something more useful :))
I found there's a newer version of jsTree (v3.0) that passes data a bit differently.
The example above uses version 1.0 which is currently distributed with MiServer.
When MiServer 3.0 is released later this year, we will probably use the latest version jsTree.
As it turns out, jsTree binds the listener for the select_node.jstree event at the tree level, not the node level.
That's why using the 'li' delegate in the JQ.On selector parameter wasn't firing.
One common jQuery event handling convention is to pass data to the handler using the event object and that's what JQ.On was coded to expect.
After a bit of investigation, I found that jsTree uses a separate data object that JQ.On wasn't picking up.
http://old.jstree.com/documentation/core describes the data object...
- {
"inst" : /* the actual tree instance */,
"args" : /* arguments passed to the function */,
"rslt" : /* any data the function passed to the event */,
"rlbk" : /* an optional rollback object - it is not always present */
}
I've updated the MiServer zip file at http://tools.dyalog.com/library/ with this change.
Here's a page that demonstrates how to access the node level id attribute when a node is clicked.
- Code: Select all
:Class tree : MiPage
:field public event
:field public what
:field public clicked←''
:include #.HTMLInput
∇ r←Render req;levels;items
:Access public
levels←1 2 3 3 3 2 3 3 2 3
items←levels{⍕'Item'⍵'Level'⍺}¨⍳⍴levels
r←req #.JQO.jsTree'mytree'levels items'"plugins" : [ "themes", "html_data", "ui", "cookies" ]'
r,←req #.JQ.On'#mytree' 'select_node.jstree'('clicked' 'eval' 'data.rslt.obj.attr("id")')
∇
∇ r←APLJax req
:Access public
r←''
⎕←clicked
∇
:EndClass
JQ.On's third parameter specifies any additional data you want to be sent to the server when the event is triggered.
('clicked' 'eval' 'data.rslt.obj.attr("id")')sends an object named "clicked" which contains the id attribute of the node that was clicked.
On the server side, we just display this to the APL session (you'd probably want to do something more useful :))
I found there's a newer version of jsTree (v3.0) that passes data a bit differently.
The example above uses version 1.0 which is currently distributed with MiServer.
When MiServer 3.0 is released later this year, we will probably use the latest version jsTree.
-
Brian|Dyalog - Posts: 120
- Joined: Thu Nov 26, 2009 4:02 pm
- Location: West Henrietta, NY
Re: MiServer: navigating with jsTree
Brian, thanks -- most helpful.
Moving on, I've modified my original design. That was to handle the app from a single MiPage, divided into #navtree and #panel. Navigating with the jsTree would (via APLJax) present the corresponding app module in #panel. But that loads a lot of code into the Index class. And it precludes navigating the app by URL, which is too useful to give up. So I will follow the Intro design and write a class for each module.
That means promoting the jsTree into the skin. And that introduces an issue with binding to JavaScript that is opaque to me. Here's a simple way to see it. Three steps.
(1) I've made my own skin SvPage. It wraps req.Response.HTML as #panel and catenates it to #navtree, in which it has composed the jsTree example from the MiServer Intro site. Thus:
In the page class compose another jsTree. (I know. Stay with me here.)
Result is two jsTrees, one in #navtree, the other (#tree) is in #panel. All is well.
(2) Replace the jsTree in Index with a P:
Now the #panel display is the simple para, but the jsTree in #navtree has become a simple UL. No script bound to it. Yuk.
(3) Lastly, remove the lamp in the Index script. The #panel display remains the same, but the JS binding to the jsTree in #navtree has been restored. Clearly the JS binding works in the page script but not in the skin script.
This is puzzling. The req left argument to #.JQO.jsTree is a pointer, so you'd think this would work in either context. I can't see in the source (in #.JQO and #.JQ) an explicit binding to context. And I haven't figured out how to trace into MiServer's execution. (Too long away from Dyalog no doubt. Perhaps someone at BAA London tomorrow will show me.)
For the record, the JS I mean to emulate for #navtree is at
http://www.linuxia.de/blog/jsTree-Navigation-Delegate-Links
Stephen
Moving on, I've modified my original design. That was to handle the app from a single MiPage, divided into #navtree and #panel. Navigating with the jsTree would (via APLJax) present the corresponding app module in #panel. But that loads a lot of code into the Index class. And it precludes navigating the app by URL, which is too useful to give up. So I will follow the Intro design and write a class for each module.
That means promoting the jsTree into the skin. And that introduces an issue with binding to JavaScript that is opaque to me. Here's a simple way to see it. Three steps.
(1) I've made my own skin SvPage. It wraps req.Response.HTML as #panel and catenates it to #navtree, in which it has composed the jsTree example from the MiServer Intro site. Thus:
___
:Class SvPage : MildPage
...
∇ Wrap req;body;head;html;footer;banner;content;lang;levels;items
⍝ "Wraps" the HTML body
...
levels←1 2 2 1
items←'item'∘,¨⍕¨⍳⍴levels
content,←req #.JQO.jsTree 'navtree' levels items
content,←'div id="panel"'Enclose req.Response.HTML
content←'div id="contentblock"'Enclose content
...
∇
...
:EndClass
In the page class compose another jsTree. (I know. Stay with me here.)
___
:Class Index : SvPage
:Include #.HTMLInput
∇ Render req
:Access Public
levels←1 2 2 1
items←'item'∘,¨⍕¨⍳⍴levels
req.Return req #.JQO.jsTree 'tree' levels items
∇
...
:EndClass
Result is two jsTrees, one in #navtree, the other (#tree) is in #panel. All is well.
(2) Replace the jsTree in Index with a P:
___
:Class Index : SvPage
:Include #.HTMLInput
∇ Render req
:Access Public
levels←1 2 2 1
items←'item'∘,¨⍕¨⍳⍴levels
⍝ req.Return req #.JQO.jsTree 'tree' levels items
req.Return 'p' Enclose 'Hello folks!'
∇
...
:EndClass
Now the #panel display is the simple para, but the jsTree in #navtree has become a simple UL. No script bound to it. Yuk.
(3) Lastly, remove the lamp in the Index script. The #panel display remains the same, but the JS binding to the jsTree in #navtree has been restored. Clearly the JS binding works in the page script but not in the skin script.
This is puzzling. The req left argument to #.JQO.jsTree is a pointer, so you'd think this would work in either context. I can't see in the source (in #.JQO and #.JQ) an explicit binding to context. And I haven't figured out how to trace into MiServer's execution. (Too long away from Dyalog no doubt. Perhaps someone at BAA London tomorrow will show me.)
For the record, the JS I mean to emulate for #navtree is at
http://www.linuxia.de/blog/jsTree-Navigation-Delegate-Links
Stephen
-
StephenTaylor - Posts: 31
- Joined: Thu May 28, 2009 8:20 am
Re: MiServer: navigating with jsTree
Hi Stephen!
When you pass req as the left argument to #.JQO.jsTree, it adds the necessary JavaScript links to req.Response.HTMLHead.
You didn't show all the code for your Wrap function, but I suspect it has already constructed the <head> element (with code something like 'head' Enclose req.Response.HTMLHead) and the the call to build navtree is later in the code, so the links aren't appearing in the <head> element.
There are a couple of ways to fix this:
I hope this helps!
/Brian
When you pass req as the left argument to #.JQO.jsTree, it adds the necessary JavaScript links to req.Response.HTMLHead.
You didn't show all the code for your Wrap function, but I suspect it has already constructed the <head> element (with code something like 'head' Enclose req.Response.HTMLHead) and the the call to build navtree is later in the code, so the links aren't appearing in the <head> element.
There are a couple of ways to fix this:
- Add
req.Use 'jquery.jstree'
to the top of the Wrap function - OR Move the block of code where you construct the content above the call that constructs the <head> element.
I hope this helps!
/Brian
-
Brian|Dyalog - Posts: 120
- Joined: Thu Nov 26, 2009 4:02 pm
- Location: West Henrietta, NY
Re: MiServer: navigating with jsTree
Thanks Brian, helpful and relevant again.
This thread now entangles the discussion of MiServer tools at BAA London last Friday.
I have customised the #navtree node icons to aid navigation:
There are (at least) four ways to do this in jsTree:
So far, so good. What's the source look like?
SvPage.Wrap has slight mods to MiPage.Wrap:
Notice I'm not using #.JQO.jsTree, but instead my own navtree.js:
Two reasons.
First, in this instance, I don't need the AJAX. Each node will either toggle or GET. Coaxing the JQO tree to stop making AJAX calls looked at least as much work as writing the required JS, which, as usual, only meant adapting someone else's.
Second, the only way I could see to customise the JQO tree's icons was to write JS to change them.
Thanks for bearing with me this far. My point (at last) is:
JQO.jsTree is sweet to use and it's clear what it does for you. If that's what you need you can just CPE: copy, paste, execute. But if you need more you have to dive in to both JS and JStree, and then you start from scratch, because nothing in JQO.jsTree relates to the docn and concepts there.
As a general principle, I'd try to design the syntax of APL wrappers to expose and clarify the encapsulated complexity. And, brutally, when Joe APLer is doing CPE, it doesn't matter whether the code looks APL-ish or not.
Best
Stephen
This thread now entangles the discussion of MiServer tools at BAA London last Friday.
I have customised the #navtree node icons to aid navigation:
There are (at least) four ways to do this in jsTree:
- load the tree with JSON with icons assigned
- load the tree with HTML with icons assigned in JSON
- load the tree with HTML with icons assigned as CSS classes
- write JS functions
So far, so good. What's the source look like?
SvPage.Wrap has slight mods to MiPage.Wrap:
∇ Wrap req;body;head;html;footer;banner;content;lang;html
⍝ "Wraps" the HTML body
⍝ This version implements a template to create a standard look and feel for all MildPages served by this site
⍝ This is provided as an example for some of the uses of Wrap
:Access Public
req.Use'JQuery'
req.Use'jquery.jstree'
head←'title'Enclose req.Server.Config.Name ⍝ Sets the name of the page at the top of the browser to the Name specified in server.xml
head,←Tag'meta http-equiv="content-type" content="text/html;charset=UTF-8"' ⍝ make it UTF-8
head,←Tag'link href="/Styles/style.css" rel="stylesheet" type="text/css"' ⍝ add the style sheet reference
⍝↓↓↓ If your code that builds the page updates HTMLHead (content that goes in the <head> element of the HTML document) it gets appended here.
⍝ This means that any style changes introduced by your code will override those in the /Styles/style.css for elements defined by both stylesheets
head,←req.Response.HTMLHead,CRLF ⍝ Adds additional html head information
head←'head'Enclose head
⍝ The design for this template implements a structure for the content within the body of the HMTL file
⍝ The <body> element encloses three <div> elements containing: a banner, the content, a footer
banner←#.Files.GetText req.Server.Root,'Styles\banner.txt'
html←''
html←#.Files.GetText #.Boot.AppRoot,'Data\navtree.html' ⍝ FIXME dynamic
html,←JS #.Files.GetText #.Boot.AppRoot,'Scripts\navtree.js'
content←'div id="contentblock"'Enclose html, 'div id="panel"' Enclose req.Response.HTML
...
Notice I'm not using #.JQO.jsTree, but instead my own navtree.js:
//
// http://www.linuxia.de/blog/jsTree-Navig ... gate-Links
$(function () {
$("#navtree").jstree({
"plugins" : [ "cookies","html_data","themes","ui" ],
"themes" : { "theme" : "classic" }
});
$("#navtree").delegate("a", "click", function (e) {
if ($("#navtree").jstree("is_leaf", this)) {
document.location.href = this;
} else {
$("#navtree").jstree("toggle_node", this);
}
});
});
Two reasons.
First, in this instance, I don't need the AJAX. Each node will either toggle or GET. Coaxing the JQO tree to stop making AJAX calls looked at least as much work as writing the required JS, which, as usual, only meant adapting someone else's.
Second, the only way I could see to customise the JQO tree's icons was to write JS to change them.
Thanks for bearing with me this far. My point (at last) is:
- I couldn't get this done without grappling with JS
- When I had to do so, that sweet little JQO tree did nothing to help me on my way
JQO.jsTree is sweet to use and it's clear what it does for you. If that's what you need you can just CPE: copy, paste, execute. But if you need more you have to dive in to both JS and JStree, and then you start from scratch, because nothing in JQO.jsTree relates to the docn and concepts there.
As a general principle, I'd try to design the syntax of APL wrappers to expose and clarify the encapsulated complexity. And, brutally, when Joe APLer is doing CPE, it doesn't matter whether the code looks APL-ish or not.
Best
Stephen
-
StephenTaylor - Posts: 31
- Joined: Thu May 28, 2009 8:20 am
5 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 1 guest
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group