applicationjs = c.uri_for( 'js/componentload.js' )
%]
<script type="text/javascript">
+var basepath = window.location.pathname
+if( basepath.lastIndexOf('/') == basepath.length - 1 ) {
+ basepath = basepath.slice( 0, basepath.length - 1)
+};
+var textOnLoad = "[% withtradition %]";
var selectedTextID;
+var selectedTextInfo;
var selectedStemmaID = -1;
var stemmata = [];
function refreshDirectory () {
+ var lmesg = $('#loading_message').clone();
+ $('#directory').empty().append( lmesg.contents() );
$('#directory').load( "[% c.uri_for( 'directory' ) %]",
function(response, status, xhr) {
if (status == "error") {
var msg = "An error occurred: ";
$("#directory").html(msg + xhr.status + " " + xhr.statusText);
+ } else {
+ if( textOnLoad != "" ) {
+ // Call the click callback for the relevant text, if it is
+ // in the page.
+ $('#'+textOnLoad).click();
+ textOnLoad = "";
+ }
}
}
);
}
+function start_upload_dialog() {
+ if( typeof uploader != 'undefined' ){ uploader.destroy() };
+ $('#upload-collation-dialog').dialog('option', 'attach_uploader')();
+ $('#upload_status').empty();
+ $('#upload_button').button('disable');
+ $('#upload-collation-dialog').dialog('open');
+}
+
$(document).ready( function() {
// call out to load the directory div
$('#textinfo_container').hide();
$('#textinfo_waitbox').hide();
refreshDirectory();
- $('#upload-collation-dialog').dialog({
+
+ // Set up the textinfo edit dialog
+ $('#textinfo-edit-dialog').dialog({
autoOpen: false,
- height: 325,
- width: 480,
+ height: 200,
+ width: 300,
+ modal: true,
+ buttons: {
+ Save: function (evt) {
+ $("#edit_textinfo_status").empty();
+ $(evt.target).button("disable");
+ var requrl = "[% c.uri_for( '/textinfo' ) %]/" + selectedTextID;
+ var reqparam = $('#edit_textinfo').serialize();
+ $.post( requrl, reqparam, function (data) {
+ // Reload the selected text fields
+ selectedTextInfo = data;
+ load_textinfo();
+ // Reenable the button and close the form
+ $(evt.target).button("enable");
+ $('#textinfo-edit-dialog').dialog('close');
+ }, 'json' );
+ },
+ Cancel: function() {
+ $('#textinfo-edit-dialog').dialog('close');
+ }
+ },
+ open: function() {
+ $("#edit_textinfo_status").empty();
+ // Populate the form fields with the current values
+ // edit_(name, language, public, owner)
+ $.each([ 'name', 'language', 'owner' ], function( idx, k ) {
+ var fname = '#edit_' + k;
+ // Special case: language Default is basically language null
+ if( k == 'language' && selectedTextInfo[k] == 'Default' ) {
+ $(fname).val( "" );
+ } else {
+ $(fname).val( selectedTextInfo[k] );
+ }
+ });
+ if( selectedTextInfo['public'] == true ) {
+ $('#edit_public').attr('checked','true');
+ } else {
+ $('#edit_public').removeAttr('checked');
+ }
+ },
+ }).ajaxError( function(event, jqXHR, ajaxSettings, thrownError) {
+ $(event.target).parent().find('.ui-button').button("enable");
+ if( ajaxSettings.url.indexOf( 'textinfo' ) > -1
+ && ajaxSettings.type == 'POST' ) {
+ display_error( jqXHR, $("#edit_textinfo_status") );
+ }
+ });
+
+
+ // Set up the stemma editor dialog
+ $('#stemma-edit-dialog').dialog({
+ autoOpen: false,
+ height: 700,
+ width: 600,
modal: true,
buttons: {
- "Upload": function( evt ) {
+ Save: function (evt) {
+ $("#edit_stemma_status").empty();
$(evt.target).button("disable");
- $('#upload_status').empty();
- form_values = $('#upload_collation').serialize();
- $.post( "[% c.uri_for ( '/newtradition' ) %]", form_values, function(data) {
+ var stemmaseq = $('#stemmaseq').val();
+ var requrl = "[% c.uri_for( '/stemma' ) %]/" + selectedTextID + "/" + stemmaseq;
+ var reqparam = { 'dot': $('#dot_field').val() };
+ // TODO We need to stash the literal SVG string in stemmata
+ // somehow. Implement accept header on server side to decide
+ // whether to send application/json or application/xml?
+ $.post( requrl, reqparam, function (data) {
+ // We received a stemma SVG string in return.
+ // Update the current stemma sequence number
+ selectedStemmaID = data.stemmaid;
+ // Stash the answer in our SVG array
+ stemmata[selectedStemmaID] = data.stemmasvg;
+ // Display the new stemma
+ load_stemma( selectedStemmaID );
+ // Reenable the button and close the form
$(evt.target).button("enable");
- $( "#dialog-form" ).dialog( "close" );
- refreshDirectory();
- loadTradition( data.id, data.name, 1 )
+ $('#stemma-edit-dialog').dialog('close');
}, 'json' );
},
Cancel: function() {
- $( this ).dialog( "close" );
+ $('#stemma-edit-dialog').dialog('close');
+ }
+ },
+ open: function(evt) {
+ $("#edit_stemma_status").empty();
+ var stemmaseq = $('#stemmaseq').val();
+ if( stemmaseq == 'n' ) {
+ // If we are creating a new stemma, populate the textarea with a
+ // bare digraph.
+ $(evt.target).dialog('option', 'title', 'Add a new stemma')
+ $('#dot_field').val( "digraph stemma {\n\n}" );
+ } else {
+ // If we are editing a stemma, grab its stemmadot and populate the
+ // textarea with that.
+ $(evt.target).dialog('option', 'title', 'Edit selected stemma')
+ $('#dot_field').val( 'Loading, please wait...' );
+ var doturl = "[% c.uri_for( '/stemmadot' ) %]/" + selectedTextID + "/" + stemmaseq;
+ $.getJSON( doturl, function (data) {
+ // Re-insert the line breaks
+ var dotstring = data.dot.replace(/\|n/gm, "\n");
+ $('#dot_field').val( dotstring );
+ });
}
},
- }).ajaxError( function(event, jqXHR, ajaxSettings, thrownError) {
- if( ajaxSettings.url.indexOf( '/new' ) > -1
- && ajaxSettings.type == 'POST' ) {
- var errobj = jQuery.parseJSON( jqXHR.responseText );
- $('#upload_status').append( '<p class="error">Error: ' + errobj.error + '</br>The tradition cannot be created.</p>' );
+ }).ajaxError( function(event, jqXHR, ajaxSettings, thrownError) {
+ $(event.target).parent().find('.ui-button').button("enable");
+ if( ajaxSettings.url.indexOf( 'stemma' ) > -1
+ && ajaxSettings.type == 'POST' ) {
+ display_error( jqXHR, $("#edit_stemma_status") );
+ }
+ });
+
+ $('#upload-collation-dialog').dialog({
+ autoOpen: false,
+ height: 325,
+ width: 480,
+ modal: true,
+ buttons: {
+ pick: {
+ text: "Pick File",
+ id: "pick_uploadfile_button",
+ click: function() {}
+ },
+ upload: {
+ text: 'Upload',
+ id: 'upload_button',
+ click: function() {
+ $('#upload_status').empty();
+ uploader.start();
+ return false;
+ }
+ },
+ Cancel: function() {
+ $('#upload-collation-dialog').dialog('close');
}
- $(event.target).parent().find('.ui-button').button("enable");
+ },
+ attach_uploader: function() {
+ create_uploader( "[% c.uri_for ( '/newtradition' ) %]" );
+ $('#filelist').empty().html( 'Use the \'Pick\' button to choose a source file…' );
}
- );
+ });
+
+ $('#stemma_graph').mousedown( function(evt) {
+ evt.stopPropagation();
+ $('#stemma_graph').data( 'mousedown_xy', [evt.clientX, evt.clientY] );
+ $('body').mousemove( function(evt) {
+ mouse_scale = 1; // for now, was: mouse_scale = svg_root_element.getScreenCTM().a;
+ dx = (evt.clientX - $('#stemma_graph').data( 'mousedown_xy' )[0]) / mouse_scale;
+ dy = (evt.clientY - $('#stemma_graph').data( 'mousedown_xy' )[1]) / mouse_scale;
+ $('#stemma_graph').data( 'mousedown_xy', [evt.clientX, evt.clientY] );
+ var svg_root = $('#stemma_graph svg').svg().svg('get').root();
+ var g = $('g.graph', svg_root).get(0);
+ current_translate = g.getAttribute( 'transform' ).split(/translate\(/)[1].split(')',1)[0].split(' ');
+ new_transform = g.getAttribute( 'transform' ).replace( /translate\([^\)]*\)/, 'translate(' + (parseFloat(current_translate[0]) + dx) + ' ' + (parseFloat(current_translate[1]) + dy) + ')' );
+ g.setAttribute( 'transform', new_transform );
+ evt.returnValue = false;
+ evt.preventDefault();
+ return false;
+ });
+ $('body').mouseup( function(evt) {
+ $('body').unbind('mousemove');
+ $('body').unbind('mouseup');
+ });
+ });
+
+ $('#stemma_graph').mousewheel(function (event, delta) {
+ event.returnValue = false;
+ event.preventDefault();
+ if (!delta || delta == null || delta == 0) delta = event.originalEvent.wheelDelta;
+ if (!delta || delta == null || delta == 0) delta = -1 * event.originalEvent.detail;
+ if( delta < -9 ) { delta = -9 };
+ var z = 1 + delta/10;
+ z = delta > 0 ? 1 : -1;
+ var svg_root = $('#stemma_graph svg').svg().svg('get').root();
+ var g = $('g.graph', svg_root).get(0);
+ if (g && ((z<1 && (g.getScreenCTM().a * start_element_height) > 4.0) || (z>=1 && (g.getScreenCTM().a * start_element_height) < 1000))) {
+ var scaleLevel = z/10;
+ current_scale = parseFloat( g.getAttribute( 'transform' ).split(/scale\(/)[1].split(')',1)[0].split(' ')[0] );
+ new_transform = g.getAttribute( 'transform' ).replace( /scale\([^\)]*\)/, 'scale(' + (current_scale + scaleLevel) + ')' );
+ g.setAttribute( 'transform', new_transform );
+ }
+ });
+
});
</script>
<div id="topbanner">
<h1>Stemmaweb - a collection of tools for analysis of collated texts</h1>
- <span class="mainnav">[% IF c.user_exists %]Hello! [% c.user.get_object.email %] <a class="navlink" href="[% c.uri_for( '/logout' ) %]">Sign out</a> | [% ELSE %]<a class="navlink" onclick="window.open('[% c.uri_for( '/login' ) %]', 'loginwindow', 'height=385,width=445')">Login</a> | <a class="navlink" onclick="window.open('[% c.uri_for( '/register' ) %]', 'regwindow', 'height=385,width=445')">Register</a> | [% END %]<a class="navlink" href="[% c.uri_for( 'about.html' ) %]">About</a> </span>
+ <span class="mainnav">[% IF c.user_exists %]Hello! [% c.user.get_object.email %] <a class="navlink" href="[% c.uri_for( '/logout' ) %]">Sign out</a> | [% ELSE %]<a class="navlink" onclick="window.open('[% c.uri_for( '/login' ) %]', 'loginwindow', 'height=385,width=445')">Login</a> | [% END %]<a class="navlink" href="[% c.uri_for( 'about.html' ) %]">About</a> </span>
</div>
<div id="directory_container">
<h2>Text directory</h2>
- <div id="directory">
- <h3>Loading texts, please wait...</h3>
- <img src="[% c.uri_for( 'images', 'ajax-loader.gif' ) %]" />
- </div>
+ <div id="directory"></div>
[% IF c.user_exists -%]
- <div class="button" id="new_trad_button" onClick="$('#upload-collation-dialog').dialog('open')">
+ <div class="button" id="new_trad_button" onClick="start_upload_dialog();">
<span>Add a new text tradition</span>
</div>
[% END %]
</div>
<div id="textinfo_waitbox">
- <img src="[% c.uri_for( 'images', 'ajax-loader.gif' ) %]" alt="Loading tradition info..."/>
+ <h3>Loading tradition information, please wait...</h3>
+ <img src="[% c.uri_for( 'images', 'ajax-loader.gif' ) %]" alt="Loading tradition info..." />
</div>
<div id="textinfo_container">
+ <div id="textinfo_load_status"></div>
<h2>Text <span class="texttitle"></span></h2>
+ <form id="open_textinfo_edit" action="" method="GET" name="edit_textinfo">
+ <div class="button" id="edit_textinfo_button"
+ onClick="$('#textinfo-edit-dialog').dialog('open')">
+ <span>Modify information about this tradition</span>
+ </div>
+ </form>
<ul>
+ <li>is owned by <span id="owner_id"></span></li>
+ <li>is <span id="not_public"></span>public</li>
+ <li>has <span id="marked_language"></span> as its primary language</li>
<li>has <span id="witness_num"></span> witnesses: <span id="witness_list"></span></li>
- <li>has <span id="reading_num"></span> distinct readings</li>
- <li>has <span id="relationship_num"></span> distinct reading relationships</li>
</ul>
- <!-- TODO buttons on either side of the graph div to flip through the stemmata -->
<div id="textinfo_container_buttons">
<form id="stemma_pager" action="" method="GET" name="stemma_pager">
- <div class="button" id="stemma_pager_button" onClick="$('#stemma_pager').submit()">
- <span>Left & right go here</span>
+ <div id="stemma_pager_buttons">
+ <div class="pager_left_button" id="stemma_pager_left_button"></div>
+ <div class="pager_right_button" id="stemma_pager_right_button"></div>
+ </div>
+ </form>
+ <form id="open_stemma_add" action="" method="GET" name="add_new_stemma">
+ <div class="button" id="stemma_add_button"
+ onClick="$('#stemmaseq').val('n'); $('#stemma-edit-dialog').dialog('open');">
+ <span>Add a new stemma</span>
+ </div>
+ </form>
+ <form id="open_stemma_edit" action="" method="GET" name="edit_current_stemma">
+ <div class="button" id="stemma_edit_button"
+ onClick="$('#stemmaseq').val(selectedStemmaID); $('#stemma-edit-dialog').dialog('open');">
+ <span>Edit this stemma</span>
</div>
</form>
<form id="run_stexaminer" action="" method="GET" name="run_stexaminer">
<div id="stemma_graph"></div>
</div>
+ <!-- Interim 'loading' message for directory box -->
+ <div id="loading_message">
+ <h3>Loading texts, please wait...</h3>
+ <img src="[% c.uri_for( 'images', 'ajax-loader.gif' ) %]" alt="Loading tradition list..."/>
+ </div>
+
+ <!-- Textinfo editor dialog -->
+ <div id="textinfo-edit-dialog" title="Edit information about this tradition">
+ <div id="textinfo_edit_container">
+ <form id="edit_textinfo">
+ <label for="edit_name">Tradition name: </label>
+ <input id="edit_name" type="text" size="30" name="name"/><br/>
+ <label for="edit_language">Language: </label>
+ <input id="edit_language" type="text" size="12" name="language"/>
+ <label for="edit_public">Publicly viewable: </label>
+ <input id="edit_public" type="checkbox" name="public"/><br/>
+[% IF c.user_exists -%]
+[% IF c.user.get_object.is_admin -%]
+ <label for="edit_owner">Tradition owner: </label>
+ <input id="edit_owner" type="text" size="30" name="owner"/><br/>
+[% END -%]
+[% END -%]
+ </form>
+ <div id="edit_textinfo_status"></div>
+ </div>
+ </div>
+
+ <!-- Stemma dot editor dialog, simple textarea for now -->
+ <div id="stemma-edit-dialog">
+ <div id="stemma_edit_container">
+ <form id="edit_stemma">
+ <label for="dot_field">Dot definition for this stemma: </label><br/>
+ <textarea id="dot_field" rows="30" cols="40"></textarea>
+ <input id="stemmaseq" type="hidden" name="stemmaseq" val="n"/>
+ <div id="edit_instructions">
+ <p>All definitions begin with the line
+ <pre>digraph stemma {</pre>
+ and end with the line
+ <pre>}</pre>Please do not change these lines.</p>
+ <p>First list each witness in your stemma, whether extant or lost /
+ reconstructed / hypothetical, and assign them a class of either "extant"
+ or "hypothetical". For example:</p><pre>
+ α [ class=hypothetical ]
+ C [ class=extant ]
+ </pre>
+ <p>Next, list the direct links between witnesses, one per line. For example, if
+ witness C descends directly from witness α, note it as follows:</p><pre>
+ α -> C
+ </pre>
+ <p>A witness may be the exemplar for any number of other witnesses, whether
+ extant or not; likewise, a witness may inherit from any number of other
+ witnesses. Use as may "A -> B" pairings as necessary to describe the links.</p>
+ </div>
+ </form>
+ <div id="edit_stemma_status"></div>
+ </div>
+ </div>
<!-- File upload dialog box -->
<div id="upload-collation-dialog" title="Upload a collation">
- <form id="upload_collation" action="" method="POST" enctype="multipart/form-data" name="upload_collation">
- <label for="traditionname">Name of this text / tradition: </label>
- <input id="traditionname" type="text" name="name" size="40"/><br/>
- <label for="inputfile">Collation file for the tradition: </label>
- <input id="inputfile" type="file" name="inputfile" size="40"/>
- <div id="upload_status"></div>
+ <div id="upload_container">
+ <form id="new_tradition">
+ <label for="new_name">Name of this text / tradition: </label>
+ <input id="new_name" type="text" name="name" size="40"/><br/>
+ <label for="new_lang">Primary language of the text: </label>
+ <input id="new_lang" type="text" name="language" size="20"/><br/>
+ <label for="new_public">Allow public display: </label>
+ <input id="new_public" name="public" type="checkbox"/><br/>
+ <div id="filelist"></div>
+ <form>
+ <div id="upload_status"></div>
<div>
<h4>Supported file types / extensions:</h4>
<ul>
</ul>
<p>All spreadsheet collations should be arranged with the witness sigla in the first row, and the words aligned by row each in its correct witness column.</p>
</div>
- </form>
+ </div>
</div>
[% PROCESS footer.tt %]
\ No newline at end of file