[isidorus-cvs] r25 - in trunk: docs src src/ajax src/ajax/css src/ajax/javascripts src/json src/rest_interface

Lukas Giessmann lgiessmann at common-lisp.net
Wed Apr 1 09:41:53 UTC 2009


Author: lgiessmann
Date: Wed Apr  1 05:41:52 2009
New Revision: 25

Log:
added the general user-interface structure; implemented the home section; and added a summary json-interface to the rest-interface

Added:
   trunk/src/ajax/css/
   trunk/src/ajax/css/create_topics.css
   trunk/src/ajax/css/edit_topics.css
   trunk/src/ajax/css/home.css
   trunk/src/ajax/css/main.css
   trunk/src/ajax/css/navi.css
   trunk/src/ajax/css/search_topics.css
   trunk/src/ajax/javascripts/ajax_constants.js   (contents, props changed)
   trunk/src/ajax/javascripts/ajax_edit_topic.js
   trunk/src/ajax/javascripts/ajax_home.js
   trunk/src/ajax/javascripts/ajax_navi.js
Modified:
   trunk/docs/xtm_json.txt
   trunk/src/ajax/isidorus.html
   trunk/src/isidorus.asd
   trunk/src/json/json_exporter.lisp
   trunk/src/rest_interface/rest-interface.lisp
   trunk/src/rest_interface/set-up-json-interface.lisp

Modified: trunk/docs/xtm_json.txt
==============================================================================
--- trunk/docs/xtm_json.txt	(original)
+++ trunk/docs/xtm_json.txt	Wed Apr  1 05:41:52 2009
@@ -1,11 +1,50 @@
-resourceData:
+//+-----------------------------------------------------------------------------
+//+ Overview:
+//+  *Part 1: XTM - data model
+//+  *Part 2: Object summaries
+//+-----------------------------------------------------------------------------
+
+
+
+
+//+-----------------------------------------------------------------------------
+//+ Part 1: XTM - data model:
+//+   The first part describes the xtm's data model, here will be all elements
+//+   defined in the xtm defined as json objects and finally there will be used
+//+   as json objects in a json-fragment-object.
+//+
+//+   this json model depends on the xtm version 2.0 and contains the following
+//+   objects:
+//+    *resourceData
+//+    *variant
+//+    *name
+//+    *name
+//+    *occurrence
+//+    *topic
+//+    *role
+//+    *association
+//+    *topicStub
+//+    *fragment
+//+
+//+   At the end of this file are some expample json objects, you can also
+//+   validate json data on "http://www.jsonlint.com/".
+//+   Note all values, although they are null values e.g. the "type" field in
+//+   a name object should be set to a value - in this case "null".
+//+-----------------------------------------------------------------------------
+
+
+//+-----------------------------------------------------------------------------
+//+ resourceData
+//+-----------------------------------------------------------------------------
 {
   "datatype" : "Text",
   "value" : "Text"
 }
 
 
-variant:
+//+-----------------------------------------------------------------------------
+//+ variant
+//+-----------------------------------------------------------------------------
 {
   "itemIdentities" : [ "Text" , "..." ],
   "scopes" : [ [ "PSI-1-t1", "PSI-2-t1", "..." ], [ "PSI-1-t2", "PSI-2-t2", "..." ], [ "..." ] ],
@@ -14,7 +53,9 @@
 }
 
 
-name:
+//+-----------------------------------------------------------------------------
+//+ name
+//+-----------------------------------------------------------------------------
 {
   "itemIdentities" : [ "Text", "..." ],
   "type" : [ "PSI-1", "PSI-2", "..." ],
@@ -24,7 +65,9 @@
 }
 
 
-occurrence:
+//+-----------------------------------------------------------------------------
+//+ occurrence
+//+-----------------------------------------------------------------------------
 {
   "itemIdentities" : [ "Text", "..." ],
   "type" : [ "PSI-1", "PSI-2", "..." ],
@@ -34,7 +77,9 @@
 }
 
 
-topic:
+//+-----------------------------------------------------------------------------
+//+ topic
+//+-----------------------------------------------------------------------------
 {
   "id" : "Text",
   "itemIdentities" : [ "Text", "..." ],
@@ -46,7 +91,9 @@
 }
 
 
-role:
+//+-----------------------------------------------------------------------------
+//+ role
+//+-----------------------------------------------------------------------------
 {
   "itemIdentities" : [ "Text", "..." ],
   "type" : [ "PSI-1", "PSI-2", "..." ],
@@ -54,7 +101,9 @@
 }
 
 
-association:
+//+-----------------------------------------------------------------------------
+//+ association
+//+-----------------------------------------------------------------------------
 {
   "itemIdentities" : [ "Text", "..." ],
   "type" : [ "PSI-1", "PSI-2", "..." ],
@@ -63,7 +112,9 @@
 }
 
 
-topicStub:
+//+-----------------------------------------------------------------------------
+//+ topicStub
+//+-----------------------------------------------------------------------------
 {
   "id" : "Text",
   "itemIdentities" : [ "Text", "..." ],
@@ -72,24 +123,70 @@
 }
 
 
-fragment
+//+-----------------------------------------------------------------------------
+//+ fragment
+//+    The field tm-ids should have only one tm-id in the list, because
+//+    there will be used only the first, if the fragment is an incoming one
+//+    outgoing fragment have a list with more tm-ids but at least one
+//+-----------------------------------------------------------------------------
 {
   "topic" : { <topic> },
   "topicStubs" : [ { <topicStub> }, { <...> } ],
   "associations" : [ { <association> }, { <...> } ],
   "tm-ids" : [ "id-1", "id-2", "..." ]
 }
