I recently had to search for a mail delivered to Gmail according to the mail server log, but I couldn't find it immediately.
As I wanted to search the message based on its Message-Id found in the mail server logs, I found this help page. After clicking several checkboxes, it display a form that lets you search your inbox based on the Message-Id. However, looking at the search query generated, it's very simple to do it right from your inbox. Just type this in the search box, replacing $my_message_id by the actual value you're looking for
YUI2's Datatable is a great widget I use in MyOwnDB and here's a small tip for when you use it to load a remote data source .
In that case, the datatable is getting the data to display from a YUI2 DataSource that has been configured with the URL to use when fetching the data requested by the datatable.
When instanciating the datatable, you can pass it a configuration object, with amongst other option, the initialRequest that should be sent by the associated datasource when the datatable is displayed for the first time. initialRequest is a string that is simply appended to the URL passed to the DataSource.
So if your datasource URL is "http://www.myurl.com?all=true", and your initialRequest is "sort=name", the request sent by the DataSource will be for the URL "http://www.myurl.com?all=truesort=name", which is clearly not good.
The solution here is to either be sure that the datasource URL ends with a ? or a &, or to always start the initialRequest with &.
The second option is the easiest in my case.
In MyOwnDB , there's an CrosstabObject inheriting from ActiveRecord, but that doesn't correspond to any table in the database (actually, it is configured to map to a table in the database as this is mandated by AR, but it's never used like that). It is only used to select data with find_by_sql.
Now, some columns of the data returned by the query can be data that has been serialized to YAML, but each query has its own set of serialized columns.
I first tried to call the serialize method provided by rails, but it didn't work. I suspect the ActiveRecord model needs the column to exist when it is initialized for the serialization to be activated, which is not the case here as the CrosstabObject is mapped to an object that doesn't have the columns returned by the sql query.
In this example, the query returns a result set which has the test_attach column serialized to YAML. test_attach is not a column of the table to which CrosstabObject was mapped. As you can see, the serialization is configured, but has no effect on the returned data:
If I redefine the test_attach accessor on list[6] 's singleton class, I get the expected result though:
As each query has its own set of serialized columns, what I want to do is just pass the list of columns that contain serialized data, so that the accessors get defined, which is easily done by adding a method to CrosstabObject:
which enables me to easily configure the columns returned by the sql query that are serialized:
As I'm working on the new interface of MyOwnDB based on YUI, I have discovered 2 subtle differences between IE and FF when creating nodes with YUI 3.
1. You can't change attribute values of INPUT nodes created from a template using the long closing node syntax
Update: IE is actually doing the right thing, as the input tag does not accept a closing tag as defined by the W3C .
By long syntax, I mean closing a tag with an explicit closing tag:
as opposed to the short syntax:
If you create an input node with YUI3 based on the long syntax with IE, you won't be able to set attribute values:
The solution is to use the short syntax to close your tag:
Note that this is only for input nodes. Divs are workling fine with the long syntax:
2. With IE, you can't set the type of an input node to "file"
This code will generate a file field with FF, but a text field with IE:
If you want to make it work with IE, you have to make your template include the type attribute:
I've put a demo page for those interesting in the code, with a YUI console.
J'ai le plaisir de donner une présentation ce soir au Café Numérique dédié à l'Open Source, comme annoncé également sur le site d'actualité Open Source de Profoss . Le sujet de la présentation est l'Open Source où ne l'attend pas, et montre combien le Libre et l'Open Source se sont propagé ces 10 dernières années. Pratiquement plus aucun domaine n'échappe à son influence. Parfois même sans qu'on s'en rende compte!
Voici mes slides au format PDF:
Logiciels Libres Inaperçus
Bonne découverte!
ALL YUI 3 code on a page is placed in its own sandbox. This allows several parts of a page to be completely independent, with benefits in maintainability and stability: one sandbox cannot have any effect on another sandbox on the page, and a sandbox only uses the modules it needs. These sandboxes are create with YUI.use :
If you have a function based on YUI that you are going to reuse often, as I had with transitioning MyOwnDB to YUI 3, the best solution is to define it in a module that you'll use in each sandbox that needs it. Defining a module is done with YUI.add which also lets you specify which other modules it depends on. The body of the module is simply adding a namespage to YUI, which will hold all my code, defining the function and putting it under the namespace just created, like this:
Now I can simply use my new module and its associated function in any sandbox I define:
Thanks to Satake and Daniel Cook on the YUI Forum for their advice .
The other day, I read the blog post Agents of Swing by Stuart Sierra describing the use of agents in combination with a Swing UI. As soon as I read it I wanted to implement it with Jwt in the hope it would be easy. And I wasn't disappointed!
As I had expected, I was able to reuse the agents code from Stuart and integrate it very easily in my web app. Actually, the development op the web interface was similar to the development of the swing interface. It's so similar I can only paste it here without further explanations:
; Create the Timer that will update results on the page ; by calling the function passed (defn create-timer [wapp fn-update-results] (let [timer (WTimer.)] (.setInterval timer 1000) (.. timer timeout (addListener wapp (create-listener [event] (fn-update-results)))) timer)) (defn make-flipper-app [env] (let [wapp (new WApplication env) root (.getRoot wapp) result-text (WText. "") flipper (new-flipper) fn-update-results (fn [] (.setText result-text ( str "error: " (error @flipper) " after " (:total @flipper) " flips, of which " (:heads @flipper) " where heads" ))) timer (create-timer wapp fn-update-results) ] (.setTitle wapp "Agents of Jwt") (.. (WPushButton. "Start counter" root) clicked (addListener wapp ( create-listener [mouse-event] (send flipper start) (fn-update-results) (.start timer) ))) (.. (WPushButton. "Stop counter" root) clicked (addListener wapp ( create-listener [mouse-event] (send flipper stop) (.stop timer) (fn-update-results) ))) (.addWidget root (WBreak.)) (.addWidget root result-text) (.addWidget root (WBreak.)) wapp))
The only thing needed in addition to this is importing the necessary jwt classes, the definition of the servlet, and starting the server, the last two being done with this code:
(def my-servlet (proxy [WtServlet] [] (createApplication [env] (make-flipper-app env)))) (def my-server (jetty-server)) (add-servlet my-server my-servlet "/*") ;(org.bitumenframework.jettify.clj_jettify/start-server jwt-toss/my-server)
Here is the file with the complete code that I was able to run:
If someone's interested, I can possibly bundle a complete environment to be able to run it immediately. Just give me a sign.
Here are the results of my exploration of Jwt tables with Clojure. The code is inspired by an example in the Jwt sources.
A table in Jwt is created with WTreeView
let [ tree-view (WTreeView.) ]
and the columns are configure in a model object. In my case, I'll use the WStandardItemModel . When instanciating the model, you tell it how many row and columns it should have, in this case 0 rows (I don't know yet why I should pass anything else than 0 here) and 4 columns:
(WStandardItemModel. 0 4)
Once the model is intanciated, we can set the column headers with the setHeaderData method:
(.setHeaderData model 0 Orientation/Horizontal "Places") (.setHeaderData model 1 Orientation/Horizontal "Weather") (.setHeaderData model 2 Orientation/Horizontal "Drink") (.setHeaderData model 3 Orientation/Horizontal "Visited")
Now we should add data to the table! A data row is represented by a list of WStandardItem objects, each being the data displayed in a column, so in our case we'll have each row represented by a list of 4 elements. A list? That's perfect for Clojure! I'll build a list of the items I want in the table and map them to a list of WStandardItems, like this:
(map #( WStandardItem. % ) '("Leuven" "Rain" "Beer" "Yes") )
For the fun I defined a function building the WStandardItem:
(defn standard-itemize [ item ] (WStandardItem. item))
Which lets me write this code to build a row:
(map standard-itemize '("Leuven" "Rain" "Beer" "Yes") )
When we have the row, we can add it to the table with appendRow :
(.appendRow model row)
We can the set assign this model to the tree-view with :setModel
(.setModel tree-view model)
Once we know that, it's trivial to work on list of rows:
(let [data'(("Leuven" "Rain" "Beer" "Yes")("Brussels" "Rain" "Beer" "Yes")) ) rows (map #( map standard-itemize %) data)] .... (doall (map #(.appendRow model %) rows))
With a function I called standard-rowize taking a row of data and returning a row of WStandardItems, we get somewhat cleaner code:
(defn standard-rowize [ row ] (map standard-itemize row)) (let [data'(("Leuven" "Rain" "Beer" "Yes")("Brussels" "Rain" "Beer" "Yes")) ) rows (map standard-rowize data)] ... (doall (map #(.appendRow model %) rows))
Here's the result, a table with row ordering and alternating row colors
But there's more to it than this. As the table is represented by a tree view, it can group rows and that is achieved really easily: each row can be the container of its sub rows! Here are the only changes to do:
Create a europe-row which will contain european cities
europe-row (WStandardItem. "Europe")
appends the rows to the europe-row rather than to the model:
(doall (map #(.appendRow europe-row %) rows))
and finally, append the europe-row to the model:
(.appendRow model europe-row)
This is all what's needed to get this:
The changes were so small that despite the fact that I discovered all this, it worked at the first try! Here's the code of the function buidling the tree-view:
(defn build-tree-view [] ( let [ tree-view (WTreeView.) model (WStandardItemModel. 0 4) europe-row (WStandardItem. "Europe") rows (map standard-rowize '(("Leuven" "Rain" "Beer" "Yes")("Brussels" "Rain" "Waffles" "Yes")) ) ] (.setHeaderData model 0 Orientation/Horizontal "Places") (.setHeaderData model 1 Orientation/Horizontal "Weather") (.setHeaderData model 2 Orientation/Horizontal "Item") (.setHeaderData model 3 Orientation/Horizontal "Visited") (.setAlternatingRowColors tree-view true) (doall (map #(.appendRow europe-row %) rows)) (.appendRow model europe-row) (.setModel tree-view model) tree-view))
Let's go further and manipulated the table: let's add a button to toggle the alternated row colors. Again, the changes to make are minimal:
- instanciate a WPushButton
- instanciate a WContainerWidget and pass it as the parent widget to the button and treeview constructor
- return the container in place of the treeview
- add a listener to the click event of the button to toggle the rows coloring. This uses the macro written for the Jwt-Clojure previous post.
Here is the code where I indicated the lines that were added or adapted:
(defn build-tree-view [] ( let [ container (WContainerWidget.) ;added button (WPushButton. "Toggle colors" container) ;added tree-view (WTreeView. container) ;adapted model (WStandardItemModel. 0 4) europe-row (WStandardItem. "Europe") rows (map standard-rowize '(("Leuven" "Rain" "Beer" "Yes")("Brussels" "Rain" "Waffles" "Yes")) ) ] (.. button clicked (addListener container (create-listener [mouse-event] (.setAlternatingRowColors tree-view (not (.hasAlternatingRowColors tree-view) ))))) ; added (.setHeaderData model 0 Orientation/Horizontal "Places") (.setHeaderData model 1 Orientation/Horizontal "Weather") (.setHeaderData model 2 Orientation/Horizontal "Item") (.setHeaderData model 3 Orientation/Horizontal "Visited") (.setAlternatingRowColors tree-view true) (doall (map #(.appendRow europe-row %) rows)) (.appendRow model europe-row) (.setModel tree-view model) ;adapted container)) ;adapted
Although there's a lot more to explore (pagination being the first thing I want to explore next), this is is for now. I hope this encourages to test Jwt and Clojure, both being very exciting projects!
I was looking for a way to easily publish documentation for Dedomenon , the information storage engine behind MyOwnDB.com which I'm again developing heavily. And as I'm developing, I want to write complete and up to date documenation. I was looking for a hosted solution, which I wouldn't have to maintain myself, but I still wanted to have full control of the content, so I could easily move to another solution in the future if needed.
I thought of a wiki, but didn't go for it as I'm not sure of the export functionalities of hosted solution and the ease of integrating the content in a new solution. Each wiki seems to have its own markup, and I'm afraid that an export functionality is not enough to ensure long term availability of the content.
I then looked at Jekyll , a tool to maintains web sites (and more specifically blogs) developed by Github . It has some very compelling functionalities:
- can be hosted as Github pages, which responds to my hosting requirement
- content is written in markdown or textile. As I had some content in textile format already, it's a plus!
- I can write content with my prefered editor (vim)
- Hosting on github means I can (I must!) handle the content's history with git
- categorizes content based on the directories hierarchy
The only problem I had it that it didn't seem a ready-made solution to handle non-blog oriented website. But after some work, I got a working solution which is worth sharing: Jekyll Base .
Jekyll Base is simply the basic directory hierarchy expected by jekkyl, with a ready-to-use template offering:
- Cross-browser layout thanks to YUI Grids
- FreshPick based CSS
- Use of Yahoo’s CDN for delivery of YUI Grids files
- Google Analytics activated by putting site id in config file
- Google Ajax Search activated by putting your API key in the config file
- Listing of documents in current section
- List of subsections
- Breadcrumbs to help in navigation
It includes 2 helpers script to add sections and pages. You can of course see it in action at http://dedomenon.github.com/documentation .
Thanks to the use of YUI Grids, the template is very simple, though will render in all browser as expected. Combined with the FreshPick CSS, it gives an acceptable solution. This is particularly important as I'm really not a designer.
Jekyll Base source is available on github and its documentation is of course self-managed and hosted as Github pages at http://raphinou.github.com/jekyll-base/
Jwt includes the class WTimer to help you run tasks at regular intervals. Here is a code that updates a text element of the page every second. It simply instanciates a WTimer, and adds a listener to its timeout signal:
(let [ container (WContainerWidget.) layout (WGridLayout.) text (WText. "Hello") timer (WTimer.) ] (doto timer (.setInterval 1000) (-> .timeout (.addListener container (create-listener [ev] (.setText text (str (java.util.Date. (System/currentTimeMillis)) ))))) (.start)) (.addWidget layout text 0 0) (.setLayout container layout) container)
Simple, isn't it?
Add comment