src/main/webapp/js/singlepage-interface.js
/**
	 * Convert a blacklab-server reply containing information about hits into a table containing the results.
	 *
	 * @param {any} data the blacklab-server response.
	 * @returns An array of html strings containing the <thead> and <tbody>, but without the enclosing <table> element.
	 */
Convert a blacklab-server reply containing information about hits into a table containing the results.
@param {any} data the blacklab-server response.
@returns An array of html strings containing the  and , but without the enclosing  element.
Convert a blacklab - server reply containing information about hits into a table containing the results . @param { any } data the blacklab - server response . @returns An array of html strings containing the and but without the enclosing element .
function formatHits(data, textDirection) {
		var html = [];
		html.push(
			'<thead><tr>',
				'<th class="text-right" style="width:40px">',
					'<span class="dropdown">',
						'<a class="dropdown-toggle" data-toggle="dropdown">',
						textDirection=='ltr'? 'Before hit ' : 'After hit ',
						'<span class="caret"></span></a>',
						'<ul class="dropdown-menu" role="menu" aria-labelledby="left">');
						PROPS.all.forEach(function(prop) { html.push(
							'<li><a data-bls-sort="left:' + prop.id + '">' + prop.displayName + '</a></li>');
						});
						html.push(
						'</ul>',
					'</span>',
				'</th>',
				'<th class="text-center" style="width:20px;">',
					'<a data-bls-sort="hit:' + PROPS.firstMainProp.id + '"><strong>' + PROPS.firstMainProp.displayName + '<strong></a>',
				'</th>',
				'<th class="text-left" style="width:40px;">',
					'<span class="dropdown">', 
						'<a class="dropdown-toggle" data-toggle="dropdown">',
						textDirection=='ltr'? 'After hit ' : 'Before hit ',
						'<span class="caret"></span></a>',
						'<ul class="dropdown-menu" role="menu" aria-labelledby="right">');
						PROPS.all.forEach(function(prop) { html.push(
							'<li><a data-bls-sort="right:' + prop.id + '">' + prop.displayName + '</a></li>');
						});
						html.push(
						'</ul>',
					'</span>',
				'</th>');
			PROPS.shown.forEach(function(prop) { html.push(
				'<th style="width:15px;"><a data-bls-sort="hit:' + prop.id + '">' + prop.displayName + '</a></th>');
			});
		html.push('</tr></thead>');
		html.push('<tbody>');
		var prevHitDocPid = null;
		var numColumns = 3 + PROPS.shown.length; 
		$.each(data.hits, function(index, hit) {
			var docPid = hit.docPid;
			if (docPid !== prevHitDocPid) {
				prevHitDocPid = docPid;
				var doc = data.docInfos[docPid];
				var docTitle = doc[data.summary.docFields.titleField] || 'UNKNOWN';
				var docAuthor = doc[data.summary.docFields.authorField] ? ' by ' + doc[data.summary.docFields.authorField] : '';
				var docDate = doc[data.summary.docFields.dateField] ? ' (' + doc[data.summary.docFields.dateField] + ')' : '';
				var docUrl;
				switch (new URI().filename()) {
					case '':
						docUrl = new URI('../../docs/'); 
						break;
					case 'docs':
					case 'hits':
						docUrl = new URI('../docs/');
						break;
					case 'search':
					default: 
						docUrl = new URI('./docs/');
						break;
				}
				docUrl = docUrl
				.absoluteTo(new URI().toString())
				.filename(docPid)
				.search({
					'query': data.summary.searchParam.patt
				})
				.toString();
				html.push(
					'<tr>',
						'<td colspan="', numColumns, '"><div class="doctitle collapse in">',
							'<a class="text-error" target="_blank" href="', docUrl, '">', docTitle, docAuthor, docDate, '</a>',
						'</div></td>',
					'</tr>');
			}
			var parts = snippetParts(hit);
			var left = textDirection=='ltr'? parts[0] : parts[2];
			var right = textDirection=='ltr'? parts[2] : parts[0];
			var propsWord = properties(hit.match).replace("'","\\'").replace("&apos;","\\'").replace('"', '&quot;');
			html.push(
				'<tr class="concordance" onclick="SINGLEPAGE.INTERFACE.showCitation(this, \''
				+ docPid + '\', '+ hit.start + ', '+ hit.end + ', \'' + textDirection + '\');SINGLEPAGE.INTERFACE.showProperties(this, \''+propsWord+'\');">',
					'<td class="text-right">', ELLIPSIS, ' <span dir="', textDirection, '">', left, '</span></td>',
					'<td class="text-center"><span dir="', textDirection, '"><strong>', parts[1], '</strong></span></td>',
					'<td><span dir="', textDirection, '">', right, '</span> ', ELLIPSIS, '</td>');
					PROPS.shown.forEach(function(prop) { html.push(
						'<td>', words(hit.match, prop.id, false, ''), '</td>');
					});
					html.push(
				'</tr>');
			html.push(
				'<tr>',
					'<td colspan="', numColumns, '" class="inline-concordance"><div class="collapse">Loading...</div></td>',
				'</tr>');
			html.push(
				'<tr>',
					'<td colspan="', numColumns, '" class="inline-concordance"><div class="collapse">Loading...</div></td>',
				'</tr>');
		});
		html.push('</tbody>');
		return html;
	}