-// the field tm-ids should have only one tm-id in the list, because
-// there will be used only the first if the fragment is an incoming one
-// outgoing fragment have a list with more tm-ids but at least one
 
 
-a summary of all topic psis within isidorus
-[["topic-1-psi-1","topic-1-psi-2",<...>],["topic-2-psi-1","topic-2-psi-2",<...>],<...>]
+//+-----------------------------------------------------------------------------
+//+ Part 2: Object summaries
+//+   The second part contains object summaries of exisiting objects in
+//+   isidorus.
+//+
+//+    *psiSummary
+//+    *topicSummary
+//+-----------------------------------------------------------------------------
+
+
+//+-----------------------------------------------------------------------------
+//+ psiSummary
+//+    The json list is made of inner json-lists.
+//+    Every inner json list represents one topic with all psis owned by the
+//+    topic. The outer list represents a set of all topics exist in isidorus.
+//+-----------------------------------------------------------------------------
+[ [ "topic-1-psi-1", "topic-1-psi-2", <...> ], [ "topic-2-psi-1", "topic-2-psi-2", <...> ], <...> ]
+
+
+//+-----------------------------------------------------------------------------
+//+ topicSummary
+//+    contains the topic id,subjetcIdentifiers, itemIdentities,
+//+    subjectLocators, nameSummaries and occurrenceSummaries
+//+-----------------------------------------------------------------------------
+{
+  "id" : "Text",
+  "itemIdentities" : [ "Text", "..." ],
+  "subjectLocators" : [ "Text", "..." ],
+  "subjectIdentifiers" : [ "Text", "..." ],
+  "instanceOfs" : [ [ "PSI-1-t1", "PSI-2-t1", "..." ], [ "PSI-1-t2", "PSI-2-t2", "..." ], [ "..." ] ],
+  "names" : [ "name-1", "name-2", <...> ],
+  "occurrences" : [ "occurrence-1", "occurrence-2", <...>]
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 
-=== example fragment with one topic, a few topicStubs and associations =========
 {
   "topic" : {
               "id"  :  "t403",

Added: trunk/src/ajax/css/create_topics.css
==============================================================================

Added: trunk/src/ajax/css/edit_topics.css
==============================================================================

Added: trunk/src/ajax/css/home.css
==============================================================================
--- (empty file)
+++ trunk/src/ajax/css/home.css	Wed Apr  1 05:41:52 2009
@@ -0,0 +1,32 @@
+.topicSummaryTd {
+    width: 40px;
+    border: solid 1px gray;
+}
+
+#topicTable {
+    width: 80%;
+    border: solid 1px gray;
+    margin-left: auto;
+    margin-right: auto;
+    margin-top: 10px;
+    margin-bottom: 10px;
+}
+
+th {
+    color: red;
+    border: solid 1px gray;
+}
+
+ul.topicTable {
+    list-style: none;
+}
+
+div.naviTopicTable {
+    width: 80%;
+    margin-left: auto;
+    margin-right: auto;
+}
+
+select.topicTable {
+    margin-left: 20px;
+}
\ No newline at end of file

Added: trunk/src/ajax/css/main.css
==============================================================================
--- (empty file)
+++ trunk/src/ajax/css/main.css	Wed Apr  1 05:41:52 2009
@@ -0,0 +1,11 @@
+.clickable{
+    cursor: pointer;
+}
+
+.clickable:hover{
+    text-decoration: underline;
+}
+
+.clickable:active{
+    color: red;
+}
\ No newline at end of file

Added: trunk/src/ajax/css/navi.css
==============================================================================
--- (empty file)
+++ trunk/src/ajax/css/navi.css	Wed Apr  1 05:41:52 2009
@@ -0,0 +1,9 @@
+#navi {
+    border: solid 1px;
+    margin-top: 10px;
+    margin-bottom: 10px;
+}
+
+.naviElem {
+    background-color: silver;
+}
\ No newline at end of file

Added: trunk/src/ajax/css/search_topics.css
==============================================================================

Modified: trunk/src/ajax/isidorus.html
==============================================================================
--- trunk/src/ajax/isidorus.html	(original)
+++ trunk/src/ajax/isidorus.html	Wed Apr  1 05:41:52 2009
@@ -3,161 +3,36 @@
   <head>
     <title>isidorus</title>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
-    <link rel="stylesheet" type="text/css" href="main.css"/>
 
+    <!-- includes all necessary css-files -->
+    <link rel="stylesheet" type="text/css" href="css/main.css"/>
+    <link rel="stylesheet" type="text/css" href="css/home.css"/>
+    <link rel="stylesheet" type="text/css" href="css/search_topics.css"/>
+    <link rel="stylesheet" type="text/css" href="css/edit_topics.css"/>
+    <link rel="stylesheet" type="text/css" href="css/create_topics.css"/>
+    <link rel="stylesheet" type="text/css" href="css/navi.css"/>
+    
     <!-- includes the prototype and scriptaculous frameworks -->
     <script language="JavaScript" type="text/javascript" src="javascripts/prototype.js"></script>
     <script language="JavaScript" type="text/javascript" src="javascripts/scriptaculous.js"></script>
 
-    <!-- own javascript code -->
-    <script language="JavaScript" type="text/javascript">
-     // --- some constants -----------------------------------------------------
-     var TIMEOUT = 5000; // const TIMEOUT = 5000 --> "const" doesn't work under IE
-     var HOST_PREF = "http://localhost:8000/";
-     var GET_PREFIX = HOST_PREF + "json/get/";
-     var COMMIT_URL = HOST_PREF + "json/commit/";
-     var ALL_PSIS_URL = HOST_PREF + "json/psis/";
-     var OWN_URL = HOST_PREF + "isidorus";
-
-     // --- some globals -------------------------------------------------------
-     var ALL_PSIS = null;
-     var CURRENT_FRAGMENT = null;
-
-     // --- default error handler for all ajax objects
-     function errorHandler(ajaxReq)
-     {
-	 alert("Something went wrong ... -> " + ajaxReq.status);
-     }
-
-
-     // --- redirects the client to the initial url
-     function goBack()
-     {
-	 window.location = OWN_URL;
-	 $("textArea").value = "";
-     }
-
-
-     // --- ajax functions -----------------------------------------------------
-     function commitPut()
-     {
-	 function commitPutHandler(ajaxReq)
-	 {
-	     alert($("textArea").value + "\n\n" + ajaxReq.status);
-	 }
-
-
-	 new Ajax.Request(COMMIT_URL,
-			  {
-			      method: "post",
-			      requestHeaders:{ "Content-Type":"application/json"},
-			      onSuccess: commitPutHandler,
-			      onFailure: errorHandler,
-			      postBody: $("textArea").value
-			  });
-     }
-
-
-     // --- hides the table with all psis and sends a request to the server for a specific topic-psi
-     function selectTopic(psi)
-     {
-	 if(ALL_PSIS !== null && ALL_PSIS.length !== 0){
-	     // --- handler for the ajax request aobject - if the request was successful
- 	     function getFragment(ajaxReq)
-	     {
-		 var response = ajaxReq.responseText;
-		 try{
-		     var jsonObj = CURRENT_FRAGMENT = response.evalJSON();
-		     $("textArea").innerHTML = response; // for safari
-		     $("textArea").value = response; // for all other browsers
-		 }catch(err){
-		     alert("got bad JSON data: " + err);
-		 }
-	     }
-	     
-	     var url = GET_PREFIX + psi.gsub("#", "%23");
-	     $("allPsisTable").shrink();
-	     setTimeout(function(){$("textArea").grow();}, 1500); // an easy way to define events by yourself
-	     setTimeout(function(){$("allPsisTable").remove();}, 2000);
-	     $("allPsisButton").insert({after: '<input id="commitPutButton" style="margin-top:10px; margin-bottom:10px;" type="button" onclick="commitPut()" value="commit fragment"/>'});
-	     // --- ajax request
-	     new Ajax.Request(url,
-			      {
-				  method:'get',
-  			          requestHeaders: ["If-Modified-Since", "Thu, 1 Jan 1970 00:00:00 GMT"], // rfc1945, to make sure that IE does not cache the ajax-response
-				  onSuccess: getFragment,
-				  onFailure: errorHandler
-			      });
-	 }
-     }
-
-
-     // --- gets all topic psis are currently contained in isidorus
-     function getAllPsis()
-     {
-	 // --- handler for the ajax request aobject - if the request was successful
-	 function getAllPsisSuccessHandler(ajaxReq)
-	 {
-	     var btn= $("commitPutButton");
-	     if(btn)btn.remove();
-
-	     if($("allPsisTable") === null){ // avoid duplicates
-		 var response = ajaxReq.responseText;
-		 try{
-		     var jsonObj = ALL_PSIS = response.evalJSON();
-		     var htmlStr = '<table id="allPsisTable"><tr><th>topic #</th><th>psis</th></tr>';
-		     
-		     jsonObj.each(function(topic, idx)
-				  {
-				      htmlStr += '<tr><td rowspan="' + topic.length + '">' + idx + '</td>';
-				      topic.each(function(psi, innerIdx)
-						 {
-						     if(innerIdx !== 0)htmlStr += "<tr>";
-						     htmlStr += '<td><span id="psiRow_' + idx + '_' + innerIdx + '" name="psi">' + psi + '</span></td></tr>';
-						 });
-				      if(topic.length !== 1)htmlStr += "</tr>";
-				  });
-		     htmlStr += "</table>";
-		     $("allPsisButton").insert({after: htmlStr});
-		     $("allPsisTable").hide();
-		     $("allPsisTable").appear();
-		     
-
-		     // --- iterates through the new created DOM-elements and adds to every one a click-event-handler
-		     jsonObj.each(function(topic, idx)
-				  {
-				      topic.each(function(psi, innerIdx)
-						 {
-						     $("psiRow_" + idx + "_" + innerIdx).observe("click", function(event){ selectTopic(Event.element(event).innerHTML); });
-						     $("psiRow_" + idx + "_" + innerIdx).observe("mouseover", function(event){Event.element(event).up().setStyle({"backgroundColor" : "silver", "cursor" : "pointer"}); });
-						     $("psiRow_" + idx + "_" + innerIdx).observe("mouseout", function(event){ Event.element(event).up().setStyle({"backgroundColor" : "white", "cursor" : "default"}); });
-						 });
-				  });
-		 }catch(err){
-		     alert("got bad JSON data: " + err);
-		 }
-	     }
-	 }
-
-	 $("textArea").fade();
-
-	 // --- ajax request
-	 new Ajax.Request(ALL_PSIS_URL,
-			  {
-			      method:"get",
-			      requestHeaders: ["If-Modified-Since", "Thu, 1 Jan 1970 00:00:00 GMT"],
-			      onSuccess: getAllPsisSuccessHandler,
-			      onFailure: errorHandler
-			  });
-     }
-    </script>
+    <!-- includes own javascript files -->
+    <script language="JavaScript" type="text/javascript" src="javascripts/ajax_constants.js"></script>
+    <script language="JavaScript" type="text/javascript" src="javascripts/ajax_edit_topic.js"></script>
+    <script language="JavaScript" type="text/javascript" src="javascripts/ajax_home.js"></script>
+    <script language="JavaScript" type="text/javascript" src="javascripts/ajax_navi.js"></script>
   </head>
 
   <body>
-    <div id="content" style="margin-top:20px; margin-left:auto; margin-right:auto; border:dashed; width:60%;">
-      <input id="allPsisButton" style="margin:10px;" type="button" onclick="getAllPsis()" value="get all psis"/><br/>
-      <textarea id="textArea" style="margin-left:10px; margin-bottom:10px;" cols="67" rows="10"></textarea><br/>
-      <input id="backButton" style="margin-left:10px; margin-bottom:10px;" type="button" onclick="goBack()" value="clear"/><br/>
+    <div id="page">
+      <div id="navi">
+	<span id="home" class="naviElem clickable">home</span>
+	<span id="searchTopic" class="naviElem clickable">search topic</span>
+	<span id="editTopic" class="naviElem clickable">edit topic</span>
+	<span id="createTopic" class="naviElem clickable">create topic</span>
+      </div>
+      <div id="content" style="border: red solid 1px;">
+      </div>
     </div>
   </body>
 </html>

Added: trunk/src/ajax/javascripts/ajax_constants.js
==============================================================================
--- (empty file)
+++ trunk/src/ajax/javascripts/ajax_constants.js	Wed Apr  1 05:41:52 2009
@@ -0,0 +1,11 @@
+var TIMEOUT = 5000; // const TIMEOUT = 5000 --> "const" doesn't work under IE
+var HOST_PREF = "http://localhost:8000/";
+var GET_PREFIX = HOST_PREF + "json/get/";
+var COMMIT_URL = HOST_PREF + "json/commit/";
+var ALL_PSIS_URL = HOST_PREF + "json/psis/";
+var OWN_URL = HOST_PREF + "isidorus";
+var SUMMARY_URL = HOST_PREF + "json/summary"
+
+
+// --- a kind of enum for the the different pages with an attribute and a value
+var PAGES = {"home" : "home", "search" : "searchTopic", "edit" : "editTopic", "create" : "createTopic"};
\ No newline at end of file

Added: trunk/src/ajax/javascripts/ajax_edit_topic.js
==============================================================================
--- (empty file)
+++ trunk/src/ajax/javascripts/ajax_edit_topic.js	Wed Apr  1 05:41:52 2009
@@ -0,0 +1,4 @@
+function makeEdit(psi)
+{
+    alert("psi: " + psi);
+}
\ No newline at end of file

Added: trunk/src/ajax/javascripts/ajax_home.js
==============================================================================
--- (empty file)
+++ trunk/src/ajax/javascripts/ajax_home.js	Wed Apr  1 05:41:52 2009
@@ -0,0 +1,258 @@
+// --- with this object there will be set the first and last index of topics to get by the ajax request
+// --- further this object handles out of range violations and some other site effects, e.g.
+// --- topicsPerPage === -1 -> show all topics, ...
+var __idx = {"firstIdx" : 0, "lastIdx" : 10, "lastDirectionForward" : true, "topicsPerPage" : 10, "outOfRange" : false,
+	     "getFirstIdx" : function(){ return this.firstIdx; },
+	     "setFirstIdx" : function(x) { if(typeof(x) === "number" && x >= 0) this.firstIdx = x; },
+	     "getLastIdx" : function(){ return this.lastIdx; },
+	     "setLastIdx" : function(x) { if(typeof(x) === "number" && x >= 0) this.lastIdx = x; },
+	     "getLastDirectionForward" : function() { return this.lastDirectionForward; },
+	     "setLastDirectionForward" : function(x) { if(typeof(x) === "boolean") this.lastDirectionForward = x; },
+	     "getTopicsPerPage" : function() {return (this.topicsPerPage === -1 ? "nil" : this.topicsPerPage); },
+	     "setTopicsPerPage" : function(x) {
+		 if(typeof(x) === "number" && x > 0){
+		     this.topicsPerPage = x;
+		     this.lastIdx = this.firstIdx + this.topicsPerPage;
+		 }
+		 else if(typeof(x) === "number" && x === -1){
+		     this.topicsPerPage = x;
+		     this.lastIdx = "nil";
+		 }
+	     },
+	     "getOutOfRange" : function() { return this.outOfRange; },
+	     "setOutOfRange" : function(x){ if(typeof(x) === "boolean") this.outOfRange = x;  },
+	     "next" : function() {
+		 if(this.outOfRange) return;
+
+		 this.firstIdx += this.topicsPerPage;
+		 if(this.topicsPerPage !== -1){ this.lastIdx = this.firstIdx + this.topicsPerPage; }
+		 else { this.lastIdx = "nil"; }
+		 this.lastDirectionForward = true;
+	     },
+	     "prev" : function() { 
+		 if(this.topicsPerPage !== -1){
+		     this.firstIdx -= this.topicsPerPage;
+		     if(this.firstIdx < 0)this.firstIdx = 0;
+		     this.lastIdx = this.firstIdx + this.topicsPerPage;
+		 }
+		 else {
+		     this.firstIdx = 0;
+		     this.lastIdx = "nil";
+		 }
+		 this.lastDirectionForward = false;
+	     }
+	    };
+
+
+
+// --- creates a html table with the id "tableId" and appends it on the element with the id
+// --- "parentId", if the variable next ist set to true there will be shown the next
+// --- topics otherwise the previous topics
+// --- the table looks like the following schema:
+// --- itemIdentity | subjectLocator | subjectIdentifier | instanceOf | name | occurrence
+function makeHome(parentId, tableId, next)
+{
+    // --- create the ajax-request handlers ------------------------------------
+    function onSuccessHandler(xhr)
+    {
+	// --- creates the navigation div-element with a forward-, backward- button and a
+	// --- selection box where the user can choose the amount of topics per page
+	function createTableNavi(top)
+	{
+	    // --- creates the backwards and forwards buttons, if they don't exist
+	    if(($("naviDivTop") === null && top === true) || ($("naviDivBottom") === null && top === false) && $(parentId)){
+		var div = new Element("div", {"id" : (top ? "naviDivTop" : "naviDivBottom"), "class" : "naviTopicTable " + PAGES.home});
+		var lftBtn = new Element("input", {"type" : "button", "id" : (top ? "topicTableLftBtnTop" : "topicTableLftBtnBottom")});
+		var rgtBtn = new Element("input", {"type" : "button", "id" : (top ? "topicTableRgtBtnTop" : "topicTableRgtBtnBottom")});
+		lftBtn.value = "<<";
+		rgtBtn.value = ">>";
+		rgtBtn.setStyle({"float" : "right"});
+		lftBtn.setStyle({"float" : "left"});
+		div.insert(lftBtn, {"position" : "top"});
+		div.insert(rgtBtn, {"position" : "bottom"});
+		$("content").insert(div, {"position" : "top"});
+		
+		rgtBtn.observe("click", function(event)
+			       {
+				   __idx.next();
+				   makeHome(parentId, tableId, true);
+			       });
+		lftBtn.observe("click", function(event)
+			       {
+				   __idx.prev();
+				   makeHome(parentId, tableId, false);
+			       });
+
+		var select = new Element("select", {"id" : (top ? "topicTableSelectTop" : "topicTableSelectBottom"), "class" : "topicTable"});
+		var selectValues = new Array("5", "10", "15", "25", "50", "100", "200", "300", "All");
+		var selectInnerHTML = "";
+		selectValues.each(function(value, idx)
+				  {
+				      if(Number(value) !== __idx.getTopicsPerPage()){
+					  select.insert(new Element("option", {"value" : (value === "All" ? -1 : value)}).update(value), {"position" : "bottom"});
+				      }
+				      else {
+					  select.insert(new Element("option", {"value" : (value === "All" ? -1 : value), "selected" : "selected"}).update(value), {"position" : "bottom"});
+				      }
+				  });
+		div.insert(select, {"position" : "content"});
+
+		select.observe("change", function(event)
+			       {
+				   __idx.setTopicsPerPage(Number(event.element().value));
+				   makeHome(parentId, tableId, true);
+			       });
+	    }
+	}
+
+
+	try {
+	    var topicSummaries = xhr.responseText.evalJSON();
+	    // --- inserts or updates the topic table if there is some json data or
+	    // --- if there isn't a table yet
+	    if(topicSummaries !== null || $(tableId) === null){
+		// --- removes the old table - if there exists an element with the id "tableId"
+		if($(tableId) !== null)$(tableId).remove();
+		if($("naviDivBottom") !== null)$("naviDivBottom").remove();
+		if($("naviDivBottom") !== null)$("naviDivBottom").remove();
+		
+		createTableNavi(true);
+
+		// --- creates the html table
+		var topicTable = new Element("table", {"id" : "topicTable", "class" : PAGES.home});
+		
+		// --- creates the header row
+		var header = new Element("tr");
+		header.insert(new Element("th", {"id" : "itemIdentityTh"}).update("itemIdentity"), {"position" : "bottom"});
+		header.insert(new Element("th", {"id" : "subjectLocatorTh"}).update("subjectLocator"), {"position" : "bottom"});
+		header.insert(new Element("th", {"id" : "subjectIdentifierTh"}).update("subjectIdentifier"), {"position" : "bottom"});
+		header.insert(new Element("th", {"id" : "instanceOfTh"}).update("instanceOf"), {"position" : "bottom"});
+		header.insert(new Element("th", {"id" : "nameTh"}).update("name"), {"position" : "bottom"});
+		header.insert(new Element("th", {"id" : "occurrenceTh"}).update("occurrence"), {"position" : "bottom"});
+		topicTable.insert(header, {"position" : "top"});
+		
+		// --- creates the topic summary data of the json object
+		if(topicSummaries !== null){
+		    topicSummaries.each(function(topicSummary, idx)
+					{
+					    var tr = new Element("tr");
+
+					    			    		    
+					    var itemIdentity = new Element("td", {"class" : "topicSummaryTd"});
+					    var ul = new Element("ul", {"class" : "topicTable"});
+					    itemIdentity.insert(ul, {"position" : "top"});
+					    if(topicSummary.itemIdentities){
+						topicSummary.itemIdentities.each(function(itemIdentityJ, innerIdx)
+										 {
+										     ul.insert(new Element("li").update(itemIdentityJ));
+										 });
+					    }
+					    
+					    var subjectLocator = new Element("td", {"class" : "topicSummaryTd"});
+					    ul = new Element("ul", {"class" : "topicTable"});
+					    subjectLocator.insert(ul, {"position" : "top"});
+					    if(topicSummary.subjectLocators){
+						topicSummary.subjectLocators.each(function(subjectLocatorJ, innerIdx)
+										  {
+										      ul.insert(new Element("li").update(subjectLocatorJ));
+										  });		    
+					    }
+
+					    var subjectIdentifier = new Element("td", {"class" : "topicSummaryTd"});
+					    ul = new Element("ul", {"class" : "topicTable"});
+					    subjectIdentifier.insert(ul, {"position" : "top"});
+					    if(topicSummary.subjectIdentifiers){
+						topicSummary.subjectIdentifiers.each(function(subjectIdentifierJ, innerIdx)
+										     {
+											 var li = new Element("li", {"class" : "clickable"}).update(subjectIdentifierJ);
+											 ul.insert(li);
+											 li.observe("click", function(event)
+												    {
+													var node = event.element();
+													makePage(PAGES.edit);//, node.textContent);
+												    });
+										     });
+					    }
+					    
+					    var instanceOf = new Element("td", {"class" : "topicSummaryTd"});
+					    ul = new Element("ul", {"class" : "topicTable"});
+						instanceOf.insert(ul, {"position" : "top"});
+					    if(topicSummary.instanceOfs){
+						topicSummary.instanceOfs.each(function(instanceOfJ, innerIdx)
+									      {
+										  if(instanceOfJ){
+											  instanceOfJ.each(function(psi, psiIdx)
+													  {
+													      ul.insert(new Element("li").update(psi));
+													  });
+										  }
+									      });
+					    }
+
+					    var name = new Element("td", {"class" : "topicSummaryTd"});
+					    ul = new Element("ul", {"class" : "topicTable"});
+					    name.insert(ul, {"position" : "top"});
+					    if(topicSummary.names){
+						topicSummary.names.each(function(nameJ, innerIdx)
+									{
+									    ul.insert(new Element("li").update(nameJ));
+									});
+					    }
+
+					    var occurrence = new Element("td", {"class" : "topicSummaryTd"});
+					    ul = new Element("ul", {"class" : "topicTable"});
+					    occurrence.insert(ul, {"position" : "top"});
+					    if(topicSummary.occurrences){
+						topicSummary.occurrences.each(function(occurrenceJ, innerIdx)
+									      {
+										  ul.insert(new Element("li").update(occurrenceJ));
+									      });
+					    }
+
+					    tr.insert(itemIdentity, {"position" : "bottom"});
+					    tr.insert(subjectLocator, {"position" : "bottom"});
+					    tr.insert(subjectIdentifier, {"position" : "bottom"});
+					    tr.insert(instanceOf, {"position" : "bottom"});
+					    tr.insert(name, {"position" : "bottom"});
+					    tr.insert(occurrence, {"position" : "bottom"});
+
+					    topicTable.insert(tr, {"position" : "bottom"});					    
+					});
+		}
+	    }
+
+	    // --- there was no data received or not all requested
+	    // --- so it's not allowed to increment the indices of the requested topics
+	    if(topicSummaries === null || topicSummaries.length != __idx.getTopicsPerPage()){
+		__idx.setOutOfRange(true);
+	    }
+	    else {
+		__idx.setOutOfRange(false);
+	    }
+
+	    // --- inserts the table in the parent element
+	    if($(parentId)){
+		$(parentId).insert(topicTable, {"position" : "top"});
+	    }
+	    createTableNavi(false);
+	}
+	catch(err){
+	    window.alert("got bad json data from: " + SUMMARY_URL + "\n\n" + err);
+	}
+    }
+
+
+    function onFailureHandler(xhr)
+    {
+	window.alert("something went wrong ...\n" + xhr.status + ": " + xhr.statusText);
+    }
+
+
+     // --- the real ajax request
+    new Ajax.Request(SUMMARY_URL,
+		     {"method" : "get",
+		      "onSuccess" : onSuccessHandler,
+		      "onFailure" : onFailureHandler,
+		      "parameters" : {"start" : __idx.getFirstIdx(), "end" : __idx.getLastIdx()}
+		     });
+}
\ No newline at end of file

Added: trunk/src/ajax/javascripts/ajax_navi.js
==============================================================================
--- (empty file)
+++ trunk/src/ajax/javascripts/ajax_navi.js	Wed Apr  1 05:41:52 2009
@@ -0,0 +1,49 @@
+// --- adds some event handlers to the navigation elements
+function addHandlersToNavi()
+{
+    $(PAGES.home).observe("click", function(){ makePage(PAGES.home, ""); });
+    $(PAGES.search).observe("click", function(){ makePage(PAGES.search, ""); });
+    $(PAGES.edit).observe("click", function(){	makePage(PAGES.edit, ""); });
+    $(PAGES.create).observe("click", function(){ makePage(PAGES.create, ""); });
+
+    // --- necessary for the first call of the page
+    makePage(PAGES.home);
+}
+
+
+// --- generates the current page depending on the variable __currentPage
+function makePage(newPage, psi)
+{
+    // --- removes the old content
+    cleanPage(newPage);
+
+    // --- creates the new content
+    switch(newPage){
+    case PAGES.home:
+	makeHome("content", "topicTable", true);
+	break;
+    case PAGES.search:
+	break;
+    case PAGES.edit:
+	makeEdit(psi);
+	break;
+    case PAGES.create:
+	break;
+    }
+}
+
+
+// --- removes all old DOM-Elements - if the page to create is not
+// --- the old page
+function cleanPage(newPage)
+{
+    $("content").childElements().each(function(nodeToDelete, idx)
+				      {
+					  if(!nodeToDelete.hasClassName(newPage))
+					      nodeToDelete.remove();
+				      });
+}
+
+
+document.observe("dom:loaded", addHandlersToNavi);
+

Modified: trunk/src/isidorus.asd
==============================================================================
--- trunk/src/isidorus.asd	(original)
+++ trunk/src/isidorus.asd	Wed Apr  1 05:41:52 2009
@@ -131,7 +131,18 @@
 							   (:static-file "scriptaculous.js")
 							   (:static-file "slider.js")
 							   (:static-file "sound.js")
-							   (:static-file "unittest.js")))))
+							   (:static-file "unittest.js")
+							   (:static-file "ajax_constants.js")
+							   (:static-file "ajax_home.js")
+							   (:static-file "ajax_navi.js")
+							   (:static-file "ajax_edit_topic.js")))
+				     (:module "css"
+					      :components ((:static-file "create_topics.css")
+							   (:static-file "edit_topics.css")
+							   (:static-file "home.css")
+							   (:static-file "navi.css")
+							   (:static-file "search_topics.css")
+							   (:static-file "main.css")))))
 	       )
 	       ;;(:module "threading"
 	       ;;	:components ((:file "reader-writer"))))

