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)))