X-Git-Url: http://sru.miketaylor.org.uk/?a=blobdiff_plain;f=notes%2Fdevelopers.txt;h=a95e4bf1255f22cf94a1d5e835eeffc276a8d561;hb=03bad786b87f4160fad6699710ecae8b6999be10;hp=3c6fc3d81cc6afdb80c6bb4cc33136fed1941b6c;hpb=28786c6b9b372c01deed2bc010a45380b45068ab;p=mkws-moved-to-github.git
diff --git a/notes/developers.txt b/notes/developers.txt
index 3c6fc3d..a95e4bf 100644
--- a/notes/developers.txt
+++ b/notes/developers.txt
@@ -4,6 +4,26 @@ These notes are collected by Heikki, mostly from skype chats with Wolfram
and Mike. I collected them for my own use, but I hope they will turn out
to be helpful to anyone who needs to get started with mkws.
+Environment
+-----------
+
+apt-get install yui-compressor
+get nodejs, sudo make install, ln -s /usr/local/bin/npm ~/bin/npm if needed
+
+cd .../mkws; make check
+
+
+Apache
+------
+You need to set up a local apache.
+ * add 'mkws' in /etc/hosts to point to 127.0.0.2
+ * symlinked .../mkws/tools/apache2/mkws-heikki to /etc/apache/sites-available
+ * a2ensite mkws-heikki
+ * a2enmod rewrite
+ * a2enmod headers
+ * service apache2 reload
+ * Check that your browser sees somethig in http://mkws/ and
+ http://mkws/jasmine-popup.html. If need be, enable javascript etc.
Libraries
---------
@@ -25,7 +45,7 @@ test page, wait 3 seconds for success and shutdown windows.
Include files
-------------
-The whitepaper says to include mkws-complete.js. This file is made by concatenating
+The manual says to include mkws-complete.js. This file is made by concatenating
a number of files (see Makefile). For us developers, it is easier to include the
raw files, as in
@@ -54,14 +74,24 @@ Most (all?) code work happens in mkws.js.
Unit tests
----------
-if you want understand the test than you can look at mkws/test/spec/mkws-config.js
+Tests are based on jasmine. a general description of jasmine is on
+http://jasmine.github.io/1.3/introduction.html
+
+If you want understand the test than you can look at mkws/test/spec/mkws-config.js
and mkws/test/spec/mkws-pazpar2.js . See also mkws/test/README.txt
+The test scripts are included from the test page, for example
+mkws/examples/htdocs/jasmine-popup.html has
+
+
+
+
Structure of mkws.js
--------------------
(This will soon be out of date, but should provide some kind of starting
-point even then)
+point even then. This is taken directly from a Skype chat with Mike, where
+he explained the whole thing.)
First page is just helper functions for the Handlebars template library, which we
use to generate some of the HTML output. (Down the line, we will use this more
@@ -77,7 +107,7 @@ That is not yet used: shifting much of the code to do so is a big part of what I
am working on right now.
Next, a very short stanza of code that just makes sure mkws_config is defined:
-simple applications won't bother to define it at all since they override node
+simple applications won't bother to define it at all since they override none
of the defaults.
Next, a factory method for making widget objects. At present this is trivial
@@ -106,7 +136,7 @@ the next thing after the end of that function (or class, if you like).
You're familiar with this JS idiom?
(function() { code ... })();
- Runs the code immediately, but within its own namespace. That's what we do for
+Runs the code immediately, but within its own namespace. That's what we do for
all the remaining code in mkws.js. In this case, we pass the jQuery object into
that namespace under the name `j' for reasons that are frankly opaque to me.
@@ -125,7 +155,7 @@ named logging types that are not in a sequence.
(You will notice that the teams have a debug() function which delegates to this
but adds some other useful team-specific stuff.)
- Next up: the utility function mkws.handle_node_with_team(). We use a LOT of nodes
+Next up: the utility function mkws.handle_node_with_team(). We use a LOT of nodes
that have their team-name in a class (as in "mkwsTeam_NAME" outlined above).
All the utility does is parse out that team-name, and the widget-type, from the
classes, and pass them through to the callback.
@@ -170,13 +200,166 @@ The first thing it does is patch up the HTML so that old-style MKWS apps work
using new-style elements. This is the code you just fixed.
Straight after that, more fixup: elements that have an mkws* class but no
-team are given an extra class kwsTeam_AUTO. This is the ONLY thing that's special
+team are given an extra class mkwsTeam_AUTO. This is the ONLY thing that's special
about the team "AUTO" -- it has no other privileges.
- Very near the end now: we walk through all nodes with an mkws* class, and create
+Very near the end now: we walk through all nodes with an mkws* class, and create
the team and widget objects using the factories we described earlier. Jason is
worried this will be slow, hence the instrumentation. It's not :-)
Last of all: start things off! SP-auth if used, otherwise straight to the
auto-searches.
+
+OK, want to plough into the team object?
+
+... bearing in mind that some of this should be moved out of the team into the
+top-level code, and some other parts will be moved down into individual widgets
+once we have them.
+
+OK. So we start with a bunch of member variables for state. Many of them will be
+hauntingly familiar to anyone who's worked on jsdemo :-)
+
+A new one is m_debug_time, which is a structure used for keeping track of elapsed
+time. It's nice: it lets debug messages for each time note how long it's been
+since the last message in that same team, which means you can see how slow-ass
+our network operations can be. That's implemented in debug(), which is the very
+next thing in the file.
+
+Then a bunch of code to do with setting initial values from defaults.
+
+The stuff about languages is a great example of code that should be at the top
+level, not in the team: it deals only with global objects, yet gets run n times
+if there are n teams. (I am adding a ###-comment to this effect right now.)
+
+Then we make the pz2 object, which is our only channel of communication with the
+server outside of the HTTP GET hack in authenticate_session(). The callback
+functions are all closures with access to this team's member variables. Are you
+somewhat familiar with pz2.js already?
+
+Well, it's all driven by callbacks. You register them at object-creation time;
+then later when you call (say) m_paz.search(), it will invoke your my_onsearch()
+function when the search-response arrives.
+
+There are some oddities in the order things get done. For example, is m_perpage
+set AFTER this object is created, rather than at the same time as its stablemate
+m_sort up above? No reason. So plenty of tedious, error-prone, cleaning up of
+this sort to be done.
+
+Then come the pz2 callbacks. my_onshow() is an interesting representative. The
+team-name is passed back by pz2 (which has used it as the SP window-ID to keep
+sessions separate). I used to think it needed to be passed back like this so
+the invoked callback functions could know what team they're being called for,
+but now I realise they don't need to, because they're closures that can see
+m_teamName. Oh well.
+
+Indeed, you can see that my_onshow() doesn't even USE the teamName parameter.
+
+Anyway, the point is to find specific elements that belong to the right team,
+so they can be populated with relevant data. We do that for the pager, and of
+course the record-list.
+
+The meat of the record-list is filled in by invocations of renderSummary(),
+which loads a Handlebars template and uses that to generate the HTML. Needless
+to say, loadTemplate() caches compiled templates.
+
+my_onstat() and my_onterm() do similar things -- you can figure out the details.
+
+add_single_facet(), target_filtered() and others are uninteresting utility
+functions.
+
+my_onrecord() and my_onbytarget() are more of the same. There is some nastiness
+in my_onrecord() to handle poping up a full-record div in the right place and
+getting rid of any old ones. It doesn't work quite right.
+
+onFormSubmitEventHandler() is more interesting. This is a JS event handle (for
+form-submit, duh) but how does it know what team to work for? It checks `this'
+to see that classes the HTML element has, and so finds the relevant mkwsTeam_NAME
+class. Then it can fire newSearch() on the relevant team. But it now occurs to
+me that this too is a closure so it doesn't need to do any of that. It can just
+start the search in its own team.
+
+[Why can that simplifying change be made here but not in, say, switchView()?
+Because the former is assigned to a DOM object from within the JS code, so acts
+as a closure; but the latter is invoked by a fragment of JS text which the user
+clicks on, when there is no context.]
+
+An oddity of newSearch(): it's not defined as
+ function newSearch()
+like most of the other member functions, but
+ that.newSearch = function()
+That's because, unlike most other member function, it gets explicitly invoked
+on a team object:
+ mkws.teams[tname].newSearch(val);
+
+But in fact that won't be necessary once I fix the invoker
+(onFormSubmitEventHandler) to be aware of its own context, so that can simplify,
+too.
+
+The next interesting method is triggerSearch(). You can see that it assembles
+the pp2filter and pp2limit values for the search invocation by walking the
+array m_filters[], which is built by click on facets.
+
+That's done in a slightly clumsy way. I might make a Filters object at some
+point with some nice clean methods.
+
+BTW., more unnecessary context-jockying with the windowid parameter. I don't
+need it, I have m_teamName.
+
+loadSelect() is another fine example of a method that appears in a random
+place. It's just one of the HTML-generation helpers.
+
+Now we come to a bunch of externally invoked functions, that.limitTarget() etc.
+These are the meat that are called by the stubs in the top-level code -- remember
+those one-liners?
+
+They change state in various ways based on the user's clicks. The first four
+({un,}limit{Query,Target}()) do so by tweaking the m_filters[] array.
+
+More HTML-generation helpers: redraw_navi(), drawPager() -- note the inconsistent
+multi-word naming scheme
+
+We are *completely* schizophrenic over whether to use camelCase or
+underscore_separated
+
+Then more UI functions (that.X, that.Y)
+
+Anyway, onwards ... loadTemplate() you already know about.
+
+defaultTemplate() is the hardwired defaults, used for applications that don't
+define their own templates. For an application that does, see
+http://example.indexdata.com/lolcat.html
+
+As you can imagine, Lynn was WAY impressed by lolcat.html
+
+mkws_html_all() is a big ugly function that generates a buttload of HTML.
+Basically, it spots where you've used a magic name like
+and expands it to contain the relevant HTML.
+
+Then it's just utility functions: parseQueryString() to read URL params,
+mkws_set_lang() and friends generate more HTML.
+
+All these HTML-generation functions should of course be together. Many of them
+should also use Handlebars templates, so that clever applications can redefine
+them. In places, too, they still need fixing to use CSS classes instead of inline
+markup, and suchlike.
+
+that.run_auto_search() is interesting. It gets the term to search for from the
+"autosearch" attribute on the relevant element, but there are special forms for
+that string. !param!NAME gets the query from the URL parameter called NAME;
+!path!NUM gets it from the NUM'th last component of the URL path. There may be
+more of these in future.
+
+Once it's got that it's a pretty straightforward invocation of newSearch()
+
+M(string) yields the translation of string into the currently selected language.
+We use it a lot in the HTML generation, and it's one part of that process that's
+more cumbersome in Handlebars. The problem is that M() is a closure so it could
+in principle know what the language of THIS team is, and it could be different
+for different teams, even though that's not the case at the moment. But Handlebars
+helpers are set once for all time, so they can't be team-specific, which means
+they can only refer to the globally selected lan
+
+And that, really, is the end of the team object (and so of mkws.js). TA-DAH!
+
+