Modified: trunk/src/json/json_exporter.lisp
==============================================================================
--- trunk/src/json/json_exporter.lisp	(original)
+++ trunk/src/json/json_exporter.lisp	Wed Apr  1 05:41:52 2009
@@ -1,14 +1,20 @@
 (defpackage :json-exporter
   (:use :cl :json :datamodel)
   (:export :to-json-string
-	   :get-all-topic-psis))
+	   :get-all-topic-psis
+	   :to-json-string-summary
+	   :make-topic-summary))
 
 (in-package :json-exporter)
 
 ;; the json schema for our datamodel is in ".../docs/xtm_json.txt"
 
+
+;; =============================================================================
+;; --- main json data model ----------------------------------------------------
+;; =============================================================================
 (defgeneric to-json-string (instance &key xtm-id)
-  (:documentation "converts the Topic Maps construct instance to a json string"))
+  (:documentation "converts the Topic Map construct instance to a json string"))
 
 
 (defun identifiers-to-json-string (parent-construct &key (what 'd:psis))
@@ -130,7 +136,7 @@
 
 
 (defmethod to-json-string ((instance TopicC) &key (xtm-id d:*current-xtm*))
-  "transforms an OccurrenceC object to a json string"
+  "transforms an TopicC object to a json string"
   (let ((id
 	 (concatenate 'string "\"id\":\"" (topicid instance) "\""))
 	(itemIdentity
@@ -272,6 +278,9 @@
     (concatenate 'string "{" main-topic "," topicStubs "," associations "," tm-ids "}")))
 
 
+;; =============================================================================
+;; --- json data summeries -----------------------------------------------------
+;; =============================================================================
 (defun get-all-topic-psis()
   "returns all topic psis as a json list of the form
    [[topic-1-psi-1, topic-1-psi-2],[topic-2-psi-1, topic-2-psi-2],...]"
@@ -279,4 +288,56 @@
    (remove-if #'null (map 'list #'(lambda(psi-list)
 				    (when psi-list
 				      (map 'list #'uri psi-list)))
-			  (map 'list #'psis (elephant:get-instances-by-class 'TopicC))))))
\ No newline at end of file
+			  (map 'list #'psis (elephant:get-instances-by-class 'TopicC))))))
+
+
+(defun to-json-string-summary (topic)
+  "creates a json string of called topic element. the following elements are within this
+   summary:
+    *topic id
+    *all identifiers
+    *names (only the real name value)
+    *occurrences (jonly the resourceRef and resourceData elements)"
+  (declare (TopicC topic))
+  (let ((id
+	 (concatenate 'string "\"id\":\"" (topicid topic) "\""))
+	(itemIdentity
+	 (concatenate 'string "\"itemIdentities\":"
+		      (identifiers-to-json-string topic :what 'item-identifiers)))
+	(subjectLocator 
+	 (concatenate 'string "\"subjectLocators\":"
+		      (identifiers-to-json-string topic :what 'locators)))
+	(subjectIdentifier
+	 (concatenate 'string "\"subjectIdentifiers\":"
+		      (identifiers-to-json-string topic :what 'psis)))
+	(instanceOf
+	 (concatenate 'string "\"instanceOfs\":" (ref-topics-to-json-string (list-instanceOf topic))))
+	(name
+	 (concatenate 'string "\"names\":"
+		      (if (names topic)
+			  (json:encode-json-to-string (loop for name in (names topic)
+							 when (slot-boundp name 'charvalue)
+							 collect (charvalue name)))
+			  "null")))
+	(occurrence
+	 (concatenate 'string "\"occurrences\":"
+		      (if (occurrences topic)
+			  (json:encode-json-to-string (loop for occurrence in (occurrences topic)
+							 when (slot-boundp occurrence 'charvalue)
+							 collect (charvalue occurrence)))
+			  "null"))))
+    (concatenate 'string "{" id "," itemIdentity "," subjectLocator "," subjectIdentifier ","
+		 instanceOf "," name "," occurrence "}")))
+
+
+(defun make-topic-summary (topic-list)
+  "creates a json list of the produced json-strings by to-json-string-summary"
+  (if topic-list
+      (let ((json-string
+	     (let ((inner-string nil))
+	       (concatenate 'string
+			    (loop for topic in topic-list
+			       do (setf inner-string (concatenate 'string inner-string (to-json-string-summary topic) ","))))
+	       (subseq inner-string 0 (- (length inner-string) 1)))))
+	(concatenate 'string "[" json-string "]"))
+      "null"))
\ No newline at end of file

Modified: trunk/src/rest_interface/rest-interface.lisp
==============================================================================
--- trunk/src/rest_interface/rest-interface.lisp	(original)
+++ trunk/src/rest_interface/rest-interface.lisp	Wed Apr  1 05:41:52 2009
@@ -19,6 +19,7 @@
 	   :*json-get-prefix*
 	   :*json-commit-url*
 	   :*json-get-all-psis*
+	   :*json-get-summary-prefix**
 	   :*ajax-user-interface-url*
 	   :*ajax-user-interface-file-path*
 	   :*ajax-javascript-directory-path*

Modified: trunk/src/rest_interface/set-up-json-interface.lisp
==============================================================================
--- trunk/src/rest_interface/set-up-json-interface.lisp	(original)
+++ trunk/src/rest_interface/set-up-json-interface.lisp	Wed Apr  1 05:41:52 2009
@@ -3,7 +3,10 @@
 (defparameter *json-get-prefix* "/json/get/(.+)$") ;the prefix to get a fragment by the psis -> localhost:8000/json/get/<fragment-psi>
 (defparameter *json-commit-url* "/json/commit/?$") ;the url to commit a json fragment by "put" or "post"
 (defparameter *json-get-all-psis* "/json/psis/?$") ;the url to get all topic psis of isidorus -> localhost:8000/json/psis
-(defparameter *ajax-user-interface-url* "/isidorus/?$") ;the url to the user interface -> localhost:8000/isidorus
+(defparameter *json-get-summary-url* "/json/summary/?$") ;the url to get a summary od all topic stored in isidorus; you have to set the GET-parameter "start" for the start index of all topics within elephant and the GET-paramter "end" for the last index of the topic sequence -> http://localhost:8000/json/summary/?start=12&end=13
+(defparameter *ajax-user-interface-url* "/isidorus/?$") ;the url to the user interface; if you want to get all topics set start=0&end=nil -> localhost:8000/isidorus
+(defparameter *ajax-user-interface-css-prefix* "/css") ;the url to the css files of the user interface
+(defparameter *ajax-user-interface-css-directory-path* "ajax/css") ;the directory contains the css files
 (defparameter *ajax-user-interface-file-path* "ajax/isidorus.html") ;the file path to the HTML file implements the user interface
 (defparameter *ajax-javascript-directory-path* "ajax/javascripts") ;the directory which contains all necessary javascript files
 (defparameter *ajax-javascript-url-prefix* "/javascripts") ; the url prefix of all javascript files
@@ -12,19 +15,31 @@
 (defun set-up-json-interface (&key (json-get-prefix *json-get-prefix*)
 			      (json-get-all-psis *json-get-all-psis*)
 			      (json-commit-url *json-commit-url*)
+			      (json-get-summary-url *json-get-summary-url*)
 			      (ajax-user-interface-url *ajax-user-interface-url*)
 			      (ajax-user-interface-file-path *ajax-user-interface-file-path*)
+			      (ajax-user-interface-css-prefix *ajax-user-interface-css-prefix*)
+			      (ajax-user-interface-css-directory-path *ajax-user-interface-css-directory-path*)
 			      (ajax-javascripts-directory-path *ajax-javascript-directory-path*)
 			      (ajax-javascripts-url-prefix *ajax-javascript-url-prefix*))
   "registers the json im/exporter to the passed base-url in hunchentoot's dispatch-table
    and also registers a file-hanlder to the html-user-interface"
-  (declare (string json-get-prefix json-get-all-psis json-commit-url ajax-user-interface-url ajax-user-interface-file-path))
+  ;; === html and css files ====================================================
   (push
    (create-regex-dispatcher ajax-user-interface-url
 			    #'(lambda()
 				(hunchentoot:handle-static-file ajax-user-interface-file-path "text/html")))
    hunchentoot:*dispatch-table*)
-  ;; === ajax frameworks =======================================================
+
+  (dolist (script-path-and-url (make-file-path-and-url ajax-user-interface-css-directory-path ajax-user-interface-css-prefix))
+    (let ((script-path (getf script-path-and-url :path))
+	  (script-url (getf script-path-and-url :url)))
+      (push (create-regex-dispatcher script-url
+				     #'(lambda()
+					 (hunchentoot:handle-static-file script-path))); "text/javascript")))
+	    hunchentoot:*dispatch-table*)))
+
+  ;; === ajax frameworks and javascript files ==================================
   (dolist (script-path-and-url (make-file-path-and-url ajax-javascripts-directory-path ajax-javascripts-url-prefix))
     (let ((script-path (getf script-path-and-url :path))
 	  (script-url (getf script-path-and-url :url)))
@@ -32,7 +47,8 @@
 				     #'(lambda()
 					 (hunchentoot:handle-static-file script-path))); "text/javascript")))
 	    hunchentoot:*dispatch-table*)))
-  ;; === ajax frameworks end ===================================================
+
+  ;; === rest interface ========================================================
   (push
    (create-regex-dispatcher json-get-all-psis #'return-all-topic-psis)
    hunchentoot:*dispatch-table*)
@@ -41,6 +57,9 @@
    hunchentoot:*dispatch-table*)
   (push
    (create-regex-dispatcher json-commit-url #'json-commit)
+   hunchentoot:*dispatch-table*)
+  (push
+   (create-regex-dispatcher json-get-summary-url #'return-topic-summaries)
    hunchentoot:*dispatch-table*))
 
 
@@ -101,15 +120,54 @@
 	(setf (hunchentoot:return-code*) hunchentoot:+http-bad-request+))))
 
 
-(defun make-file-path-and-url (path-to-javascripts url-prefix)
+(defun return-topic-summaries(&optional param)
+  "returns a summary of the requested topics"
+  (declare (ignorable param))
+  (let ((start-idx 
+	 (handler-case (parse-integer (hunchentoot:get-parameter "start"))
+	   (condition () 0)))
+	(end-idx
+	 (handler-case (parse-integer (hunchentoot:get-parameter "end"))
+	   (condition () nil))))
+
+    (let ((topics (elephant:get-instances-by-class 'd:TopicC)))
+      (let ((end
+	     (cond
+	       ((not end-idx)
+		(length topics))
+	       ((> end-idx (length topics))
+		(length topics))
+	       ((< end-idx 0)
+		0)
+	       (t
+		end-idx))))
+	(let ((start
+	       (cond
+		 ((> start-idx (length topics))
+		  end)
+		 ((< start-idx 0)
+		  0)
+		 (t
+		  start-idx))))
+	  (let ((topics-in-range
+		 (if (<= start end)
+		     (subseq topics start end)
+		     (reverse (subseq topics end start)))))
+	    (setf (hunchentoot:content-type*) "application/json") ;RFC 4627
+	    (json-exporter:make-topic-summary topics-in-range)))))))
+
+
+;; =============================================================================
+;; --- some helper functions ---------------------------------------------------
+;; =============================================================================
+(defun make-file-path-and-url (path-to-files-directory url-prefix)
   "returns a list of lists which contains an absolute file path and a file-url
    concatenated of the url-prefix and the relative path of all all files in the
    passed directory and its subdirectories"
-  (declare (string path-to-javascripts url-prefix))
   (let ((start-position-of-relative-path
-	 (- (length (write-to-string (com.gigamonkeys.pathnames:file-exists-p path-to-javascripts))) 2)))
+	 (- (length (write-to-string (com.gigamonkeys.pathnames:file-exists-p path-to-files-directory))) 2)))
     (let ((files-and-urls nil))
-      (com.gigamonkeys.pathnames:walk-directory path-to-javascripts
+      (com.gigamonkeys.pathnames:walk-directory path-to-files-directory
 						#'(lambda(current-path)
 						    (let ((current-path-string
 							   (write-to-string current-path)))




More information about the Isidorus-cvs mailing list