function formatHits ( data , textDirection ) { var html = [ ] ; html . push ( '<thead><tr>' , '<th class="text-right" style="width:40px">' , '<span class="dropdown">' , '<a class="dropdown-toggle" data-toggle="dropdown">' , textDirection == 'ltr' ? 'Before hit ' : 'After hit ' , '<span class="caret"></span></a>' , '<ul class="dropdown-menu" role="menu" aria-labelledby="left">' ) ; PROPS . all . forEach ( function ( prop ) { html . push ( '<li><a data-bls-sort="left:' + prop . id + '">' + prop . displayName + '</a></li>' ) ; } ) ; html . push ( '</ul>' , '</span>' , '</th>' , '<th class="text-center" style="width:20px;">' , '<a data-bls-sort="hit:' + PROPS . firstMainProp . id + '"><strong>' + PROPS . firstMainProp . displayName + '<strong></a>' , '</th>' , '<th class="text-left" style="width:40px;">' , '<span class="dropdown">' , '<a class="dropdown-toggle" data-toggle="dropdown">' , textDirection == 'ltr' ? 'After hit ' : 'Before hit ' , '<span class="caret"></span></a>' , '<ul class="dropdown-menu" role="menu" aria-labelledby="right">' ) ; PROPS . all . forEach ( function ( prop ) { html . push ( '<li><a data-bls-sort="right:' + prop . id + '">' + prop . displayName + '</a></li>' ) ; } ) ; html . push ( '</ul>' , '</span>' , '</th>' ) ; PROPS . shown . forEach ( function ( prop ) { html . push ( '<th style="width:15px;"><a data-bls-sort="hit:' + prop . id + '">' + prop . displayName + '</a></th>' ) ; } ) ; html . push ( '</tr></thead>' ) ; html . push ( '<tbody>' ) ; var prevHitDocPid = null ; var numColumns = 3 + PROPS . shown . length ; $ . each ( data . hits , function ( index , hit ) { var docPid = hit . docPid ; if ( docPid !== prevHitDocPid ) { prevHitDocPid = docPid ; var doc = data . docInfos [ docPid ] ; var docTitle = doc [ data . summary . docFields . titleField ] || 'UNKNOWN' ; var docAuthor = doc [ data . summary . docFields . authorField ] ? ' by ' + doc [ data . summary . docFields . authorField ] : '' ; var docDate = doc [ data . summary . docFields . dateField ] ? ' (' + doc [ data . summary . docFields . dateField ] + ')' : '' ; var docUrl ; switch ( new URI ( ) . filename ( ) ) { case '' : docUrl = new URI ( '../../docs/' ) ; break ; case 'docs' : case 'hits' : docUrl = new URI ( '../docs/' ) ; break ; case 'search' : default : docUrl = new URI ( './docs/' ) ; break ; } docUrl = docUrl . absoluteTo ( new URI ( ) . toString ( ) ) . filename ( docPid ) . search ( { 'query' : data . summary . searchParam . patt } ) . toString ( ) ; html . push ( '<tr>' , '<td colspan="' , numColumns , '"><div class="doctitle collapse in">' , '<a class="text-error" target="_blank" href="' , docUrl , '">' , docTitle , docAuthor , docDate , '</a>' , '</div></td>' , '</tr>' ) ; } var parts = snippetParts ( hit ) ; var left = textDirection == 'ltr' ? parts [ 0 ] : parts [ 2 ] ; var right = textDirection == 'ltr' ? parts [ 2 ] : parts [ 0 ] ; var propsWord = properties ( hit . match ) . replace ( "'" , "\\'" ) . replace ( "&apos;" , "\\'" ) . replace ( '"' , '&quot;' ) ; html . push ( '<tr class="concordance" onclick="SINGLEPAGE.INTERFACE.showCitation(this, \'' + docPid + '\', ' + hit . start + ', ' + hit . end + ', \'' + textDirection + '\');SINGLEPAGE.INTERFACE.showProperties(this, \'' + propsWord + '\');">' , '<td class="text-right">' , ELLIPSIS , ' <span dir="' , textDirection , '">' , left , '</span></td>' , '<td class="text-center"><span dir="' , textDirection , '"><strong>' , parts [ 1 ] , '</strong></span></td>' , '<td><span dir="' , textDirection , '">' , right , '</span> ' , ELLIPSIS , '</td>' ) ; PROPS . shown . forEach ( function ( prop ) { html . push ( '<td>' , words ( hit . match , prop . id , false , '' ) , '</td>' ) ; } ) ; html . push ( '</tr>' ) ; html . push ( '<tr>' , '<td colspan="' , numColumns , '" class="inline-concordance"><div class="collapse">Loading...</div></td>' , '</tr>' ) ; html . push ( '<tr>' , '<td colspan="' , numColumns , '" class="inline-concordance"><div class="collapse">Loading...</div></td>' , '</tr>' ) ; } ) ; html . push ( '</tbody>' ) ; return html ; }
Convert a blacklab-server reply containing information about hits into a table containing the results.
Convert a blacklab - server reply containing information about hits into a table containing the results .
// TODO use mustache.js // Span as when it's div, and we're right aligning text, the dropdown doesn't align because the div extends all the way left // Not all properties have their own table columns // before context - hit context - after context - remaining properties // Render a row for this hit's document, if this hit didn't occurred in a new document // TODO the clientside url generation story... https://github.com/INL/corpus-frontend/issues/95 // Ideally use absolute urls everywhere, if the application needs to be proxied, let the proxy server handle it. // Have a configurable url in the backend that's made available on the client that we can use here. // some weird proxy? // Display some info about the document // And display the hit itself // Snippet row (initially hidden) // Properties row (initially hidden)