You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2018/09/21 10:15:16 UTC

[05/70] [abbrv] [partial] jena git commit: JENA-1597: separate jena-fuseki-webapp module

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/dataset-stats.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/dataset-stats.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/dataset-stats.js
new file mode 100644
index 0000000..f2dc198
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/dataset-stats.js
@@ -0,0 +1,41 @@
+define(
+  function( require ) {
+    var Backbone = require( "backbone" ),
+        _ = require( "underscore" ),
+        fui = require( "app/fui" ),
+        datasetStatsViewTpl = require( "plugins/text!app/templates/dataset-stats.tpl" );
+
+    var DatasetStatsView = Backbone.Marionette.ItemView.extend( {
+      initialize: function() {
+        _.bindAll( this, "onShowTab" );
+
+        fui.vent.on( "shown.bs.tab", this.onShowTab );
+      },
+
+      template: _.template( datasetStatsViewTpl ),
+
+      ui: {
+      },
+
+      el: "#statistics",
+
+      modelEvents: {
+        'change': "modelChanged"
+      },
+
+      modelChanged: function() {
+          this.render();
+      },
+
+      onShowTab: function( tab ) {
+        if (tab.attr("href") === "#info") {
+          this.model.refresh();
+        }
+      }
+
+    });
+
+
+    return DatasetStatsView;
+  }
+);

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/datasets-dropdown-list.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/datasets-dropdown-list.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/datasets-dropdown-list.js
new file mode 100644
index 0000000..92b2bf4
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/datasets-dropdown-list.js
@@ -0,0 +1,43 @@
+define(
+  function( require ) {
+    var Backbone = require( "backbone" ),
+        _ = require( "underscore" ),
+        fui = require( "app/fui" );
+
+    var DatasetDropDownListView = Backbone.Marionette.ItemView.extend( {
+      initialize: function(){
+      },
+
+      template:"",
+
+      el: "ul.dropdown-menu.dataset-list",
+
+      ui: {
+      },
+
+      events: {
+      },
+
+      render: function() {
+        var e = $(this.el).empty();
+        _.each( this.model, function( ds ) {
+          e.append( sprintf( "<li><a class='action select-dataset'href='?ds=%s'>%s</a></li>", ds.name(), ds.name() ));
+        } );
+      },
+
+      /** Change the currently selected dataset name. If required, notify other units via an event */
+      setCurrentDatasetName: function( dsName, notify ) {
+        if (dsName) {
+          $(".current-dataset").text( dsName );
+        }
+
+        if (notify) {
+          fui.vent.trigger( "views.datasets-dropdown-list.dataset-changed", dsName )
+        }
+      }
+    });
+
+
+    return DatasetDropDownListView;
+  }
+);

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/file-upload.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/file-upload.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/file-upload.js
new file mode 100644
index 0000000..f16e544
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/file-upload.js
@@ -0,0 +1,225 @@
+/**
+ * This view presents a control to upload files to the current dataset, and a recently-uploaded
+ * log to track what has been done.
+ */
+
+define(
+  function( require ) {
+    var Backbone = require( "backbone" ),
+        _ = require( "underscore" ),
+        sprintf = require( "sprintf" ),
+        fui = require( "app/fui" ),
+        fileUploadTemplate = require( "plugins/text!app/templates/file-upload.tpl" ),
+        UploadableFileView = require( "app/views/uploadable-file" );
+
+    var FileUploadView = Backbone.Marionette.CompositeView.extend( {
+      initialize: function(){
+        _.bindAll( this,
+                   "onUploadAdd", "onRemoveUpload", "onUploadAll",
+                   "onProgress", "onUploadDone", "onUploadFail",
+                   "onPerformUpload" );
+
+        fui.vent.on( "upload.remove", this.onRemoveUpload );
+        fui.vent.on( "upload.perform", this.onPerformUpload );
+      },
+
+      template: _.template( fileUploadTemplate ),
+
+      el: "#file-upload",
+
+      itemViewContainer: "ul",
+      itemView: UploadableFileView,
+      collection: new Backbone.Collection(),
+
+      ui: {
+        fileUpload: '#fileuploadForm',
+        graphLabel: '.graph-label input'
+      },
+
+      events: {
+        "click .action-upload-all": "onUploadAll"
+      },
+
+      templateHelpers: {
+      },
+
+      onRender: function() {
+        // initialise the file upload widget
+        this.ui.fileUpload.fileupload( {
+          dataType: 'json',
+          add: this.onUploadAdd,
+          progress: this.onProgress
+        } );
+      },
+
+      /** User has added a file */
+      onUploadAdd: function( e, data ) {
+        var collection = this.collection;
+        var self = this;
+
+        _.each( data.files, function( file ) {
+          file.readableFileSize = self.readableFileSize( file );
+          collection.add( new Backbone.Model( {file: file} ) );
+        } );
+
+        this.enableUploadAll( true );
+      },
+
+      /** Return file size in bytes in a human-readable form */
+      readableFileSize: function( file ) {
+        var k = 1024;
+        var m = k * k;
+
+        if (file.size >= m) {
+          return sprintf( "%.1fmb", file.size / m );
+        }
+        else if (file.size >= k) {
+          return sprintf( "%.1fkb", file.size / k );
+        }
+        else {
+          return sprintf( "%d bytes", file.size );
+        }
+      },
+
+      /** User has requested to remove a selected upload */
+      onRemoveUpload: function( file ) {
+        this.collection.remove( file );
+        this.enableUploadAll( this.collection.size() > 0 )
+      },
+
+      /** User has requested to perform a selected upload */
+      onPerformUpload: function( model ) {
+        this.loadAll = false;
+        this.uploadFileFromModel( model );
+      },
+
+      /** Return the list of active files waiting for upload */
+      activeFiles: function() {
+        var activeModels = _.filter( this.collection.models, function( m ) {
+            return !m.completed;
+          } );
+
+        return _.map( activeModels,  function( m ) {
+            return m.get( "file" );
+          } );
+      },
+
+      /** User action to upload all active files */
+      onUploadAll: function( e ) {
+        if (e) {
+          e.preventDefault();
+        }
+
+        this.$el.find( ".file-description .action" ).attr( 'disabled', 'disabled' );
+        this.loadNextAvailableFile( true );
+      },
+
+      /** Load the next file in the sequence */
+      loadNextAvailableFile: function( all ) {
+        this.loadAll = all;
+        var files = this.activeFiles();
+
+        if (files.length > 0) {
+          this.uploadFile( files.shift() );
+        }
+        else {
+          this.enableUploadAll( false );
+        }
+      },
+
+      /** Upload the given file to the server */
+      uploadFile: function( file ) {
+        this.uploadFileFromModel( this.collection.findWhere( {file: file} ) );
+      },
+
+      /** Upload the file attached to a given model */
+      uploadFileFromModel: function( model ) {
+        this.cacheModel( model );
+
+        var file = model.get( "file" );
+        var ds = fui.models.fusekiServer.selectedDataset();
+        var url = ds.uploadURL( this.destinationGraphName() );
+
+        this.ui.fileUpload.fileupload( 'send', {
+          files: [file],
+          url: url
+        })
+          .success( this.onUploadDone )
+          .fail( this.onUploadFail );
+      },
+
+      /** Return the selected graph name, or 'default' */
+      destinationGraphName: function() {
+        var gName = this.ui.graphLabel.val();
+        return (gName && gName !== "") ? gName : 'default';
+      },
+
+      /** Callback on progress against an upload */
+      onProgress: function( e, data ) {
+        var complete = Math.round( 100.0 * data.loaded/ data.total);
+        $(this.activeView.el).find( ".progress-bar" )
+                             .attr( 'aria-valuenow', complete )
+                             .css( 'width', sprintf( "%s%%", complete ));
+      },
+
+      /** Callback on successful completion */
+      onUploadDone: function( data, response ) {
+        var label = "Data file was empty.";
+        if ((data.count) > 0) {
+          var s = (data.count === 1) ? "" : "s";
+          label = sprintf( "%d %s%s", data.count, ((data.tripleCount > 0) ? "triple" : "quad"), s );
+        }
+
+        this.displayUploadResult( sprintf( "<p><small>Result: <strong>success</strong>. %s</small></p>", label ), "" );
+
+        if (this.loadAll) {
+          this.loadNextAvailableFile( true );
+        }
+      },
+
+      /** Callback on error */
+      onUploadFail: function( jqxhr, error, msg ) {
+        $(this.activeView.el).find( ".progress-bar" )
+                             .removeClass( "progress-bar-success" )
+                             .addClass( "progress-bar-warning" );
+        this.displayUploadResult( sprintf( "<p><small>Result: <strong>failed</strong> with message &quot;%s&quot;</small></p>", msg ), "text-danger" );
+
+        if (this.loadAll) {
+          this.loadNextAvailableFile( true );
+        }
+      },
+
+      /** Show the result of uploading a file */
+      displayUploadResult: function( html, cls ) {
+        var el = $(this.activeView.el);
+        this.activeModel.completed = true;
+        el.find( ".action" ).hide();
+
+        el.find( ".result" )
+          .addClass( cls )
+          .append( html );
+      },
+
+      /** Cache the currently active model so that we can attach actions to the corresponding view */
+      cacheModel: function( model ) {
+        this.activeModel = model;
+        this.activeView = this.children.findByModel( model );
+      },
+
+      /** Enable or disable the upload all button */
+      enableUploadAll: function( enabled ) {
+        if (enabled) {
+          $(".action-upload-all").removeAttr( 'disabled' );
+        }
+        else {
+          $(".action-upload-all").attr( 'disabled', 'disabled' );
+        }
+      }
+
+
+    });
+
+
+    return FileUploadView;
+  }
+);

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/tabbed-view-manager.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/tabbed-view-manager.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/tabbed-view-manager.js
new file mode 100644
index 0000000..5bba26d
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/tabbed-view-manager.js
@@ -0,0 +1,63 @@
+/**
+ * Reusable component that encapsulates managing a collection of sub-views as
+ * tabs, with the active tab being selected via the URL query param `tab`.
+ **/
+
+define(
+  function( require ) {
+    "use strict";
+
+    var Marionette = require( "marionette" ),
+        Backbone = require( "backbone" ),
+        _ = require( "underscore" ),
+        fui = require( "app/fui" ),
+        sprintf = require( "sprintf" ),
+        PageUtils = require( "app/util/page-utils" );
+
+    var TabbedViewManagerView = Backbone.View.extend( {
+
+      initialize: function(){
+        this._tab = PageUtils.queryParam( "tab" );
+        this._firstRender = false;
+      },
+
+      render: function() {
+        if (!this._firstRender) {
+          this._firstRender = true;
+          this.activateCurrentTab();
+
+          $(".nav-tabs").on( "shown.bs.tab", function( e ) {
+            fui.vent.trigger( "shown.bs.tab", $(e.target) );
+          } );
+        }
+      },
+
+      /**
+       * Make the tab named as the current tab active. If no named tab, make
+       * the first tab active by default.
+       */
+      activateCurrentTab: function() {
+        var tabs = $(".nav-tabs");
+        var tab = tabs.children().first();
+
+        if (this._tab) {
+          tab = tabs.find( sprintf( "a[href=#%s]", this._tab ) )
+                    .parent();
+        }
+
+        if (!tab.is(".active")) {
+          tabs.children( "li" ).removeClass( "active" );
+          tabs.parent().children(".tab-pane").removeClass("active");
+
+          tab.addClass( "active" );
+          $( tab.children( "a" ).attr( "href" ) ).addClass("active");
+        }
+      }
+
+
+    });
+
+
+    return TabbedViewManagerView;
+  }
+);

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/uploadable-file.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/uploadable-file.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/uploadable-file.js
new file mode 100644
index 0000000..382a92f
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/uploadable-file.js
@@ -0,0 +1,39 @@
+/**
+ * This view encapsulates a single uploadable file
+ */
+
+define(
+  function( require ) {
+    var Backbone = require( "backbone" ),
+        _ = require( "underscore" ),
+        fui = require( "app/fui" ),
+        uploadableFileTemplate = require( "plugins/text!app/templates/uploadable-file.tpl" );
+
+    var UploadableFileView = Backbone.Marionette.ItemView.extend( {
+      initialize: function(){
+      },
+
+      tagName: "li",
+
+      template: _.template( uploadableFileTemplate ),
+
+      events: {
+        "click .action-remove-upload": "onActionRemoveUpload",
+        "click .action-upload-file": "onActionUploadFile"
+      },
+
+      onActionRemoveUpload: function( e ) {
+        e.preventDefault();
+        fui.vent.trigger( "upload.remove", this.model );
+      },
+
+      onActionUploadFile: function( e ) {
+        e.preventDefault();
+        fui.vent.trigger( "upload.perform", this.model );
+      }
+
+    });
+
+    return UploadableFileView;
+  }
+);

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/validation-options.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/validation-options.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/validation-options.js
new file mode 100644
index 0000000..ef0f723
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/app/views/validation-options.js
@@ -0,0 +1,54 @@
+define(
+  function( require ) {
+    var Backbone = require( "backbone" ),
+        _ = require( "underscore" ),
+        fui = require( "app/fui" );
+
+    var ValidationOptions = Backbone.Marionette.ItemView.extend( {
+      initialize: function(){
+        _.bindAll( this, "onValidateAs", "onOutputFormat", "onModelChange" );
+        this.listenTo( this.model, "change", this.onModelChange, this );
+      },
+
+      el: ".validation",
+
+      events: {
+        "click .validate-as-options a": "onValidateAs",
+        "click .output-format-options a": "onOutputFormat",
+      },
+
+      templateHelpers: {
+      },
+
+      onValidateAs: function( e ) {
+        e.preventDefault();
+        var elem = $(e.currentTarget);
+        this.model.setValidateAs( elem.data( "validate-as" ) );
+        this.$el.find(".validate-as-options a").removeClass("active");
+        elem.addClass("active");
+
+        if (this.model.validateAsQuery()) {
+          this.$el.find(".output-format-options").removeClass("hidden");
+        }
+        else {
+          this.$el.find(".output-format-options").addClass("hidden");
+        }
+      },
+
+      onOutputFormat: function( e ) {
+        e.preventDefault();
+        var elem = $(e.currentTarget);
+        this.model.setOutputFormat( elem.data( "output-format" ) );
+        this.$el.find(".output-format-options a").removeClass("active");
+        elem.addClass("active");
+      },
+
+      onModelChange: function( event ) {
+      }
+
+    });
+
+
+    return ValidationOptions;
+  }
+);

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/common-config.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/common-config.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/common-config.js
new file mode 100644
index 0000000..eac4b27
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/common-config.js
@@ -0,0 +1,94 @@
+require.config({
+  baseUrl: 'js/lib',
+  paths: {
+    'app':                  '../app',
+    // lib paths
+    'bootstrap':            'bootstrap.min',
+    'jquery':               'jquery-1.10.2.min',
+    'marionette':           'backbone.marionette',
+    'sprintf':              'sprintf-0.7-beta1',
+    'datatables':           'jquery.dataTables.min',
+    'yasqe':                'yasqe.min',
+    'yasr':                 'yasr.min',
+    'pivottable':           'pivot.min',
+    'jquery-ui':            'jquery-ui.min'
+  },
+  map: {
+      '*': {
+          'codemirror': 'lib/codemirror',
+          'jquery.dataTables.min' : 'datatables',
+          'jquery-ui': 'jquery-ui'
+      },
+  },
+  shim: {
+    'underscore': {
+      exports: '_'
+    },
+    'backbone': {
+      deps: ['underscore', 'jquery'],
+      exports: 'Backbone'
+    },
+    'bootstrap': {
+      deps: ['jquery']
+    },
+    'bootstrap-select.min': {
+      deps: ['bootstrap']
+    },
+    'jquery.xdomainrequest': {
+      deps: ['jquery']
+    },
+    'jquery.dataTables.min': {
+      deps: ['jquery']
+    },
+    'jquery.form': {
+      deps: ['jquery']
+    },
+    'jquery.ui.widget': {
+      deps: ['jquery']
+    },
+    'qonsole': {
+      deps: ['yasqe', 'yasr'],
+      exports: 'qonsole'
+    },
+    'yasqe': {
+      deps: ['jquery', 'lib/codemirror'],
+      exports: 'YASQE'
+    },
+    'yasr': {
+//        deps: ['pivottable', 'jquery', 'lib/codemirror', 'datatables'],
+        deps: ['jquery', 'lib/codemirror', 'datatables'],
+        exports: 'YASR'
+    },
+    'pivottable': {
+        deps: ['jquery-ui']
+    },
+    'jquery-ui': {
+        deps: ['jquery']
+    },
+    'jquery.fileupload': {
+      deps: ['jquery.fileupload.local', 'jquery.iframe-transport', 'jquery.ui.widget']
+    },
+    'jquery.fileupload.local': {
+      deps: ['jquery']
+    },
+    'jquery.iframe-transport': {
+      deps: ['jquery']
+    },
+    'sprintf': {
+      exports: 'sprintf'
+    },
+    'marionette': {
+      deps: ['backbone'],
+      exports: 'Marionette'
+    },
+    'addon/fold/foldcode': {deps: ['lib/codemirror']},
+    'addon/fold/brace-fold': {deps: ['addon/fold/foldcode']},
+    'addon/fold/comment-fold': {deps: ['addon/fold/foldcode']},
+    'addon/fold/foldgutter': {deps: ['addon/fold/foldcode']},
+    'addon/fold/xml-fold': {deps: ['addon/fold/foldcode']},
+    'mode/javascript/javascript': {deps: ['lib/codemirror']},
+    'mode/sparql/sparql': {deps: ['lib/codemirror']},
+    'mode/xml/xml': {deps: ['lib/codemirror']},
+    'mode/turtle/turtle': {deps: ['lib/codemirror']}
+  }
+});

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/brace-fold.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/brace-fold.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/brace-fold.js
new file mode 100644
index 0000000..1605f6c
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/brace-fold.js
@@ -0,0 +1,105 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.registerHelper("fold", "brace", function(cm, start) {
+  var line = start.line, lineText = cm.getLine(line);
+  var startCh, tokenType;
+
+  function findOpening(openCh) {
+    for (var at = start.ch, pass = 0;;) {
+      var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
+      if (found == -1) {
+        if (pass == 1) break;
+        pass = 1;
+        at = lineText.length;
+        continue;
+      }
+      if (pass == 1 && found < start.ch) break;
+      tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
+      if (!/^(comment|string)/.test(tokenType)) return found + 1;
+      at = found - 1;
+    }
+  }
+
+  var startToken = "{", endToken = "}", startCh = findOpening("{");
+  if (startCh == null) {
+    startToken = "[", endToken = "]";
+    startCh = findOpening("[");
+  }
+
+  if (startCh == null) return;
+  var count = 1, lastLine = cm.lastLine(), end, endCh;
+  outer: for (var i = line; i <= lastLine; ++i) {
+    var text = cm.getLine(i), pos = i == line ? startCh : 0;
+    for (;;) {
+      var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
+      if (nextOpen < 0) nextOpen = text.length;
+      if (nextClose < 0) nextClose = text.length;
+      pos = Math.min(nextOpen, nextClose);
+      if (pos == text.length) break;
+      if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
+        if (pos == nextOpen) ++count;
+        else if (!--count) { end = i; endCh = pos; break outer; }
+      }
+      ++pos;
+    }
+  }
+  if (end == null || line == end && endCh == startCh) return;
+  return {from: CodeMirror.Pos(line, startCh),
+          to: CodeMirror.Pos(end, endCh)};
+});
+
+CodeMirror.registerHelper("fold", "import", function(cm, start) {
+  function hasImport(line) {
+    if (line < cm.firstLine() || line > cm.lastLine()) return null;
+    var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
+    if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
+    if (start.type != "keyword" || start.string != "import") return null;
+    // Now find closing semicolon, return its position
+    for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
+      var text = cm.getLine(i), semi = text.indexOf(";");
+      if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
+    }
+  }
+
+  var start = start.line, has = hasImport(start), prev;
+  if (!has || hasImport(start - 1) || ((prev = hasImport(start - 2)) && prev.end.line == start - 1))
+    return null;
+  for (var end = has.end;;) {
+    var next = hasImport(end.line + 1);
+    if (next == null) break;
+    end = next.end;
+  }
+  return {from: cm.clipPos(CodeMirror.Pos(start, has.startCh + 1)), to: end};
+});
+
+CodeMirror.registerHelper("fold", "include", function(cm, start) {
+  function hasInclude(line) {
+    if (line < cm.firstLine() || line > cm.lastLine()) return null;
+    var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
+    if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
+    if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
+  }
+
+  var start = start.line, has = hasInclude(start);
+  if (has == null || hasInclude(start - 1) != null) return null;
+  for (var end = start;;) {
+    var next = hasInclude(end + 1);
+    if (next == null) break;
+    ++end;
+  }
+  return {from: CodeMirror.Pos(start, has + 1),
+          to: cm.clipPos(CodeMirror.Pos(end))};
+});
+
+});

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/comment-fold.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/comment-fold.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/comment-fold.js
new file mode 100644
index 0000000..b75db7e
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/comment-fold.js
@@ -0,0 +1,57 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
+  return mode.blockCommentStart && mode.blockCommentEnd;
+}, function(cm, start) {
+  var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
+  if (!startToken || !endToken) return;
+  var line = start.line, lineText = cm.getLine(line);
+
+  var startCh;
+  for (var at = start.ch, pass = 0;;) {
+    var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
+    if (found == -1) {
+      if (pass == 1) return;
+      pass = 1;
+      at = lineText.length;
+      continue;
+    }
+    if (pass == 1 && found < start.ch) return;
+    if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)))) {
+      startCh = found + startToken.length;
+      break;
+    }
+    at = found - 1;
+  }
+
+  var depth = 1, lastLine = cm.lastLine(), end, endCh;
+  outer: for (var i = line; i <= lastLine; ++i) {
+    var text = cm.getLine(i), pos = i == line ? startCh : 0;
+    for (;;) {
+      var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
+      if (nextOpen < 0) nextOpen = text.length;
+      if (nextClose < 0) nextClose = text.length;
+      pos = Math.min(nextOpen, nextClose);
+      if (pos == text.length) break;
+      if (pos == nextOpen) ++depth;
+      else if (!--depth) { end = i; endCh = pos; break outer; }
+      ++pos;
+    }
+  }
+  if (end == null || line == end && endCh == startCh) return;
+  return {from: CodeMirror.Pos(line, startCh),
+          to: CodeMirror.Pos(end, endCh)};
+});
+
+});

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/foldcode.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/foldcode.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/foldcode.js
new file mode 100644
index 0000000..3abeb83
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/foldcode.js
@@ -0,0 +1,145 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  function doFold(cm, pos, options, force) {
+    if (options && options.call) {
+      var finder = options;
+      options = null;
+    } else {
+      var finder = getOption(cm, options, "rangeFinder");
+    }
+    if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
+    var minSize = getOption(cm, options, "minFoldSize");
+
+    function getRange(allowFolded) {
+      var range = finder(cm, pos);
+      if (!range || range.to.line - range.from.line < minSize) return null;
+      var marks = cm.findMarksAt(range.from);
+      for (var i = 0; i < marks.length; ++i) {
+        if (marks[i].__isFold && force !== "fold") {
+          if (!allowFolded) return null;
+          range.cleared = true;
+          marks[i].clear();
+        }
+      }
+      return range;
+    }
+
+    var range = getRange(true);
+    if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) {
+      pos = CodeMirror.Pos(pos.line - 1, 0);
+      range = getRange(false);
+    }
+    if (!range || range.cleared || force === "unfold") return;
+
+    var myWidget = makeWidget(cm, options);
+    CodeMirror.on(myWidget, "mousedown", function(e) {
+      myRange.clear();
+      CodeMirror.e_preventDefault(e);
+    });
+    var myRange = cm.markText(range.from, range.to, {
+      replacedWith: myWidget,
+      clearOnEnter: true,
+      __isFold: true
+    });
+    myRange.on("clear", function(from, to) {
+      CodeMirror.signal(cm, "unfold", cm, from, to);
+    });
+    CodeMirror.signal(cm, "fold", cm, range.from, range.to);
+  }
+
+  function makeWidget(cm, options) {
+    var widget = getOption(cm, options, "widget");
+    if (typeof widget == "string") {
+      var text = document.createTextNode(widget);
+      widget = document.createElement("span");
+      widget.appendChild(text);
+      widget.className = "CodeMirror-foldmarker";
+    }
+    return widget;
+  }
+
+  // Clumsy backwards-compatible interface
+  CodeMirror.newFoldFunction = function(rangeFinder, widget) {
+    return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
+  };
+
+  // New-style interface
+  CodeMirror.defineExtension("foldCode", function(pos, options, force) {
+    doFold(this, pos, options, force);
+  });
+
+  CodeMirror.defineExtension("isFolded", function(pos) {
+    var marks = this.findMarksAt(pos);
+    for (var i = 0; i < marks.length; ++i)
+      if (marks[i].__isFold) return true;
+  });
+
+  CodeMirror.commands.toggleFold = function(cm) {
+    cm.foldCode(cm.getCursor());
+  };
+  CodeMirror.commands.fold = function(cm) {
+    cm.foldCode(cm.getCursor(), null, "fold");
+  };
+  CodeMirror.commands.unfold = function(cm) {
+    cm.foldCode(cm.getCursor(), null, "unfold");
+  };
+  CodeMirror.commands.foldAll = function(cm) {
+    cm.operation(function() {
+      for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
+        cm.foldCode(CodeMirror.Pos(i, 0), null, "fold");
+    });
+  };
+  CodeMirror.commands.unfoldAll = function(cm) {
+    cm.operation(function() {
+      for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
+        cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold");
+    });
+  };
+
+  CodeMirror.registerHelper("fold", "combine", function() {
+    var funcs = Array.prototype.slice.call(arguments, 0);
+    return function(cm, start) {
+      for (var i = 0; i < funcs.length; ++i) {
+        var found = funcs[i](cm, start);
+        if (found) return found;
+      }
+    };
+  });
+
+  CodeMirror.registerHelper("fold", "auto", function(cm, start) {
+    var helpers = cm.getHelpers(start, "fold");
+    for (var i = 0; i < helpers.length; i++) {
+      var cur = helpers[i](cm, start);
+      if (cur) return cur;
+    }
+  });
+
+  var defaultOptions = {
+    rangeFinder: CodeMirror.fold.auto,
+    widget: "\u2194",
+    minFoldSize: 0,
+    scanUp: false
+  };
+
+  CodeMirror.defineOption("foldOptions", null);
+
+  function getOption(cm, options, name) {
+    if (options && options[name] !== undefined)
+      return options[name];
+    var editorOptions = cm.options.foldOptions;
+    if (editorOptions && editorOptions[name] !== undefined)
+      return editorOptions[name];
+    return defaultOptions[name];
+  }
+});

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/foldgutter.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/foldgutter.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/foldgutter.js
new file mode 100644
index 0000000..bd31ec4
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/foldgutter.js
@@ -0,0 +1,134 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"), require("./foldcode"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror", "./foldcode"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
+    if (old && old != CodeMirror.Init) {
+      cm.clearGutter(cm.state.foldGutter.options.gutter);
+      cm.state.foldGutter = null;
+      cm.off("gutterClick", onGutterClick);
+      cm.off("change", onChange);
+      cm.off("viewportChange", onViewportChange);
+      cm.off("fold", onFold);
+      cm.off("unfold", onFold);
+      cm.off("swapDoc", updateInViewport);
+    }
+    if (val) {
+      cm.state.foldGutter = new State(parseOptions(val));
+      updateInViewport(cm);
+      cm.on("gutterClick", onGutterClick);
+      cm.on("change", onChange);
+      cm.on("viewportChange", onViewportChange);
+      cm.on("fold", onFold);
+      cm.on("unfold", onFold);
+      cm.on("swapDoc", updateInViewport);
+    }
+  });
+
+  var Pos = CodeMirror.Pos;
+
+  function State(options) {
+    this.options = options;
+    this.from = this.to = 0;
+  }
+
+  function parseOptions(opts) {
+    if (opts === true) opts = {};
+    if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
+    if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
+    if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
+    return opts;
+  }
+
+  function isFolded(cm, line) {
+    var marks = cm.findMarksAt(Pos(line));
+    for (var i = 0; i < marks.length; ++i)
+      if (marks[i].__isFold && marks[i].find().from.line == line) return true;
+  }
+
+  function marker(spec) {
+    if (typeof spec == "string") {
+      var elt = document.createElement("div");
+      elt.className = spec + " CodeMirror-guttermarker-subtle";
+      return elt;
+    } else {
+      return spec.cloneNode(true);
+    }
+  }
+
+  function updateFoldInfo(cm, from, to) {
+    var opts = cm.state.foldGutter.options, cur = from;
+    cm.eachLine(from, to, function(line) {
+      var mark = null;
+      if (isFolded(cm, cur)) {
+        mark = marker(opts.indicatorFolded);
+      } else {
+        var pos = Pos(cur, 0), func = opts.rangeFinder || CodeMirror.fold.auto;
+        var range = func && func(cm, pos);
+        if (range && range.from.line + 1 < range.to.line)
+          mark = marker(opts.indicatorOpen);
+      }
+      cm.setGutterMarker(line, opts.gutter, mark);
+      ++cur;
+    });
+  }
+
+  function updateInViewport(cm) {
+    var vp = cm.getViewport(), state = cm.state.foldGutter;
+    if (!state) return;
+    cm.operation(function() {
+      updateFoldInfo(cm, vp.from, vp.to);
+    });
+    state.from = vp.from; state.to = vp.to;
+  }
+
+  function onGutterClick(cm, line, gutter) {
+    var opts = cm.state.foldGutter.options;
+    if (gutter != opts.gutter) return;
+    cm.foldCode(Pos(line, 0), opts.rangeFinder);
+  }
+
+  function onChange(cm) {
+    var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
+    state.from = state.to = 0;
+    clearTimeout(state.changeUpdate);
+    state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
+  }
+
+  function onViewportChange(cm) {
+    var state = cm.state.foldGutter, opts = cm.state.foldGutter.options;
+    clearTimeout(state.changeUpdate);
+    state.changeUpdate = setTimeout(function() {
+      var vp = cm.getViewport();
+      if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
+        updateInViewport(cm);
+      } else {
+        cm.operation(function() {
+          if (vp.from < state.from) {
+            updateFoldInfo(cm, vp.from, state.from);
+            state.from = vp.from;
+          }
+          if (vp.to > state.to) {
+            updateFoldInfo(cm, state.to, vp.to);
+            state.to = vp.to;
+          }
+        });
+      }
+    }, opts.updateViewportTimeSpan || 400);
+  }
+
+  function onFold(cm, from) {
+    var state = cm.state.foldGutter, line = from.line;
+    if (line >= state.from && line < state.to)
+      updateFoldInfo(cm, line, line + 1);
+  }
+});

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/xml-fold.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/xml-fold.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/xml-fold.js
new file mode 100644
index 0000000..a45da58
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/addon/fold/xml-fold.js
@@ -0,0 +1,181 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  var Pos = CodeMirror.Pos;
+  function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
+
+  var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
+  var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
+  var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
+
+  function Iter(cm, line, ch, range) {
+    this.line = line; this.ch = ch;
+    this.cm = cm; this.text = cm.getLine(line);
+    this.min = range ? range.from : cm.firstLine();
+    this.max = range ? range.to - 1 : cm.lastLine();
+  }
+
+  function tagAt(iter, ch) {
+    var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
+    return type && /\btag\b/.test(type);
+  }
+
+  function nextLine(iter) {
+    if (iter.line >= iter.max) return;
+    iter.ch = 0;
+    iter.text = iter.cm.getLine(++iter.line);
+    return true;
+  }
+  function prevLine(iter) {
+    if (iter.line <= iter.min) return;
+    iter.text = iter.cm.getLine(--iter.line);
+    iter.ch = iter.text.length;
+    return true;
+  }
+
+  function toTagEnd(iter) {
+    for (;;) {
+      var gt = iter.text.indexOf(">", iter.ch);
+      if (gt == -1) { if (nextLine(iter)) continue; else return; }
+      if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
+      var lastSlash = iter.text.lastIndexOf("/", gt);
+      var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
+      iter.ch = gt + 1;
+      return selfClose ? "selfClose" : "regular";
+    }
+  }
+  function toTagStart(iter) {
+    for (;;) {
+      var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
+      if (lt == -1) { if (prevLine(iter)) continue; else return; }
+      if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
+      xmlTagStart.lastIndex = lt;
+      iter.ch = lt;
+      var match = xmlTagStart.exec(iter.text);
+      if (match && match.index == lt) return match;
+    }
+  }
+
+  function toNextTag(iter) {
+    for (;;) {
+      xmlTagStart.lastIndex = iter.ch;
+      var found = xmlTagStart.exec(iter.text);
+      if (!found) { if (nextLine(iter)) continue; else return; }
+      if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
+      iter.ch = found.index + found[0].length;
+      return found;
+    }
+  }
+  function toPrevTag(iter) {
+    for (;;) {
+      var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
+      if (gt == -1) { if (prevLine(iter)) continue; else return; }
+      if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
+      var lastSlash = iter.text.lastIndexOf("/", gt);
+      var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
+      iter.ch = gt + 1;
+      return selfClose ? "selfClose" : "regular";
+    }
+  }
+
+  function findMatchingClose(iter, tag) {
+    var stack = [];
+    for (;;) {
+      var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
+      if (!next || !(end = toTagEnd(iter))) return;
+      if (end == "selfClose") continue;
+      if (next[1]) { // closing tag
+        for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
+          stack.length = i;
+          break;
+        }
+        if (i < 0 && (!tag || tag == next[2])) return {
+          tag: next[2],
+          from: Pos(startLine, startCh),
+          to: Pos(iter.line, iter.ch)
+        };
+      } else { // opening tag
+        stack.push(next[2]);
+      }
+    }
+  }
+  function findMatchingOpen(iter, tag) {
+    var stack = [];
+    for (;;) {
+      var prev = toPrevTag(iter);
+      if (!prev) return;
+      if (prev == "selfClose") { toTagStart(iter); continue; }
+      var endLine = iter.line, endCh = iter.ch;
+      var start = toTagStart(iter);
+      if (!start) return;
+      if (start[1]) { // closing tag
+        stack.push(start[2]);
+      } else { // opening tag
+        for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
+          stack.length = i;
+          break;
+        }
+        if (i < 0 && (!tag || tag == start[2])) return {
+          tag: start[2],
+          from: Pos(iter.line, iter.ch),
+          to: Pos(endLine, endCh)
+        };
+      }
+    }
+  }
+
+  CodeMirror.registerHelper("fold", "xml", function(cm, start) {
+    var iter = new Iter(cm, start.line, 0);
+    for (;;) {
+      var openTag = toNextTag(iter), end;
+      if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
+      if (!openTag[1] && end != "selfClose") {
+        var start = Pos(iter.line, iter.ch);
+        var close = findMatchingClose(iter, openTag[2]);
+        return close && {from: start, to: close.from};
+      }
+    }
+  });
+  CodeMirror.findMatchingTag = function(cm, pos, range) {
+    var iter = new Iter(cm, pos.line, pos.ch, range);
+    if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
+    var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
+    var start = end && toTagStart(iter);
+    if (!end || end == "selfClose" || !start || cmp(iter, pos) > 0) return;
+    var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
+
+    if (start[1]) { // closing tag
+      return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
+    } else { // opening tag
+      iter = new Iter(cm, to.line, to.ch, range);
+      return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
+    }
+  };
+
+  CodeMirror.findEnclosingTag = function(cm, pos, range) {
+    var iter = new Iter(cm, pos.line, pos.ch, range);
+    for (;;) {
+      var open = findMatchingOpen(iter);
+      if (!open) break;
+      var forward = new Iter(cm, pos.line, pos.ch, range);
+      var close = findMatchingClose(forward, open.tag);
+      if (close) return {open: open, close: close};
+    }
+  };
+
+  // Used by addon/edit/closetag.js
+  CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
+    var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
+    return findMatchingClose(iter, name);
+  };
+});

