/**
* HTML module.
* @module html
*/
var dwv = dwv || {};
/**
* Namespace for HTML related functions.
* @class html
* @namespace dwv
* @static
*/
dwv.html = dwv.html || {};
/**
* Append a cell to a given row.
* @method appendCell
* @static
* @param {Object} row The row to append the cell to.
* @param {String} text The text of the cell.
*/
dwv.html.appendCell = function(row, text)
{
var cell = row.insertCell(-1);
var str = text;
// special case for Uint8Array (no default toString)
if ( text instanceof Uint8Array ) {
str = "";
for ( var i = 0; i < text.length; ++i ) {
if ( i > 0 ) {
str += ",";
}
str += text[i];
}
}
cell.appendChild(document.createTextNode(str));
};
/**
* Append a header cell to a given row.
* @method appendHCell
* @static
* @param {Object} row The row to append the header cell to.
* @param {String} text The text of the header cell.
*/
dwv.html.appendHCell = function(row, text)
{
var cell = document.createElement("th");
// TODO jquery-mobile specific...
if( text !== "Value" && text !== "Name" ) {
cell.setAttribute("data-priority", "1");
}
cell.appendChild(document.createTextNode(text));
row.appendChild(cell);
};
/**
* Append a row to an array.
* @method appendRowForArray
* @static
* @param {} table
* @param {} input
* @param {} level
* @param {} maxLevel
* @param {} rowHeader
*/
dwv.html.appendRowForArray = function(table, input, level, maxLevel, rowHeader)
{
var row = null;
// loop through
for(var i=0; i= maxLevel ) {
if( !row ) {
row = table.insertRow(-1);
}
dwv.html.appendCell(row, input[i]);
}
// last level
else {
dwv.html.appendRow(table, input[i], level+i, maxLevel, rowHeader);
}
}
};
/**
* Append a row to an object.
* @method appendRowForObject
* @static
* @param {} table
* @param {} input
* @param {} level
* @param {} maxLevel
* @param {} rowHeader
*/
dwv.html.appendRowForObject = function(table, input, level, maxLevel, rowHeader)
{
var keys = Object.keys(input);
var row = null;
for( var o=0; o= maxLevel ) {
if( !row ) {
row = table.insertRow(-1);
}
if( o === 0 && rowHeader) {
dwv.html.appendCell(row, rowHeader);
}
dwv.html.appendCell(row, input[keys[o]]);
}
// last level
else {
dwv.html.appendRow(table, input[keys[o]], level+o, maxLevel, keys[o]);
}
}
// header row
// warn: need to create the header after the rest
// otherwise the data will inserted in the thead...
if( level === 2 ) {
var header = table.createTHead();
var th = header.insertRow(-1);
if( rowHeader ) {
dwv.html.appendHCell(th, "Name");
}
for( var k=0; k]+>/g, "").toLowerCase();
if (text.indexOf(terms[i]) < 0) {
display = 'none';
} else {
if (terms[i].length) {
dwv.html.highlight(terms[i], table.rows[r]);
}
}
table.rows[r].style.display = display;
}
}
};
/**
* Transform back each
* 'preText term postText'
* into its original 'preText term postText'.
* @method dehighlight
* @static
* @param {Object} container The container to de-highlight.
*/
dwv.html.dehighlight = function(container) {
for (var i = 0; i < container.childNodes.length; i++) {
var node = container.childNodes[i];
if (node.attributes &&
node.attributes['class'] &&
node.attributes['class'].value === 'highlighted') {
node.parentNode.parentNode.replaceChild(
document.createTextNode(
node.parentNode.innerHTML.replace(/<[^>]+>/g, "")),
node.parentNode);
// Stop here and process next parent
return;
} else if (node.nodeType !== 3) {
// Keep going onto other elements
dwv.html.dehighlight(node);
}
}
};
/**
* Create a
* 'preText term postText'
* around each search term.
* @method highlight
* @static
* @param {String} term The term to highlight.
* @param {Object} container The container where to highlight the term.
*/
dwv.html.highlight = function(term, container) {
for (var i = 0; i < container.childNodes.length; i++) {
var node = container.childNodes[i];
if (node.nodeType === 3) {
// Text node
var data = node.data;
var data_low = data.toLowerCase();
if (data_low.indexOf(term) >= 0) {
//term found!
var new_node = document.createElement('span');
node.parentNode.replaceChild(new_node, node);
var result;
while ((result = data_low.indexOf(term)) !== -1) {
// before term
new_node.appendChild(document.createTextNode(
data.substr(0, result)));
// term
new_node.appendChild(dwv.html.createHighlightNode(
document.createTextNode(data.substr(
result, term.length))));
// reduce search string
data = data.substr(result + term.length);
data_low = data_low.substr(result + term.length);
}
new_node.appendChild(document.createTextNode(data));
}
} else {
// Keep going onto other elements
dwv.html.highlight(term, node);
}
}
};
/**
* Highlight a HTML node.
* @method createHighlightNode
* @static
* @param {Object} child The child to highlight.
* @return {Object} The created HTML node.
*/
dwv.html.createHighlightNode = function(child) {
var node = document.createElement('span');
node.setAttribute('class', 'highlighted');
node.attributes['class'].value = 'highlighted';
node.appendChild(child);
return node;
};
/**
* Remove all children of a HTML node.
* @method cleanNode
* @static
* @param {Object} node The node to remove kids.
*/
dwv.html.cleanNode = function(node) {
// remove its children
while (node.hasChildNodes()) {
node.removeChild(node.firstChild);
}
};
/**
* Remove a HTML node and all its children.
* @method removeNode
* @static
* @param {Number} nodeId The id of the node to delete.
*/
dwv.html.removeNode = function(nodeId) {
// find the node
var node = document.getElementById(nodeId);
// check node
if( !node ) {
return;
}
// remove its children
dwv.html.cleanNode(node);
// remove it from its parent
var top = node.parentNode;
top.removeChild(node);
};
/**
* Create a HTML select from an input array of options.
* The values of the options are the name of the option made lower case.
* It is left to the user to set the 'onchange' method of the select.
* @method createHtmlSelect
* @static
* @param {String} name The name of the HTML select.
* @param {Mixed} list The list of options of the HTML select.
* @return {Object} The created HTML select.
*/
dwv.html.createHtmlSelect = function(name, list) {
// select
var select = document.createElement("select");
select.id = name;
select.name = name;
// options
var option;
if( list instanceof Array )
{
for ( var i in list )
{
option = document.createElement("option");
option.value = list[i];
option.appendChild(document.createTextNode(dwv.utils.capitaliseFirstLetter(list[i])));
select.appendChild(option);
}
}
else if( typeof list === 'object')
{
for ( var item in list )
{
option = document.createElement("option");
option.value = item;
option.appendChild(document.createTextNode(dwv.utils.capitaliseFirstLetter(item)));
select.appendChild(option);
}
}
else
{
throw new Error("Unsupported input list type.");
}
return select;
};
/**
* Get a list of parameters from an input URI that looks like:
* [dwv root]?input=encodeURI([root]?key0=value0&key1=value1)
* or
* [dwv root]?input=encodeURI([manifest link])&type=manifest
*
* @method getUriParam
* @static
* @param {String } uri The URI to decode.
* @return {Array} The array of parameters.
*/
dwv.html.getUriParam = function(uri)
{
var inputUri = uri || window.location.href;
// split key/value pairs
var mainQueryPairs = dwv.utils.splitQueryString(inputUri);
// check pairs
if( Object.keys(mainQueryPairs).length === 0 ) {
return null;
}
// has to have an input key
var query = mainQueryPairs.query;
if( !query || !query.input ) {
throw new Error("No input parameter in query URI.");
}
var result = [];
// if manifest
if( query.type && query.type === "manifest" ) {
result = dwv.html.decodeManifestUri( query.input, query.nslices );
}
// if key/value uri
else {
result = dwv.html.decodeKeyValueUri( query.input, query.dwvReplaceMode );
}
return result;
};
/**
* Decode a Key/Value pair uri. If a key is repeated, the result
* be an array of base + each key.
* @method decodeKeyValueUri
* @static
* @param {String} uri The uri to decode.
* @param {String} replaceMode The key replace more.
*/
dwv.html.decodeKeyValueUri = function(uri, replaceMode)
{
var result = [];
// repeat key replace mode (default to keep key)
var repeatKeyReplaceMode = "key";
if( replaceMode ) {
repeatKeyReplaceMode = replaceMode;
}
// decode input URI
var queryUri = decodeURIComponent(uri);
// get key/value pairs from input URI
var inputQueryPairs = dwv.utils.splitQueryString(queryUri);
if ( Object.keys(inputQueryPairs).length === 0 )
{
result.push(queryUri);
}
else
{
var keys = Object.keys(inputQueryPairs.query);
// find repeat key
var repeatKey = null;
for( var i = 0; i < keys.length; ++i )
{
if( inputQueryPairs.query[keys[i]] instanceof Array )
{
repeatKey = keys[i];
break;
}
}
if( !repeatKey )
{
result.push(queryUri);
}
else
{
var repeatList = inputQueryPairs.query[repeatKey];
// build base uri
var baseUrl = inputQueryPairs.base;
// do not add '?' when the repeatKey is 'file'
// root/path/to/?file=0.jpg&file=1.jpg
if( repeatKey !== "file" ) {
baseUrl += "?";
}
var gotOneArg = false;
for( var j = 0; j < keys.length; ++j )
{
if( keys[j] !== repeatKey ) {
if( gotOneArg ) {
baseUrl += "&";
}
baseUrl += keys[j] + "=" + inputQueryPairs.query[keys[j]];
gotOneArg = true;
}
}
// append built urls to result
var url;
for( var k = 0; k < repeatList.length; ++k )
{
url = baseUrl;
if( gotOneArg ) {
url += "&";
}
if( repeatKeyReplaceMode === "key" ) {
url += repeatKey + "=";
}
// other than 'key' mode: do nothing
url += repeatList[k];
result.push(url);
}
}
}
// return
return result;
};
/**
* Decode a manifest uri.
* @method decodeManifestUri
* @static
* @param {String} uri The uri to decode.
* @param {number} nslices The number of slices to load.
*/
dwv.html.decodeManifestUri = function(uri, nslices)
{
var result = [];
// Request error
var onErrorRequest = function(/*event*/)
{
console.warn( "RequestError while receiving manifest: "+this.status );
};
// Request handler
var onLoadRequest = function(/*event*/)
{
result = dwv.html.decodeManifest(this.responseXML, nslices);
};
var request = new XMLHttpRequest();
// synchronous request (third parameter)
request.open('GET', decodeURIComponent(uri), false);
request.responseType = "xml";
request.onload = onLoadRequest;
request.onerror = onErrorRequest;
//request.onprogress = dwv.gui.updateProgress;
request.send(null);
// return
return result;
};
/**
* Decode an XML manifest.
* @method decodeManifest
* @static
* @param {Object} manifest The manifest to decode.
* @param {Number} nslices The number of slices to load.
*/
dwv.html.decodeManifest = function(manifest, nslices)
{
var result = [];
// wado url
var wadoElement = manifest.getElementsByTagName("wado_query");
var wadoURL = wadoElement[0].getAttribute("wadoURL");
var rootURL = wadoURL + "?requestType=WADO&contentType=application/dicom&";
// patient list
var patientList = manifest.getElementsByTagName("Patient");
if( patientList.length > 1 ) {
console.warn("More than one patient, loading first one.");
}
// study list
var studyList = patientList[0].getElementsByTagName("Study");
if( studyList.length > 1 ) {
console.warn("More than one study, loading first one.");
}
var studyUID = studyList[0].getAttribute("StudyInstanceUID");
// series list
var seriesList = studyList[0].getElementsByTagName("Series");
if( seriesList.length > 1 ) {
console.warn("More than one series, loading first one.");
}
var seriesUID = seriesList[0].getAttribute("SeriesInstanceUID");
// instance list
var instanceList = seriesList[0].getElementsByTagName("Instance");
// loop on instances and push links
var max = instanceList.length;
if( nslices < max ) {
max = nslices;
}
for( var i = 0; i < max; ++i ) {
var sopInstanceUID = instanceList[i].getAttribute("SOPInstanceUID");
var link = rootURL +
"&studyUID=" + studyUID +
"&seriesUID=" + seriesUID +
"&objectUID=" + sopInstanceUID;
result.push( link );
}
// return
return result;
};
/**
* Display or not an element.
* @method displayElement
* @static
* @param {Number} id The id of the element to toggle its display.
* @param {Boolean} flag True to display the element.
*/
dwv.html.displayElement = function (id, flag)
{
var element = document.getElementById(id);
if ( element ) {
element.style.display = flag ? "" : "none";
}
};
/**
* Toggle the display of an element.
* @method toggleDisplay
* @static
* @param {Number} id The id of the element to toggle its display.
*/
dwv.html.toggleDisplay = function (id)
{
var element = document.getElementById(id);
if ( element ) {
if ( element.style.display === "none" ) {
element.style.display = '';
}
else {
element.style.display = "none";
}
}
};
/**
* Append an element.
* @method appendElement
* @static
* @param {Number} parentId The id of the element to append to.
* @param {Object} element The element to append.
*/
dwv.html.appendElement = function (parentId, element)
{
var node = document.getElementById(parentId);
if ( element ) {
// append
node.appendChild(element);
// trigger create event (mobile)
$('#'+parentId).trigger("create");
}
};
/**
* Create an element.
* @method createElement
* @static
* @param {String} type The type of the elemnt.
* @param {Number} id The id of the element
*/
dwv.html.createHiddenElement = function (type, id)
{
var element = document.createElement(type);
element.id = id;
// hide by default
element.style.display = "none";
// return
return element;
};