TopicGenerator

From BITPlan cr Wiki
Jump to navigation Jump to search

dialog

@// Copyright (c) 2016 BITPlan GmbH
@// 
@// This is a Wikitask / Rythm template that
@// displays an AJAX GUI for generating SmartMediaWiki results
@// 
@import org.sidif.wiki.Reference
@import org.sidif.wiki.ReferenceManager
@import org.sidif.wiki.Source
@import org.sidif.wiki.PageCache
@import org.sidif.wiki.WikiTask
@import com.bitplan.mediawiki.japi.api.Page
@import com.bitplan.mediawiki.japi.api.Rev
@include(wiki.SiDIFTemplates.defs)
@include(wiki.SiDIFTemplates.dialogdefs)
@// get a link for the given pagetitle
@def String getLink(String pageTitle, int revid) {
  String link=wikiTask.getServer()+wikiTask.getScriptpath()+"/index.php?title="+urlEncode(pageTitle);
  if (revid>0) {
    link+="&oldid="+revid;
  }
  return link;
}
@// get the parameters for the wikitask
@def String getWikiTaskParams(String engine) {
  String params="?server="+urlEncode(wikiTask.getServer());
  params+="&scriptpath="+urlEncode(wikiTask.getScriptpath());
  params+="&page="+urlEncode(wikiTask.getPageTitle());
  params+="&engine="+engine;
  return params;
}
@// run the given wikitask command
@def doWikiTaskCmd(String cmd, String param) {
@{ 
  String icon="component";
  String engine="Freemarker";
  if ("runtemplate".equals(cmd)){ icon="media_play_green.png"; }
  if ("reset".equals(cmd))      { icon="refresh"; }
  if ("help".equals(cmd))       { icon="help"; }
  if ("debug".equals(cmd))      { icon="wrench"; }
  if ("refreshRef".equals(cmd)) { icon="refresh"; }
  String params=getWikiTaskParams(engine);
}
  <a href='@(cmd)@(params)'>@(stockicon(icon,48,cmd,cmd))</a>
}
@// run the given wikitask command
@def wikiTaskCmd(String cmd) {
  @doWikiTaskCmd(cmd,null)
}
@// run the given wikitask command with a parameter
@def wikiTaskCmd(String cmd, String param) {
  @doWikiTaskCmd(cmd,param)
}
@// add styles for the generator
@def generatorStyle(String i_____) {
@(i_____)  <style type="text/css">
@(i_____)    // progress text that comes with progress bars
@(i_____)    // see http://stackoverflow.com/questions/12452594/how-can-i-add-label-inside-a-progress-bar-tag
@(i_____)    span.progresstext {
@(i_____)    font-family:'Arial';
@(i_____)    position:relative;
@(i_____)    top:-1.5em;
@(i_____)    margin-left:50%;;
@(i_____)    font-size:small;
@(i_____)  }
@(i_____)  </style>
}
@// scripts for generators
@def generatorScript() {    
<script>      
       // JavaScript support for Y-Principle TopicGenerator
       // convert a string to make the first char lower case
       function firstToLower(string) {
         return string.charAt(0).toLowerCase() + string.slice(1);
       } 
       // get the div where responses are shown
       function getResponseDiv() {
         var result=document.getElementById("response");
         return result;
       }
       // get the div where errors are shown
       function getErrorDiv() {        
         var result=document.getElementById("errorMessage");
         return result;
       }
 
       // get the checkBox jquery object with the given id
       function getGeneratorElement(generatorId,postfix) {
         var result=$("#"+generatorId+postfix);
         return result;
       }
       // clear the given div
       function clearDiv(div) {
         div.innerHTML='';
       }
       // add a TextElement with the given tag and message to the given parent
       function newTextElement(tag,msg) {
       	 var newElement=document.createElement(tag);
         var content = document.createTextNode(msg);
         newElement.appendChild(content);
         return newElement;
       }
       // add a message to the given div
       function addMessage(div, msg) {
       	 var newElement=newTextElement('pre',msg);
       	 div.appendChild(newElement);
       	 return newElement;
       }
       // progress on transfers from the server to the client (downloads)
       // see https://developer.mozilla.org/de/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
       function updateProgress (oEvent) {
         if (oEvent.lengthComputable) {
           var percentComplete = oEvent.loaded / oEvent.total;
           // ...
         } else {
           // Unable to compute progress information since the total size is unknown
         }
       }
       // show an error Message
       // param errMsg: the message to show
       function errorMessage(errMsg) {
         var errDiv=getErrorDiv();
         if (errDiv!=null) {
           addMessage(errDiv,errMsg);
           errDiv.style.display = 'block';
         } else {
           alert(errMsg); 
         }
       }
       // flag an error for the given id
       function flagError(id,msg) {
       	 setProgress(id,0,"");
         var checkBox=getGeneratorElement(id,"");
         var progresstext=getGeneratorElement(id,"_progress_pc");
         var errorSpan=newTextElement('span',' '+msg);
         errorSpan.style='color:red;font-size:14px';
         progresstext[0].appendChild(errorSpan);
         return checkBox;
       }
       // handle an error that has been thrown
       function handleError(err,id) {
       	 flagError(id,err.message);
       	 // abusing checkBox as data lookup 
       	 var checkBox=getGeneratorElement(id,"");
       	 var errMessage=checkBox[0].name+" ERROR:"+err.code+" "+err.name+" '"+err.message+"' line:"+err.lineNumber;
       	 errorMessage(errMessage);
       }
       // get the class name of the given object
       function getClass(obj) {
         if (typeof obj === "undefined")
           return "undefined";
         if (obj === null)
           return "null";
         return Object.prototype.toString.call(obj)
           .match(/^\[object\s(.*)\]$/)[1];
       }
       // send the given form
       function sendForm(formData,action,id) {
         try {
           var oReq = new XMLHttpRequest();
           oReq.addEventListener('progress', updateProgress, false);
           oReq.addEventListener('load', transferComplete, false);
           oReq.addEventListener('error', transferFailed, false);
           oReq.addEventListener('abort', transferCanceled, false);
           oReq.onload = ajaxSuccess;
           // http://stackoverflow.com/questions/921198/get-request-url-from-xhr-object
           var xhrProto = XMLHttpRequest.prototype,
           origOpen = xhrProto.open;
 
           xhrProto.open = function (method, url, async) {
             this._url = url;
             this._id = id;
             return origOpen.apply(this,arguments);
           };
           var async=true;
           oReq.open('POST', action, async,id);
           // important - this makes the request a non-simple request with CORS
           // oReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
           // user defined header forces CORS?
           oReq.setRequestHeader('Header-Custom-WikitaskCORS', 'OK');
           oReq.setRequestHeader('Accept','application/json');
           oReq.send(formData);
         } catch(err) {
           handleError(err,id);
         }
         return false; // Prevent direct form page button submit action
       }
       // set the progress for the given check box id
       // and return the progress bar
       function setProgress(checkBoxId,progress,percent) {
         var checkBox=getGeneratorElement(checkBoxId,"");
         var progressbar=getGeneratorElement(checkBoxId,"_progress");
         var progresstext=getGeneratorElement(checkBoxId,"_progress_pc");
         // console.log(progressbar);
         // FIXME - do a true progress
         // progressbar.val(progress);
         if (progress==0) {
           progressbar[0].style.display = 'none';
         } else {
           progressbar[0].style.display = 'block';
         }
         progresstext[0].textContent=percent;
         return progressbar;
       }
       // start the generator for the given form, contextSetting, contextname, template and targetpage
       function startGenerator(form,contextSettingTxt,contextname,topic,template,targetpage,id) {
         var formData = new FormData(form);
         formData.append('server', "@(wikiTask.getServer())");
         formData.append('scriptpath', "/@(wikiTask.getScriptpath())");
         formData.append('engine', 'Rythm');
         formData.append('input', 'sidif');
         formData.append('page','Topic');
         var action=form.action;
         // action=
         // action="http://phobos.bitplan.com:9089/wikiserver/task/runtemplate";
         formData.append('template',template);
         formData.append('targetpage',targetpage);
         formData.append('id',id);
         // set the params from the contextSettings
         // e.g. wikiId:capri,sidifInput:Topic#sidif,contextName:MetaModel,maintopicName:Topic
         var contextSetting=JSON.parse(contextSettingTxt);
         contextSetting.maintopicName=topic;
         var contextSettingJson=JSON.stringify(contextSetting)
         formData.append('params',contextSettingJson);
         sendForm(formData,action,id);
       }
       // start the generators for the given form
       function startGenerators(form) {
         clearDiv(getErrorDiv());
         clearDiv(getResponseDiv());
 
         var generatorchecks= $(".checkBoxClass:checked");
         generatorchecks.each(function(){
           setProgress(this.id,1,"");
           // targetPage is the name of the checkbox
           var template=this.value;
           var ytname=$(this).attr("yt")
           var target=$(this).attr("target");
           var contextname=$(this).attr("context");
           var contextSetting=$(this).attr("contextsetting");
           var id=this.id;
           // split e.g. Template_Context;
           var split = id.split('__');
           // FIXME use yt and topic and generator objects instead
           var topic=split[1]; 
           startGenerator(form,contextSetting,contextname,topic,template,target,id);
         });
         return false;
       }
       // get SiDIF
       function getSiDIF(lbutton) {
         // {{wikitask
         // |cmd=runtemplate
         // |engine=Rythm
         // |input=sidif
         // |dialog=TopicGenerator#dialog
         // |template=TopicGenerator#template
         // |params=tripleStoreMode:SMW,contextName:{{{context|}}}
         // |targetpage=TopicGenerator2015/{{{context|}}}}}
         var contextSetting=JSON.parse(lbutton.value);
         var params='@(getWikiTaskParams("Rythm"))';
         var wikiTaskLink="runtemplate"+params;
         wikiTaskLink+="&input="+encodeURIComponent(contextSetting.sidifInput);
         wikiTaskLink+="&dialog="+encodeURIComponent("TopicGenerator#dialog");
         wikiTaskLink+="&template="+encodeURIComponent("TopicGenerator#template");
         wikiTaskLink+="&targetpage="+encodeURIComponent("TopicGenerator2015/"+contextSetting.contextName);
         wikiTaskLink+="&params=tripleStoreMode:"+contextSetting.tripleStoreMode;
         wikiTaskLink+=",contextName:"+encodeURIComponent(contextSetting.contextName);
         wikiTaskLink+=",sidifInput:"+encodeURIComponent(contextSetting.sidifInput);
         // console.log(wikiTaskLink);
         window.location.replace(wikiTaskLink);
       }
       // show the given event with the given message
       function showEvent(evt, msg) {
       	 var doshow=true;
         if (evt.target instanceof XMLHttpRequest) {
           var xhr=evt.target;
           msg+=" target="+xhr._url;
           msg+=" responseType="+xhr.responseType;
           msg+=" status="+xhr.status;
           if (xhr.status==200) {
             doshow=false;
           }
         }
         if (doshow) {
           errorMessage(evt.type+" "+getClass(evt.target)+": "+msg);
         }
         return evt.target;
       }
       // event when the transfer was successfully completed
       function ajaxSuccess () {
         var json=this.responseText;
         // console.log(json);
         try {
           var jsonResult=JSON.parse(json);  
           // console.log(jsonResult);
           var errorMsg=jsonResult.errorMsg;
           if (errorMsg!=null) {
             setProgress(jsonResult.id,100,"");
             addMessage(getResponseDiv(),errorMsg);
           } else {
             setProgress(jsonResult.id,0,"");
             var checkBox=getGeneratorElement(jsonResult.id,"");
             var progresstext=getGeneratorElement(jsonResult.id,"_progress_pc");
             var target=$("#"+jsonResult.id).attr("target");
             var targetRef=newTextElement('a',target);
             targetRef.href=jsonResult.targetUrl;
             targetRef.style='font-size:12px';
             var doneSpan=newTextElement('span','✓');
             doneSpan.style='color:green;font-size:14px';
             progresstext[0].appendChild(targetRef);
             progresstext[0].appendChild(doneSpan);
             var deltaRef=newTextElement('a','Δ');
             deltaRef.style='font-size:12px';
             var revid=$("#"+jsonResult.id+"_rev").attr("revid");
             deltaRef.href=jsonResult.targetUrl+"?diff=cur&oldid="+revid;
             progresstext[0].appendChild(deltaRef);
           }
         } catch (ex) {
            alert(ex.message+"\njson="+json);
         }
       }
       // event when transfer is complete
       function transferComplete(evt) {
         showEvent(evt,"transfer complete");
       }
       // event when the transfer failed
       function transferFailed(evt) {
         var xhr=showEvent(evt,"transfer failed");
         if (xhr instanceof XMLHttpRequest) {
         	 flagError(xhr._id,"transfer failed");
         }
       }
       // event when the transer was cancelled
       function transferCanceled(evt) {
         showEvent(evt,"transfer canceled");
       }
     </script>
}
@// run the selected generators
@def runGenerators() {
@{
  String icon="media_play_green";
  String cmd="run";
}
    <button type='submit' name='@cmd' value='@cmd' title='@cmd' onclick="return startGenerators(this.form);">
      @(stockicon(icon,32,cmd,cmd))
    </button>
}
@// display the given Reference as a row
@def referenceRow(Reference ref) {
<tr>
  <td>@(wikiTaskCmd("refreshRef",ref.getReferenceId()))</td>
  <td><a href='@(ref.getUrl())'>@(ref.getReferenceId())</a></td>
  <td>@(ref.getReferenceType().toString())</td>
  <td>@(ref.getAge())</td>
  <td>@(ref.isAvailable())</td>
  <td>@if(ref.getContent()) { @(ref.getContent().length()) } else { - }</td>
</tr>
}
@// display the given Source as a row
@def sourceRow(Source source) {
      <tr><td></td><td>@(source.getId())</td><td>@(source.getPageTitle())</td><td>@(source.getAge())</td><td>@(source.isCache())</td><td>@(source.getSource().length())</td></tr>
}
@// display the table of PageCache entries 
@def pageCacheTable(PageCache pageCache,String indent) {
@(indent)<table class="table tablesorter sortable">
@(indent)<thead>
@(indent)  <tr><th>page</th><th>rev</th><th>timestamp</th></tr>
@(indent)</thead>
@(indent)<tbody>
@{
  List<String> pageTitles = new ArrayList<String>(pageCache.getCachedPages().keySet());
}
@for (String pageTitle:pageTitles) {
@{
  Page page=pageCache.getCachedPages().get(pageTitle);
  Rev rev = PageCache.getPageRevision(page);
  int revid=-1;
  String timeStamp="?";
  if (rev!=null)  {
    revid=rev.getRevid();
    timeStamp=rev.getTimestamp();
  }
}
@(indent)  <tr><td>@showLink(pageTitle, 0, "Cache0_"+revid, "")</td><td>@showLink(pageTitle, revid, "Cache_"+revid, "")</td><td>@(timeStamp)</td></tr>
}
@(indent)</tbody>
@(indent)</table>
}
@// display the table of references and sources
@def referenceTable(ReferenceManager rm) {
           <table class="table tablesorter sortable">
              <thead>
                <tr><th></th><th>id</th><th>type</th><th>age</th><th>cache</th><th>size</th></tr>
              </thead>
              <tbody>
                @for (Reference reference:rm.referenceByReferenceId.values()) {
                  @referenceRow(reference)
                  @if (rm.getSourceById().get(reference.getReferenceId())!=null) {
                    <tr><th colspan='3'>Sources by Id</th>
                    @for (Source source:wikiTask.referenceManager.getSourceById().get(reference.getReferenceId()).values()) {
                      @sourceRow(source)
                    }   
                  }
                  @if (rm.getSourceBySection().get(reference.getAnchor())!=null) {
                    <tr><th colspan='3'>Sources by Section</th>
                    @for (Source source:wikiTask.referenceManager.getSourceBySection().get(reference.getAnchor()).values()) {
                      @sourceRow(source)
                    }   
                  }
                }
              </tbody>           
           </table>
}
@// show a link for the given pageTitle and revision id
@def showLink(String pageTitle,int revid, String id, String indent) {
@{
  // default is unknown revision red link / create page approach
  String revname="click to create";
  String style="style='color:red'";
  if (revid>=0) {
    style="style='font-size: 12px'"; // normal link but small font
    revname="Rev "+revid;
  }
  String link=getLink(pageTitle,revid);
}
@(indent)<a href='@(link)' id='@(id)' revid='@(revid)' title='@(revname)' @(style)>@(pageTitle)</a>
}
@// show the page status link
@def pageStatusLink(Topic topic,YT yt,Map<String, Page> statusMap) {
@{
  String pageTitle=yt.getPageTitle(topic);
  Page page=statusMap.get(pageTitle);
  int revid = -1;
  if (page != null) {
    Rev rev = PageCache.getPageRevision(page);
    if (rev!=null) {
      revid = rev.getRevid();
    }
  }
}
  @showLink(pageTitle, revid, yt.name+"__"+topic.name+"_rev", "             ") 
}
@// show a single row of generators for a given domain topic
@def topicRow(ContextSetting contextSetting,Context context,Topic topic,Map<String, Page> statusMap,YT[] yts, int rownum) {
        <tr>
          <th>@(topic.name)<div style="margin: 0 auto; width: 48px"><img src='@(wikiTask.getServer())@(wikiTask.getScriptpath())@(topic.iconUrl)' alt='@(topic.name)'></div></th><th><label><input class='checkboxSelect' type='checkbox' id="select_row_@(rownum)" title='select row'/></label></th>
      @{ int colnum=0;}
      @for(YT yt:yts) {
          <td>
            <label for='@(yt.name)_@(topic.name)'>
              <input type="checkbox" class="checkBoxClass row_@(rownum) col_@(colnum)" contextsetting='@contextSetting.toJson()' context='@(context.name)' target='@yt.getPageTitle(topic)' yt='@(yt.name)' topic='@(topic.name)' id='@(yt.name)__@(topic.name)' name='@(yt.name):@(topic.name)' title='generate @(yt.getPageTitle(topic))' value="SiDIFTemplates#@(yt.template)">
            </label>
          </td>
          <td>
             @pageStatusLink(topic,yt,statusMap)
             <progress id='@(yt.name)__@(topic.name)_progress' max='10' title='@(yt.name):@(topic.name)' style='display:none'></progress>
             <span id='@(yt.name)__@(topic.name)_progress_pc' class='progresstext'></span>
          </td>
        @{ colnum++;}
      }
        </tr>
}
@// display the generators
@// sortable disabled - doesn't seem to work with selectAll logic
@def showGeneratorTasks(WikiTask wikiTask,ContextSetting contextSetting) {
@{ 
  Context context=ContextFactory.getInstance().getContext(contextSetting);
  List<String> pageTitles = new ArrayList<String>();
  if (context!=null) {
    for (YT yt : YT.yts) {
      for (Topic topic : context.getTopics()) {
        pageTitles.add(yt.getPageTitle(topic));
      }
    }
  }
  Map<String, Page> statusMap = wikiTask.referenceManager.getPageCache()
        .updatePageStatus(pageTitles, true);
}
  <h3>@(contextSetting.getTripleStoreMode())</h3>
@if (context) {
  <form action='#'>
    <table class="table tablesorter tablesorter-blue">
      <thead>
        <tr>
          <th width='12%'>@(runGenerators())</th>
          <th>Targets
          </th>
    @for(YT yt:YT.yts) {
          <th colspan='2' style="text-align:center">@(yt.label)</th>
    }
        </tr>
    @{ int colnum=0;}
        <tr>
          <th class='{sorter: false}'>Topics<br>
            <div id='reloadbuttoncontainer' style='width:80px;display:inline-block' >
	      <button onclick='getSiDIF(this);return false;' value='@ContextSetting.fromWikiTaskAsSiDIF(wikiTask).toJson()'  title='reload from SiDIF' style='display:inline-block'>
	        <img src='/stockicons/16x16/shadow/arrow_down_blue.png'/>
	      </button>
	      <button onclick='getSiDIF(this);return false;' value='@contextSetting.asSMWContextSetting().toJson()' title='reload from SMW Triples' style='display:inline-block' >
	        <img src='/stockicons/16x16/shadow/arrow_down_green.png'/>
	      </button>
	    </div>
          </th>
          <th class='{sorter: false}'><label><input type="checkbox" id="selectall" name="selectall" title='select all'/></label></th>
   @for(YT yt:YT.yts) {
          <th class='{sorter: false}' width='14px'><label><input class='checkboxSelect' type='checkbox' id='select_col_@(colnum)' title='select all @(yt.label)'/></label></th><th width='10%'><div style="margin: 0 auto; width: 48px"><img src='@(wikiTask.getServer())@(wikiTask.getScriptpath())@(yt.iconUrl)' alt='@(yt.label)'></div></th>
        @{ colnum++;}
   }
        </tr>
      </thead>
      <tbody id='generatortasktable'>
    @{ int rownum=0;}
    @for (Topic topic:context.getTopics()) { 
      @topicRow(contextSetting,context,topic,statusMap,YT.yts,rownum++)
    }
      </tbody>
    </table>
  </form>
}
}
@// show the HTML Page for the given context
@def showHtml(ContextSetting contextSetting) {
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
    <title>@(title)</title>
@jquery("    ")
@style("    ")
@selectall()
@generatorStyle("    ")
@generatorScript()
  </head>
  <body>
     <div id='container' class='container'>
       <div id="dialog" title="@(title)" >
         @(wikiTaskCmd("reset"))@(wikiTaskCmd("help"))@(wikiTaskCmd("debug"))
         <a href='@(wikiTask.getTargetLink().getUrl())'>@(wikiTask.getTargetpage())</a>
         called from <a href='@(wikiTask.getServer())@(wikiTask.getScriptpath())/index.php/@(wikiTask.getPageTitle())'>@(wikiTask.getPageTitle())</a> (@(wikiTask.getDuration()) msecs)
         <div id="tabs">
           <ul>
             <li><a href="#generators">Generators</a></li>
             <li><a href="#pagecache">Page-Cache</a></li>
             <li><a href="#references">References</a></li>
           </ul>
           <div id="generators">
             @(showGeneratorTasks(wikiTask,contextSetting))
           </div>
           <div id="pagecache">
             @pageCacheTable(wikiTask.referenceManager.getPageCache(),"        ")
           </div>
           <div id="references">
             @referenceTable(wikiTask.referenceManager)
           </div>
        </div>
        <div id='errorMessage' style='color:red;font-size: 14px;border:1px solid red;display:none'></div>
        <div id='response' style='font-size: 14px;border:1px solid blue'></div>
       </div>
     </div>
     @dialog("     ")
   </body>
</html>
}
@{
  ContextSetting contextSetting=ContextSetting.fromWikiTask(wikiTask);
}
@showHtml(contextSetting)

template

@include(wiki.SiDIFTemplates.defs)
@// handle error
@def handleError(Throwable error) {
error @(error.getClass().getName()): @(error.getMessage())
=== stacktrace ===
<pre>
@getStackTrace(error)
</pre>
}
@{
  ContextSetting contextSetting=ContextSetting.fromWikiTask(wikiTask);
  Context context=ContextFactory.getInstance().getContext(contextSetting);
  Context smwContext=ContextFactory.getInstance().getContext(contextSetting.asSMWContextSetting());
  String contextName=contextSetting.getContextName();
}
@if (context==null) {
Context (sidif): @(contextName) not found in SiDIF
} else {== SiDIF ==
=== @(contextName) SiDIF ===
<pre>
@(context.asSiDIF())
</pre>
=== @(contextName) JSON ===
<pre>
@(context.toJson())
</pre>
}
@if (smwContext==null) {
Context (smw): @(contextName) not found in SMW triples of Wiki
} else {
== SMW ==
=== @(contextName) SiDIF ===
<pre>
@(smwContext.asSiDIF())
</pre>
=== @(contextName) JSON ===
<pre>
@(smwContext.toJson())
</pre>
}