You are viewing a plain text version of this content. The canonical link for it is here.
Posted to infrastructure-dev@apache.org by Sam Ruby <ru...@intertwingly.net> on 2014/09/24 02:39:50 UTC

Whimsy board agenda tool overview and roll call 'attend' button implementation

Overview of the board agenda tool:

1) There is code which parses an agenda, combining it with some 
information from other sources like LDAP, and returning a datastructure 
consisting of hashes, arrays, and strings.  This datastructure is 
serialized as JSON and send to the client.  The parsing code can be 
found here:

https://svn.apache.org/repos/infra/infrastructure/trunk/projects/whimsy/lib/whimsy/asf/agenda.rb
https://svn.apache.org/repos/infra/infrastructure/trunk/projects/whimsy/lib/whimsy/asf/agenda

2) In addition to static HTML, stylesheets, and JavaScript, the client 
makes use of Angular.JS which provides model, views, and controllers on 
the client.  A key feature of Angular.JS is two way data binding which 
means that changes to the model are automatically reflected in views and 
vice versa.  Models in Angular.JS can be POJOs (plain old JavaScript 
objects), and in the board agenda tool they represent items resulting 
from the parsing of the JSON.

https://angularjs.org/

3) CSS from Bootstrap add style and animation.

http://getbootstrap.com/

4) Wunderbar and ruby2js makes it easy to create readable and correct 
HTML and JavaScript from Ruby.

https://github.com/rubys/wunderbar#readme
https://github.com/rubys/ruby2js#readme

---

Updating the roll call demonstrates a number of these concepts.  For 
starters, the code for the button itself:

     _ng_template.attend_button! do
       _button.btn.btn_primary '{{ attend_label }}', ng_controller: 
'Attend',
         ng_click: 'click()', ng_disabled: 'disabled'
     end


https://svn.apache.org/repos/infra/infrastructure/trunk/projects/whimsy/www/board/agenda/partials/section._html

This is a template as the button is conditionally shown. 
'attend_button' is the identifier.  'btn' and 'btn_primary' correspond 
to Bootstrap styles.  The attend_label is computed.  This button is 
associted with the 'Attend' controller.  Clicking the button calls the 
click() function, and the 'disabled' value controls whether or not this 
button is disabled.

With this in place, there are a number of todos: (1) decide when the 
button is shown, (2) defind a controller that (a) sets the attend_button 
and disabled values and (b) implements click.

Inside the Section controller (an agenda section corresponds to a page), 
you will find the following code:

     if item.title == 'Roll Call' and not @minutes['Roll Call']
       Actions.add 'attend-button'
     end

https://svn.apache.org/repos/infra/infrastructure/trunk/projects/whimsy/www/board/agenda/js/app._js

This adds the button if the page the user is viewing has a title of 
'Roll Call' and there aren't minutes yet for the Roll Call.

Next up, the Attend controller.  First the attend_label property:

     controller :Attend do
       def attend_label
         if @item.people[@user] and @item.people[@user].attending
           'regrets'
         else
           'attend'
         end
       end

       ...
     end

Looking at the JSON for an agenda makes it easier to understand this code:

https://whimsy.apache.org/board/agenda/2014-10-15.json

The item with a title of "Roll Call" has a list of people.  If the user 
viewing this page is in that list, and is listed as attending, then the 
button label will read 'regrets', otherwise it will read attend'.

Now for click handing:

     controller :Attend do
       ...

       def click()
         if @attend_label == 'regrets'
           data = {action: 'regrets', name: @item.people[@user].name}
         else
           data = {action: 'attend', userid: @user}
         end

         data.agenda = Data.get('agenda')

         @disabled = true
         $http.post('../json/attend', data).success { |response|
           Agenda.put response
         }.error { |data|
           $log.error data.exception + "\n" + data.backtrace.join("\n")
           alert data.exception
         }.finally {
           @disabled = false
         }
       end
     end

Based on the attend label, different data will be sent on the request. 
Additionally, the name of the agenda file will be passed.  Before the 
request is sent, @disabled is set to true, thereby disabling the button. 
  Upon receipt of a successful response, the entire agenda is replaced 
with data from the server, causing everything in the browser window to 
be re-evaluated.  On a failure, the exception is logged and a pop-up 
alert is shown.  Finally, the button is re-enabled.

This leaves a final task of writing server logic that takes action based 
on the data sent, and returns either an exception or an Agenda in JSON 
format.  This logic can be found here:

https://svn.apache.org/repos/infra/infrastructure/trunk/projects/whimsy/www/board/agenda/json/attend._json

Those interested may want to explore the generate JavaScript:

https://whimsy.apache.org/board/agenda/js/app.js

Search for AsfBoardAgenda.controller("Attend", function(...) {...});

Of particular note, 'attend_label' is a property as it was defined 
without any parenthesis, and 'click' is a function as it was defined 
with parenthesis.  This is because properties and functions are handled 
differently in JavaScript.