[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