http://git-wip-us.apache.org/repos/asf/jena/blob/e8abcbb6/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/backbone-min.js
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/backbone-min.js b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/backbone-min.js
new file mode 100644
index 0000000..3b2593d
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-webapp/src/main/webapp/js/lib/backbone-min.js
@@ -0,0 +1,2 @@
+(function(){var t=this;var e=t.Backbone;var i=[];var r=i.push;var s=i.slice;var n=i.splice;var a;if(typeof exports!=="undefined"){a=exports}else{a=t.Backbone={}}a.VERSION="1.1.0";var h=t._;if(!h&&typeof require!=="undefined")h=require("underscore");a.$=t.jQuery||t.Zepto||t.ender||t.$;a.noConflict=function(){t.Backbone=e;return this};a.emulateHTTP=false;a.emulateJSON=false;var o=a.Events={on:function(t,e,i){if(!l(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,i){if(!l(this,"once",t,[e,i])||!e)return this;var r=this;var s=h.once(function(){r.off(t,s);e.apply(this,arguments)});s._callback=e;return this.on(t,s,i)},off:function(t,e,i){var r,s,n,a,o,u,c,f;if(!this._events||!l(this,"off",t,[e,i]))return this;if(!t&&!e&&!i){this._events={};return this}a=t?[t]:h.keys(this._events);for(o=0,u=a.length;o<u;o++){t=a[o];if(n=this._events[t]){this._events[t]=r=[
 ];if(e||i){for(c=0,f=n.length;c<f;c++){s=n[c];if(e&&e!==s.callback&&e!==s.callback._callback||i&&i!==s.context){r.push(s)}}}if(!r.length)delete this._events[t]}}return this},trigger:function(t){if(!this._events)return this;var e=s.call(arguments,1);if(!l(this,"trigger",t,e))return this;var i=this._events[t];var r=this._events.all;if(i)c(i,e);if(r)c(r,arguments);return this},stopListening:function(t,e,i){var r=this._listeningTo;if(!r)return this;var s=!e&&!i;if(!i&&typeof e==="object")i=this;if(t)(r={})[t._listenId]=t;for(var n in r){t=r[n];t.off(e,i,this);if(s||h.isEmpty(t._events))delete this._listeningTo[n]}return this}};var u=/\s+/;var l=function(t,e,i,r){if(!i)return true;if(typeof i==="object"){for(var s in i){t[e].apply(t,[s,i[s]].concat(r))}return false}if(u.test(i)){var n=i.split(u);for(var a=0,h=n.length;a<h;a++){t[e].apply(t,[n[a]].concat(r))}return false}return true};var c=function(t,e){var i,r=-1,s=t.length,n=e[0],a=e[1],h=e[2];switch(e.length){case 0:while(++r<s)(i=t[r]
 ).callback.call(i.ctx);return;case 1:while(++r<s)(i=t[r]).callback.call(i.ctx,n);return;case 2:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a);return;case 3:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a,h);return;default:while(++r<s)(i=t[r]).callback.apply(i.ctx,e)}};var f={listenTo:"on",listenToOnce:"once"};h.each(f,function(t,e){o[e]=function(e,i,r){var s=this._listeningTo||(this._listeningTo={});var n=e._listenId||(e._listenId=h.uniqueId("l"));s[n]=e;if(!r&&typeof i==="object")r=this;e[t](i,r,this);return this}});o.bind=o.on;o.unbind=o.off;h.extend(a,o);var d=a.Model=function(t,e){var i=t||{};e||(e={});this.cid=h.uniqueId("c");this.attributes={};if(e.collection)this.collection=e.collection;if(e.parse)i=this.parse(i,e)||{};i=h.defaults({},i,h.result(this,"defaults"));this.set(i,e);this.changed={};this.initialize.apply(this,arguments)};h.extend(d.prototype,o,{changed:null,validationError:null,idAttribute:"id",initialize:function(){},toJSON:function(t){return h.clone(this.attributes)},
 sync:function(){return a.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return h.escape(this.get(t))},has:function(t){return this.get(t)!=null},set:function(t,e,i){var r,s,n,a,o,u,l,c;if(t==null)return this;if(typeof t==="object"){s=t;i=e}else{(s={})[t]=e}i||(i={});if(!this._validate(s,i))return false;n=i.unset;o=i.silent;a=[];u=this._changing;this._changing=true;if(!u){this._previousAttributes=h.clone(this.attributes);this.changed={}}c=this.attributes,l=this._previousAttributes;if(this.idAttribute in s)this.id=s[this.idAttribute];for(r in s){e=s[r];if(!h.isEqual(c[r],e))a.push(r);if(!h.isEqual(l[r],e)){this.changed[r]=e}else{delete this.changed[r]}n?delete c[r]:c[r]=e}if(!o){if(a.length)this._pending=true;for(var f=0,d=a.length;f<d;f++){this.trigger("change:"+a[f],this,c[a[f]],i)}}if(u)return this;if(!o){while(this._pending){this._pending=false;this.trigger("change",this,i)}}this._pending=false;this._changing=false;return this},unset:funct
 ion(t,e){return this.set(t,void 0,h.extend({},e,{unset:true}))},clear:function(t){var e={};for(var i in this.attributes)e[i]=void 0;return this.set(e,h.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!h.isEmpty(this.changed);return h.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?h.clone(this.changed):false;var e,i=false;var r=this._changing?this._previousAttributes:this.attributes;for(var s in t){if(h.isEqual(r[s],e=t[s]))continue;(i||(i={}))[s]=e}return i},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return h.clone(this._previousAttributes)},fetch:function(t){t=t?h.clone(t):{};if(t.parse===void 0)t.parse=true;var e=this;var i=t.success;t.success=function(r){if(!e.set(e.parse(r,t),t))return false;if(i)i(e,r,t);e.trigger("sync",e,r,t)};M(this,t);return this.sync("read",this,t)},save:function(t,e,i){var r,s,n,a=this.attributes;if(t==null||
 typeof t==="object"){r=t;i=e}else{(r={})[t]=e}i=h.extend({validate:true},i);if(r&&!i.wait){if(!this.set(r,i))return false}else{if(!this._validate(r,i))return false}if(r&&i.wait){this.attributes=h.extend({},a,r)}if(i.parse===void 0)i.parse=true;var o=this;var u=i.success;i.success=function(t){o.attributes=a;var e=o.parse(t,i);if(i.wait)e=h.extend(r||{},e);if(h.isObject(e)&&!o.set(e,i)){return false}if(u)u(o,t,i);o.trigger("sync",o,t,i)};M(this,i);s=this.isNew()?"create":i.patch?"patch":"update";if(s==="patch")i.attrs=r;n=this.sync(s,this,i);if(r&&i.wait)this.attributes=a;return n},destroy:function(t){t=t?h.clone(t):{};var e=this;var i=t.success;var r=function(){e.trigger("destroy",e,e.collection,t)};t.success=function(s){if(t.wait||e.isNew())r();if(i)i(e,s,t);if(!e.isNew())e.trigger("sync",e,s,t)};if(this.isNew()){t.success();return false}M(this,t);var s=this.sync("delete",this,t);if(!t.wait)r();return s},url:function(){var t=h.result(this,"urlRoot")||h.result(this.collection,"url")|
 |U();if(this.isNew())return t;return t+(t.charAt(t.length-1)==="/"?"":"/")+encodeURIComponent(this.id)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return this.id==null},isValid:function(t){return this._validate({},h.extend(t||{},{validate:true}))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=h.extend({},this.attributes,t);var i=this.validationError=this.validate(t,e)||null;if(!i)return true;this.trigger("invalid",this,i,h.extend(e,{validationError:i}));return false}});var p=["keys","values","pairs","invert","pick","omit"];h.each(p,function(t){d.prototype[t]=function(){var e=s.call(arguments);e.unshift(this.attributes);return h[t].apply(h,e)}});var v=a.Collection=function(t,e){e||(e={});if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,h.extend({silent:true},e))};var g={add:true,remove:true,m
 erge:true};var m={add:true,remove:false};h.extend(v.prototype,o,{model:d,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return a.sync.apply(this,arguments)},add:function(t,e){return this.set(t,h.extend({merge:false},e,m))},remove:function(t,e){var i=!h.isArray(t);t=i?[t]:h.clone(t);e||(e={});var r,s,n,a;for(r=0,s=t.length;r<s;r++){a=t[r]=this.get(t[r]);if(!a)continue;delete this._byId[a.id];delete this._byId[a.cid];n=this.indexOf(a);this.models.splice(n,1);this.length--;if(!e.silent){e.index=n;a.trigger("remove",a,this,e)}this._removeReference(a)}return i?t[0]:t},set:function(t,e){e=h.defaults({},e,g);if(e.parse)t=this.parse(t,e);var i=!h.isArray(t);t=i?t?[t]:[]:h.clone(t);var r,s,n,a,o,u,l;var c=e.at;var f=this.model;var p=this.comparator&&c==null&&e.sort!==false;var v=h.isString(this.comparator)?this.comparator:null;var m=[],y=[],_={};var w=e.add,b=e.merge,x=e.remove;var E=!p&&w&&x?[]:false;for(r=0,s=t.length;r<s;r++){o
 =t[r];if(o instanceof d){n=a=o}else{n=o[f.prototype.idAttribute]}if(u=this.get(n)){if(x)_[u.cid]=true;if(b){o=o===a?a.attributes:o;if(e.parse)o=u.parse(o,e);u.set(o,e);if(p&&!l&&u.hasChanged(v))l=true}t[r]=u}else if(w){a=t[r]=this._prepareModel(o,e);if(!a)continue;m.push(a);a.on("all",this._onModelEvent,this);this._byId[a.cid]=a;if(a.id!=null)this._byId[a.id]=a}if(E)E.push(u||a)}if(x){for(r=0,s=this.length;r<s;++r){if(!_[(a=this.models[r]).cid])y.push(a)}if(y.length)this.remove(y,e)}if(m.length||E&&E.length){if(p)l=true;this.length+=m.length;if(c!=null){for(r=0,s=m.length;r<s;r++){this.models.splice(c+r,0,m[r])}}else{if(E)this.models.length=0;var T=E||m;for(r=0,s=T.length;r<s;r++){this.models.push(T[r])}}}if(l)this.sort({silent:true});if(!e.silent){for(r=0,s=m.length;r<s;r++){(a=m[r]).trigger("add",a,this,e)}if(l||E&&E.length)this.trigger("sort",this,e)}return i?t[0]:t},reset:function(t,e){e||(e={});for(var i=0,r=this.models.length;i<r;i++){this._removeReference(this.models[i])}e.pr
 eviousModels=this.models;this._reset();t=this.add(t,h.extend({silent:true},e));if(!e.silent)this.trigger("reset",this,e);return t},push:function(t,e){return this.add(t,h.extend({at:this.length},e))},pop:function(t){var e=this.at(this.length-1);this.remove(e,t);return e},unshift:function(t,e){return this.add(t,h.extend({at:0},e))},shift:function(t){var e=this.at(0);this.remove(e,t);return e},slice:function(){return s.apply(this.models,arguments)},get:function(t){if(t==null)return void 0;return this._byId[t.id]||this._byId[t.cid]||this._byId[t]},at:function(t){return this.models[t]},where:function(t,e){if(h.isEmpty(t))return e?void 0:[];return this[e?"find":"filter"](function(e){for(var i in t){if(t[i]!==e.get(i))return false}return true})},findWhere:function(t){return this.where(t,true)},sort:function(t){if(!this.comparator)throw new Error("Cannot sort a set without a comparator");t||(t={});if(h.isString(this.comparator)||this.comparator.length===1){this.models=this.sortBy(this.compa
 rator,this)}else{this.models.sort(h.bind(this.comparator,this))}if(!t.silent)this.trigger("sort",this,t);return this},pluck:function(t){return h.invoke(this.models,"get",t)},fetch:function(t){t=t?h.clone(t):{};if(t.parse===void 0)t.parse=true;var e=t.success;var i=this;t.success=function(r){var s=t.reset?"reset":"set";i[s](r,t);if(e)e(i,r,t);i.trigger("sync",i,r,t)};M(this,t);return this.sync("read",this,t)},create:function(t,e){e=e?h.clone(e):{};if(!(t=this._prepareModel(t,e)))return false;if(!e.wait)this.add(t,e);var i=this;var r=e.success;e.success=function(t,e,s){if(s.wait)i.add(t,s);if(r)r(t,e,s)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models)},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(t instanceof d){if(!t.collection)t.collection=this;return t}e=e?h.clone(e):{};e.collection=this;var i=new this.model(t,e);if(!i.validationError)return i;this.trigger("invalid",this
 ,i.validationError,e);return false},_removeReference:function(t){if(this===t.collection)delete t.collection;t.off("all",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if((t==="add"||t==="remove")&&i!==this)return;if(t==="destroy")this.remove(e,r);if(e&&t==="change:"+e.idAttribute){delete this._byId[e.previous(e.idAttribute)];if(e.id!=null)this._byId[e.id]=e}this.trigger.apply(this,arguments)}});var y=["forEach","each","map","collect","reduce","foldl","inject","reduceRight","foldr","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","max","min","toArray","size","first","head","take","initial","rest","tail","drop","last","without","difference","indexOf","shuffle","lastIndexOf","isEmpty","chain"];h.each(y,function(t){v.prototype[t]=function(){var e=s.call(arguments);e.unshift(this.models);return h[t].apply(h,e)}});var _=["groupBy","countBy","sortBy"];h.each(_,function(t){v.prototype[t]=function(e,i){var r=h.isFunction(e)?e:func
 tion(t){return t.get(e)};return h[t](this.models,r,i)}});var w=a.View=function(t){this.cid=h.uniqueId("view");t||(t={});h.extend(this,h.pick(t,x));this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()};var b=/^(\S+)\s*(.*)$/;var x=["model","collection","el","id","attributes","className","tagName","events"];h.extend(w.prototype,o,{tagName:"div",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();this.stopListening();return this},setElement:function(t,e){if(this.$el)this.undelegateEvents();this.$el=t instanceof a.$?t:a.$(t);this.el=this.$el[0];if(e!==false)this.delegateEvents();return this},delegateEvents:function(t){if(!(t||(t=h.result(this,"events"))))return this;this.undelegateEvents();for(var e in t){var i=t[e];if(!h.isFunction(i))i=this[t[e]];if(!i)continue;var r=e.match(b);var s=r[1],n=r[2];i=h.bind(i,this);s+=".delegateEvents"+this.cid;if(n===""){this.$el.on(s,i)}else{this.
 $el.on(s,n,i)}}return this},undelegateEvents:function(){this.$el.off(".delegateEvents"+this.cid);return this},_ensureElement:function(){if(!this.el){var t=h.extend({},h.result(this,"attributes"));if(this.id)t.id=h.result(this,"id");if(this.className)t["class"]=h.result(this,"className");var e=a.$("<"+h.result(this,"tagName")+">").attr(t);this.setElement(e,false)}else{this.setElement(h.result(this,"el"),false)}}});a.sync=function(t,e,i){var r=T[t];h.defaults(i||(i={}),{emulateHTTP:a.emulateHTTP,emulateJSON:a.emulateJSON});var s={type:r,dataType:"json"};if(!i.url){s.url=h.result(e,"url")||U()}if(i.data==null&&e&&(t==="create"||t==="update"||t==="patch")){s.contentType="application/json";s.data=JSON.stringify(i.attrs||e.toJSON(i))}if(i.emulateJSON){s.contentType="application/x-www-form-urlencoded";s.data=s.data?{model:s.data}:{}}if(i.emulateHTTP&&(r==="PUT"||r==="DELETE"||r==="PATCH")){s.type="POST";if(i.emulateJSON)s.data._method=r;var n=i.beforeSend;i.beforeSend=function(t){t.setRequ
 estHeader("X-HTTP-Method-Override",r);if(n)return n.apply(this,arguments)}}if(s.type!=="GET"&&!i.emulateJSON){s.processData=false}if(s.type==="PATCH"&&E){s.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var o=i.xhr=a.ajax(h.extend(s,i));e.trigger("request",e,o,i);return o};var E=typeof window!=="undefined"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};a.ajax=function(){return a.$.ajax.apply(a.$,arguments)};var k=a.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\((.*?)\)/g;var $=/(\(\?)?:\w+/g;var H=/\*\w+/g;var A=/[\-{}\[\]+?.,\\\^$|#\s]/g;h.extend(k.prototype,o,{initialize:function(){},route:function(t,e,i){if(!h.isRegExp(t))t=this._routeToRegExp(t);if(h.isFunction(e)){i=e;e=""}if(!i)i=this[e];var r=this;a.history.route(t,function(s){var n=r._extractParameters(t,s);i&&i.ap
 ply(r,n);r.trigger.apply(r,["route:"+e].concat(n));r.trigger("route",e,n);a.history.trigger("route",r,e,n)});return this},navigate:function(t,e){a.history.navigate(t,e);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=h.result(this,"routes");var t,e=h.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(A,"\\$&").replace(S,"(?:$1)?").replace($,function(t,e){return e?t:"([^/]+)"}).replace(H,"(.*?)");return new RegExp("^"+t+"$")},_extractParameters:function(t,e){var i=t.exec(e).slice(1);return h.map(i,function(t){return t?decodeURIComponent(t):null})}});var I=a.History=function(){this.handlers=[];h.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var N=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var P=/msie [\w.]+/;var C=/\/$/;var j=/[?#].*$/;I.started=false;h.extend(I.prototype,o,{interval:50,getHash:function(t){var e=(t||this).location.href.matc
 h(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=this.location.pathname;var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(N,"")},start:function(t){if(I.started)throw new Error("Backbone.history has already been started");I.started=true;this.options=h.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var e=this.getFragment();var i=document.documentMode;var r=P.exec(navigator.userAgent.toLowerCase())&&(!i||i<=7);this.root=("/"+this.root+"/").replace(O,"/");if(r&&this._wantsHashChange){this.iframe=a.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow;this.navigate(e)}if(this._hasPushState){a.$(window).on("popstate",this.checkUrl)}
 else if(this._wantsHashChange&&"onhashchange"in window&&!r){a.$(window).on("hashchange",this.checkUrl)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}this.fragment=e;var s=this.location;var n=s.pathname.replace(/[^\/]$/,"$&/")===this.root;if(this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!n){this.fragment=this.getFragment(null,true);this.location.replace(this.root+this.location.search+"#"+this.fragment);return true}else if(this._hasPushState&&n&&s.hash){this.fragment=this.getHash().replace(N,"");this.history.replaceState({},document.title,this.root+this.fragment+s.search)}}if(!this.options.silent)return this.loadUrl()},stop:function(){a.$(window).off("popstate",this.checkUrl).off("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);I.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.ge
 tFragment(this.getHash(this.iframe))}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()},loadUrl:function(t){t=this.fragment=this.getFragment(t);return h.any(this.handlers,function(e){if(e.route.test(t)){e.callback(t);return true}})},navigate:function(t,e){if(!I.started)return false;if(!e||e===true)e={trigger:!!e};var i=this.root+(t=this.getFragment(t||""));t=t.replace(j,"");if(this.fragment===t)return;this.fragment=t;if(t===""&&i!=="/")i=i.slice(0,-1);if(this._hasPushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,i)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getFragment(this.getHash(this.iframe))){if(!e.replace)this.iframe.document.open().close();this._updateHash(this.iframe.location,t,e.replace)}}else{return this.location.assign(i)}if(e.trigger)return this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}e
 lse{t.hash="#"+e}}});a.history=new I;var R=function(t,e){var i=this;var r;if(t&&h.has(t,"constructor")){r=t.constructor}else{r=function(){return i.apply(this,arguments)}}h.extend(r,i,e);var s=function(){this.constructor=r};s.prototype=i.prototype;r.prototype=new s;if(t)h.extend(r.prototype,t);r.__super__=i.prototype;return r};d.extend=v.extend=k.extend=w.extend=I.extend=R;var U=function(){throw new Error('A "url" property or function must be specified')};var M=function(t,e){var i=e.error;e.error=function(r){if(i)i(t,r,e);t.trigger("error",t,r,e)}}}).call(this);
+//# sourceMappingURL=backbone-min.map
\ No newline at end of file