OPENNLP-480 Added first draft of simple web demo.
diff --git a/tagging-server/src/main/resources/htmls/annotation-editor.js b/tagging-server/src/main/resources/htmls/annotation-editor.js
new file mode 100644
index 0000000..6a811a9
--- /dev/null
+++ b/tagging-server/src/main/resources/htmls/annotation-editor.js
@@ -0,0 +1,94 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+function Annotation(type, id, begin, end) {
+ this.type = type;
+ this.id = id;
+ this.begin = begin;
+ this.end = end;
+};
+
+Annotation.prototype.length = function() {
+ return this.end - this.begin;
+};
+
+function AnnotationEditor(parentElement, tokens, annotations) {
+ this.parentElement = parentElement;
+ this.annotations = new Array();
+ this.tokens = tokens;
+
+ // Render tokens
+ for (var i = 0, token; token = this.tokens[i++];) {
+ this.parentElement.append("<span class=token id=token" +
+ (i - 1) + ">" + token + "</span>");
+ }
+
+ // Insert annotation after annotation
+ for (var i = 0, annotation; annotation = annotations[i++];) {
+ this.addAnnotation(annotation);
+ }
+};
+
+// Annotation Model:
+// - All annotation indexes are token indexes
+// - Annotations can contain other annotations.
+// - Annotations which cross each other or intersect with each other are not allowed
+// for example A <START_1> B <START_2> C <END_1> D E <END_2>.
+
+AnnotationEditor.prototype.addAnnotation = function(annotation) {
+
+ // TODO: Do crossing annotation detection and fail if they do! (return false or fail harder!)
+
+ // Note:
+ // If an annotation span with the same bounds already exist the new annotation
+ // span is placed inside the existing one
+ $(".token").slice(annotation.begin, annotation.end).wrapAll("<span class=" + annotation.type +
+ " id=" + annotation.type + annotation.id + ">");
+
+ this.annotations.push(annotation);
+};
+
+AnnotationEditor.prototype.removeAnnotation = function(annotationId) {
+ $("#" + annotationId).unwrap();
+};
+
+
+// Selection handling and navigation depends highly
+// on the annotation task. There is no default way of
+// doing it which fits all tasks.
+// Therefore we should implement a few default tools which
+// can be registered if required.
+
+// Registers a previous and forward key shortcuts to navigate based on span types.
+// Multiple span types can be passed in and optionally a function to choose a
+// span to select in case it is ambiguous.
+AnnotationEditor.prototype.setNavigationBySpanTypeKeys = function(spanType, previousKey, nextKey) {
+};
+
+// Registers a previous and forward key shortcuts to navigate with the help of a span locator function.
+AnnotationEditor.prototype.setNavigationByFunctionKeys = function(previousKey, nextKey, spanLocator){
+};
+
+
+// If a user clicks with a mouse on something he expects a reaction
+// It should be possible to register a function which helps dealing with
+// such a selection in a default way
+
+// e.g. user wants to select a few tokens
+// e.g. user wants to select a named entity annotation
+// He likely wants to do both in the same AnnotationEditor instance.
+// Span type priority could help with this (also for navigation)
+
diff --git a/tagging-server/src/main/resources/htmls/index.html b/tagging-server/src/main/resources/htmls/index.html
new file mode 100644
index 0000000..e239ed3
--- /dev/null
+++ b/tagging-server/src/main/resources/htmls/index.html
@@ -0,0 +1,65 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+
+<html>
+<head>
+<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.js"></script>
+<script type="text/javascript" src="annotation-editor.js"></script>
+<script type="text/javascript" src="opennlp-demo.js"></script>
+<style>
+ .token {PADDING-LEFT: 3px; PADDING-RIGHT: 3px;}
+ .person {color:brown;}
+ .location {color: green;}
+
+ #opennlp-demo {
+ min-height: 12.1em;
+ }
+
+ #opennlp-demo-language {
+ position: relative;
+ top: 0;
+ }
+
+ #opennlp-demo-input {
+ width: 49.999%;
+ height: 100px;
+ float: left;
+ position: relative;
+ resize: none;
+ }
+
+ #opennlp-demo-result {
+ width: 49.999%;
+ height: 100px;
+ left: 50%;
+ position: relative;
+ background: whiteSmoke;
+ }
+</style>
+
+<script type="text/javascript">
+ $(document).ready(function() {
+ $("div#opennlp-demo").opennlpDemo('namefinder');
+ });
+</script>
+</head>
+<body>
+ <div id="opennlp-demo"></div>
+</body>
+</html>
diff --git a/tagging-server/src/main/resources/htmls/opennlp-demo.js b/tagging-server/src/main/resources/htmls/opennlp-demo.js
new file mode 100644
index 0000000..545b9a6
--- /dev/null
+++ b/tagging-server/src/main/resources/htmls/opennlp-demo.js
@@ -0,0 +1,108 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+(function( $ ){
+
+ function insertDemoElements( element ) {
+ element.append('<select id="opennlp-demo-language"></select>');
+ element.append('<div id="input-output">');
+ element.append('<textarea id="opennlp-demo-input"></textarea>');
+ element.append('<div id="opennlp-demo-result"></div>');
+ element.append('</div>');
+ element.append('<button id="opennlp-demo-process">Process</button>');
+ };
+
+ function detectLanguage( componentName ) {
+
+ // TODO:
+ // Query name finder tagging service for supported languages
+ // Try to auto detect language in the background (every time input changed)
+
+ // For now lets hard code English
+ $('select#opennlp-demo-language').append('<option value="en">English</option>');
+ };
+
+ var methods = {
+
+ namefinder : function( options ) {
+ insertDemoElements(this);
+
+ // Can we get the method name here?
+ detectLanguage('namefinder')
+
+ $('button#opennlp-demo-process').click(function() {
+
+ //$.ajax({url:"/rest/namefinder/_findRawText",type:"GET",data: "Test text",dataType:"json",contentType:"application/json"})
+
+ var inputText = $('textarea#opennlp-demo-input').val();
+
+ // Call the name finder service to detect names
+ $.ajax({
+ type: 'POST',
+ url: "http://localhost:8080/rest/namefinder/_findRawText",
+ data: inputText,
+ dataType: "json",
+ contentType: "application/json; charset=UTF-8",
+ success: function (data) {
+
+ $("div#opennlp-demo-result").empty();
+
+ // Extract tokens and names from the array array
+ var tokens = [];
+ var annotations = [];
+
+ for (si = 0; si < data.document.length; si++) {
+ for (ni = 0; ni < data.names[si].length; ni++) {
+ var ann = data.names[si][ni];
+
+ // alert(data.names[si][ni]);
+
+ annotations.push(new Annotation("person", 0, tokens.length + ann.start,
+ tokens.length + ann.end));
+ }
+
+ for (ti = 0; ti < data.document[si].length; ti++) {
+ // TODO: its end and begin index, need to do substring on input text!
+
+ tokens.push(inputText.substring(data.document[si][ti].start, data.document[si][ti].end));
+ }
+ }
+
+ // Display results in annotation editor!
+ new AnnotationEditor($("div#opennlp-demo-result"),
+ tokens, annotations);
+ },
+ error: function (jqXHR, textStatus, errorThrown) {
+ alert("Failed to call name finder service for some reason!");
+ }
+ });
+ });
+ }
+ };
+
+ $.fn.opennlpDemo = function( method ) {
+
+ // Method calling logic
+ if ( methods[method] ) {
+ return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
+ } else if ( typeof method === 'object' || ! method ) {
+ return methods.init.apply( this, arguments );
+ } else {
+ $.error( 'Method ' + method + ' does not exist on jQuery.opennlpDemo' );
+ }
+
+ };
+
+})( jQuery );