// Need to get this from matplotlib var dpi = 100; // number of products waiting to refresh var inc = 0; var waitimg; // add methods to the product containers // of a certain class. // product container is a jQuery object // "image" is the only type supported currently var extenders = new Object(); extenders["googletimeline"] = function(container) { container.Render = function(env, callback) { // var qs = env.AsQueryString(); } } extenders["image"] = function(container) { // add the Render method container.Render = function(env, callback) { var prodname = container.attr("product"); // Setup the link var link = JQ("//a[@class*=display]", this); var oldimage = JQ("img.display", link).not('.wait'); var customargs = {} //context products have fixed size if (JQ(this).is('.context')) { customargs.width = [oldimage.width()/dpi]; customargs.height = [oldimage.height()/dpi]; } customargs.product = [prodname]; JQ(".parameter", this).each(function(i) { customargs[JQ(this).attr("name")] = [JQ(this).attr("value")]; }); // Build the new query string var qs = env.AsQueryString(customargs); var url = GetURL() + '/getproduct' + qs; link.attr("href", url); // construct the new image var newrealimage = new Image; newrealimage.src = url; JQ(newrealimage).hide(); JQ(newrealimage).addClass("display"); // use the onload event to hide the wait image newrealimage.onload = function() { var oldimage = JQ("img.display", link);//#.not('.wait'); if (container.is('.context')) { JQ(this).width(oldimage.width()); JQ(this).height(oldimage.height()); } oldimage.remove(); // splice in the new image link.append(this); //this.style.display = 'inline'; JQ(this).show(); callback(); }; }; container.Init = function(env, callback) { var oldimage = JQ("img.display", this); oldimage.hide(); oldimage.onload = function() { callback(); }; } // add the Hide method container.Hide = function() { var oldimage = JQ("img.display", this); oldimage.css("-moz-opacity", "0.5"); //oldimage.css("z-index", "20"); oldimage.css("filter", "alpha(opacity=50)"); }; return container; }; function GetProduct(prodname) { // Return a product object corresponding to name var proddivQ = "//div[@class*=renderedproduct][@product=" + prodname + "]"; var proddiv = JQ(proddivQ); var rtype = proddiv.attr("rendertype"); return extenders[rtype](proddiv); } function ProductElement(prod, query) { // Evaluate a query relative to a product div var proddivQ = "//div[@class*=product][@product=" + prod + "]"; return JQ(proddivQ + query); } function GetRefreshButton(prod) { var but = ProductElement(prod, "//[@class*=refreshbutton]"); but.css("position", "absolute"); but.css("z-index", "20"); return but; } JQ(document).ready( function() { // Hide the hidden params JQ(".hidden").parent().hide(); // Assign behaviors var show = function() { JQ(".hidden").parent().show(); JQ('.toggleoptions').val("fewer options"); } var hide = function() { JQ(".hidden").parent().hide(); JQ('.toggleoptions').val("more options"); } if (JQ(".hidden").size() > 0) { JQ(".toggleoptions").toggle(show, hide); } else { JQ(".toggleoptions").hide(); } // make a wait image element waitimg = JQ(document.createElement('img')); waitimg.attr('src', GetWaitURL()); waitimg.addClass('wait'); waitimg.css("z-index", "20"); // activate any refresh buttons JQ("//[@class*=product]").not(".context").each(function(i) { var prod = JQ(this).attr("product"); //var proddiv = GetProduct(prod); //var env = new Environment(prod); //function callback() { // nothing //} //proddiv.Init(env, callback); function refreshme() { RefreshContext(prod); } JQ(".refreshbutton", JQ(this)).bind("click", refreshme); refreshme(); }); var ps = JQ("//form[@class*=factoryform]//div[@class*=parameter]//*"); JQ("//form[@class*=factoryform]//div[@class*=parameter]//*").bind("change", function() { var prod = JQ(this).attr("product"); // Update the links with the new value SetLinkURLs(prod); //hide the image after settings have been changed var proddiv = GetProduct(prod); proddiv.Hide(); // Refresh the SQL-driven parameters var params = JQ("//form[@class='factoryform']//*[@product*=" + prod + "]"); //var params = JQ("//form[@class='factoryform']//div[@class*=parameter]//*[@product="+ prod +"]"); //params.filter("//*[@product="+ prod +"]"); var i = params.index(this); if (i < params.size() && i >= 0) { var after = params.filter(':gt('+ i +')'); var torefresh = after.filter('.refreshable'); torefresh.fadeOut('fast'); if (torefresh.size() > 0) { RefreshParameter(JQ(torefresh.get(0))); } else { GetRefreshButton(prod).show(); } } } ) } ); function toggleLayer( whichLayer ) { JQ("//div[@class*=factoryform][@product=" + whichLayer + "]").toggle(); } function SetLinkURLs(product) { var qs = GetQueryString(product,product); // Set the urls of the links based on the current parameters var prodnode = JQ("//div[@product=" + product + "]") var rlink = ''; rlink = prodnode.find("//a[@id=describelink]"); rlink.attr("href", GetRequestUrl(qs,"describe")) rlink = prodnode.find("//a[@id=getasciilink]"); rlink.attr("href", GetRequestUrl(qs,"getascii")) rlink = prodnode.find("//a[@id=getcsvlink]"); rlink.attr("href", GetRequestUrl(qs,"getcsv")) rlink = prodnode.find("//a[@id=getmatlablink]"); rlink.attr("href", GetRequestUrl(qs,"getmatlab")) } function GetWaitURL() { return 'http://data.stccmop.org/wait.gif'; } function loadJson( url ) { // not using jQuery here. // jQuery seems to trigger a XMLHttpRrequest call // which incurs a permission denied error var script = document.createElement( 'script' ); script.type = 'text/javascript'; script.src = url; document.getElementsByTagName('head')[0].appendChild( script ); } var lock=0; function lock() { while (lock == 1) { } lock = 0; } function Environment(prodname) { var env = this; this.AsQueryString = function(extra) { // Convert an Environment to a Query String. // Assumes environment values are escaped properly // make a copy var copy = {}; for (name in env) { if (name != 'AsQueryString') { copy[name] = env[name]; } } // set any custom properties for (name in extra) { copy[name] = extra[name] } var qs = "?"; for (name in copy) { var vs = copy[name]; for (var i=0; i < vs.length; i++) { qs = qs + '&' + name + '=' + vs[i]; } } return qs; } function append(name, val) { if (env[name]==undefined) { env[name] = val.split(','); } else { env[name] = env[name].concat(val.split(',')); } } JQ("//form[@class*=factoryform]//textarea[@product='" + prodname + "']").each( function(i) { var val; if (JQ(this).attr("type") == "hidden") { val = JQ(this).val(); } else { // user input val = escape(JQ(this).val()); } append(JQ(this).attr('name'), val); } ); // now collect input parameters JQ("//form[@class*=factoryform]//input[@product=" + prodname + "]").each( function(i) { append(JQ(this).attr('name'), JQ(this).val()); } ); // now collect calculated parameters JQ("//form[@class*='factoryform']//div[@class*=CalculatedParameter][@product='" + prodname + "']").each( function(i) { append(JQ(this).attr('name'), JQ(this).text()); } ); // now collect select box parameters JQ("//form[@class*='factoryform']//select[@product="+ prodname +"]/option:selected").each( function(i) { append(JQ(this).parent().attr('name'), JQ(this).val()); } ); } function GetQueryString(prodname, getprod) { var env = new Environment(prodname); return env.AsQueryString({'product' : [getprod]}); } function GetURL() { return 'http://data.stccmop.org/ws/product/factory.py'; } function GetParameter(prodname, param) { selectnode = JQ('//select[@product='+ prodname+'][@name=' + param +']'); return selectnode.get(0); } function NextSQLParameter(prodname, param) { // Return the Next SQL Parameter in document order from the argument // var sels = JQ("//form[@class*='factoryform']//*"); var sels = JQ("//form[@class*='factoryform']//*[@product='"+ prodname +"']"); var index = -1; sels.each( function(i) { if ( JQ(this).attr('name') == param ) { index = i+1; } }); if (index >= sels.size() | index == -1) { return null; } else { var nxt = JQ(sels.get(index)); return nxt; } } function RefreshAll(prodname) { var sels = JQ("//form[@class*='factoryform']//*[@product="+ prodname +"][@class*=refreshable]"); sels.fadeOut('fast'); var fst = sels.get(0); RefreshParameter(JQ(fst)); } function SetValue(product, parameter, val) { var node = JQ("//*[@product='"+ product+"'][@name='" + parameter +"']"); if (node.is('div')) { node.empty(); node.append(val); } else { node.val(val); } // html method may not work properly on IE //node.html(val); if (node.attr('type') != 'hidden') { node.fadeIn('normal'); } var next = NextSQLParameter(product, parameter); if (null == next) { GetRefreshButton(product).show(); } else { RefreshParameter(next); } } function ProcessDomain(domain) { // This call can be slow in IE 6 when parsing a large domain // All the time is spent on the regular expression exec method var dom = JQ(domain); var product = dom.attr("product"); var param = dom.attr("name"); var selectnode = JQ('//select[@product='+ product+'][@name=' + param +']'); // Damn bug with context argument. //s = JQ('//option:selected', selectnode); newopts = dom.children(); var s = new Array(); // This can be a lot simpler with jQuery voodoo, but I ran aground selectnode.children().each( function(i) { if (JQ(this).attr('selected')) { s.push(JQ(this).val()); } }); selectnode.empty(); selectnode.append(newopts); selectnode.children().each( function(i) { JQ(this).attr("selected", false); var v1 = JQ(this).val(); var i=0; for (var i in s) { if (s[i] == v1) { JQ(this).attr("selected", true); break; } } } ); selectnode.fadeIn('slow'); var next = NextSQLParameter(product, param); if (null == next) { GetRefreshButton(product).show(); } else { RefreshParameter(next); } } function RefreshParameter(selectnode) { // Recursive function to refresh the parameter provided // as an argument as well as all downstream parameters. // Argument is expected to be a singleton JQ array. var param = selectnode.attr('name'); var prodname = selectnode.attr('product'); if (selectnode.is('.refreshable') && selectnode.attr('name') != 'product') { var request = ''; if (selectnode.filter('select').size() > 0) { request = 'getdomain'; } else { request = 'getdefault'; } selectnode.end(); // Use dynamic script tags to avoid cross-domain security restrictions var env = new Environment(prodname); var overrides = { 'product' : [prodname], 'request' : [escape(request)], 'ajaxformat' : ['json'], 'parameter' : [escape(param)] }; var qs = "?" + env.AsQueryString(overrides); url = GetURL() + qs; //JQ("//body").append("
" + url + "
"); loadJson(url); } var next = NextSQLParameter(prodname, param); if (null == next) { GetRefreshButton(prodname).show(); } else { RefreshParameter(next); } } function RefreshProduct(prodname, env) { // Get product container var proddiv = GetProduct(prodname); proddiv.Hide(); // Show the wait button var waitimage = ShowWaitImage(proddiv); function callback() { var waitimage = JQ("img.wait",proddiv); waitimage.remove(); } // Re-render the image proddiv.Render(env, callback); } function RefreshContext(prodname) { // hide the refresh button GetRefreshButton(prodname).hide(); // Gather up the environment var env = new Environment(prodname); // update any links SetLinkURLs(prodname); // Refresh the product who triggered the refresh RefreshProduct(prodname, env); // refresh all the context products on the page var proddivQ = "//div[@class*=renderedproduct][@class*=context]"; var contexts = JQ(proddivQ); contexts.each(function(i) { var prodname = JQ(this).attr("product"); RefreshProduct(prodname, env); }); } function ShowWaitImage(proddiv) { // Splice in the wait image proddiv.prepend(JQ(waitimg).clone()); // This query does not work. Yet another XPath bug in jquery. Grrrr... //var waitimage = JQ("//img[class*=wait]",proddiv); var waitimage = JQ("img.wait",proddiv); waitimage.css("position", "absolute"); return waitimage; } function GetRequestUrl(qs, request) { url = GetURL() + '/' + request + qs; return url; }