Ticket #9238: trac_9238_interactive_js.patch

File trac_9238_interactive_js.patch, 53.4 KB (added by gutow, 10 years ago)

Patch of notebook_lib.js and jmol_lib.js for interactive enhancements to Jmol in notebook

  • sagenb/data/sage/js/jmol_lib.js

    # HG changeset patch
    # User Jonathan H. Gutow <gutow@uwosh.edu
    # Date 1300821537 18000
    # Node ID 1f6311a9060b14b23dcc36597650962b66eb870a
    # Parent  b0a0157ab2ad8b034004a0950dfaefd440144ac8
    Trac 9238 .js updates for interactive Jmol controls
    
    diff -r b0a0157ab2ad -r 1f6311a9060b sagenb/data/sage/js/jmol_lib.js
    a b  
     1/*
     2Based on the SAGE jmol_lib.js as of 12/13/09
     3Modified by Jonathan Gutow <gutow@uwosh.edu>
     4version 1.1.2 10/15/10
     5version 1.1.3 1/22/11 - can use direct calls to jmolApplet when building page now, should
     6        not have to extract any Jmol.js funtions and turn them into strings anymore. Also
     7        code cleanup and changes to accommodate vocabulary changes in the file created by
     8        SAGE.
     9       
     10        This version limits the number of Jmol applets that may simultaneously be live
     11        on a page.  The default is 5.  This may be set by calling setMaxLiveJmol.
     12
     13        This version places the applet in a div within a table.  The applet is resized to specific
     14        sizes other approaches seem to run amok of the updates from the server.  The default
     15        sizes are miniature (100 x 100 px), small (250 x 250 px), medium (400 x 400 px)
     16        and large (600 x 600 px) choices.   User may choose a random size by using the
     17        "open in separate window" option.
     18        NOTE THIS VERSION IGNORES THE SIZE AS SPECIFIED BY THE SAGE NOTEBOOK CODE.
     19
     20        This version also allows turning on and off surfaces and meshes.  Color of
     21        the surfaces and meshes may also be controlled.  Developed with Jmol version 11.9.
     22        Recommend using Jmol version 12.0.35 or greater.
     23
     24        Things to do:
     25        at present it is using the script saved in the JmolStatus structure to avoid problems
     26        with the scrolling div added to the applet tab.
     27        fix in new window to cleanly use script in JmolStatus structure
     28        make settings save with worksheet.
     29
     30REQUIRES:
     31Jmol.js
     32        path must be specified in the <head> of the page: use jmolInitialize(path), where
     33        "path" = the relative path on the server to this file.
     34
     35notebook_lib.js
     36        uses the get_element(Id) function from this library.
     37        the delete_all_output() call must be modified to call jmol_delete_all_output()
     38        the evaluate_cell() call must be modified to call jmol_delete_check()
     39
     40main.css
     41        where a
     42select.jmol {
     43  border: #aaaaaa;
     44  border-style: solid;
     45  border-top-width: 1px;
     46  border-right-width: 1px;
     47  border-bottom-width: 1px;
     48  border-left-width: 1px
     49}
     50 format is defined.  If it doesn't exist it will still work, but not be as pretty.
     51*/
     52
    153/*global window */
    254/*jslint white: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, strict: true, newcap: true, immed: true */
    355//"use strict";
    456
    557var jmol_count = 0;
    6 //var allowedJmolSize = [1, 2048, 300];
    7 function jmol_applet(size, url) {
    8     var s;
    9     jmolSetDocument(cell_writer);
    10     jmolSetAppletCssClass('jmol_applet');
    11     jmolApplet(size, "script " + url, jmol_count);
    12     s = ' <a href="#" onclick="jmol_image(' + jmol_count +
    13         ');return false;">Get Image</a>';
    14     cell_writer.write(s);
     58
     59var jmolStatus = {
     60    maxLiveAllowed: 5,
     61    numLive: 0,
     62    jmolArray: new Array(),//-1 deleted, 0 awake, 1 sleeping, 2 loading.
     63    urls: new Array(),
     64    defaultdirectory: new Array(),
     65    widths: new Array(),
     66    heights: new Array(),
     67    controlStrs: new Array(),
     68    captionStrs: new Array(),
     69    pictureStrs: new Array(),
     70    stateScripts: new Array(),
     71    cntrls: new Array(),
     72    }
     73
     74//Some default constants
     75//applet sizes
     76miniature = 100;
     77small = 250;
     78medium = 400;
     79large = 600;
     80sleepMessage = "Click to Sleep this 3-D view";
     81wakeMessage = "Wake this 3-D view";
     82captionStr = ''; //empty no caption
     83controlStr = ' '; //could put special controls here.  Must not be empty for default controls to appear, that is why it is a space.
     84
     85function jmol_pulldown(theform) {
     86    /*
     87    This is called when the user selects a menu item.  This just
     88    evaluates the corresponding value, which results in running some
     89    javascript code to do the action.
     90    */
     91    with(theform) {
     92        eval(options[selectedIndex].value);
     93        }
     94    }
     95
     96function jmol_spin (state, n) {
     97    if(state == true){
     98        result = jmolScriptWait("spin on", n);
     99        }else {
     100        result = jmolScriptWait("spin off", n);
     101        }
     102    storeDefaultDir(n);
     103    jmolUpdateState(n);
     104    }
     105
     106function jmol_show_element(state,whichsurface, type ,n) {
     107    if(state == true){
     108        scriptStr = ''+type+' '+whichsurface+' on;';
     109        result = jmolScriptWait(scriptStr, n);
     110        }else {
     111        scriptStr = ''+type+' '+whichsurface+' off;';
     112        result = jmolScriptWait(scriptStr, n);
     113        }
     114    storeDefaultDir(n);
     115    jmolUpdateState(n);
     116    }
     117
     118function do_jmolScriptWait(scriptStr, n){
     119    result = jmolScriptWait(scriptStr,n);
     120    storeDefaultDir(n);
     121    jmolUpdateState(n);
     122    }
     123
     124function jmolSurfColor(color,surface,n){
     125    scriptStr = 'color $'+surface+' '+color;
     126    result = jmolScriptWait(scriptStr,n);
     127    storeDefaultDir(n);
     128    jmolUpdateState(n);
     129    }
     130
     131function jmolCntrlPanel(state, panelID, tabID, tabName, panelHTML){ //The default definition for a jmolcontrolpanel
     132    this.state = state; //0 active, 1 inactive, 2 hidden ...other numbers for future possibilities
     133    this.panelID = panelID;
     134    this.tabID = tabID;
     135    this.tabName=tabName;
     136    this.panelHTML=panelHTML;
     137    }
     138
     139function jmolUpdateState(n){
     140    var divID = 'jmolStateDiv'+n;
     141    var stateStr ="#a comment to guarrantee one line";
     142    stateStr+= jmolGetPropertyAsString("stateInfo", "", n);
     143    re_modelinline = /data "model list"(.|\n|\r)*end "model list"/;
     144    var modelStr = (stateStr.match(re_modelinline))[0];
     145    modelStr = modelStr.replace(/\r\n/g,'|').replace(/\r/g, '|').replace(/\n/g,'|').replace(/\|\|/g, '|');
     146//    modelStr = 'fix between here '+modelStr+' and here';
     147    stateStr = stateStr.replace(re_modelinline, modelStr);
     148    re_endofline = /\n/g;
     149    re_doublequote = /"/g;
     150    get_element(divID).innerHTML = '<div style="overflow:scroll;max-height:400px;">set '+ jmolStatus.defaultdirectory[n] +';<br>'+stateStr.replace(re_endofline,'<br>')+'</div>';
     151    jmolStatus.stateScripts[n] = 'set '+ jmolStatus.defaultdirectory[n] +';\n'+stateStr;
     152    }
     153
     154function storeDefaultDir(n) {
     155    result = jmolScript('set MessageCallback "jmolMessageHandler"; show defaultdirectory; delay 1;',n);
     156    }
     157
     158var jmolLastDefaultDir = '';
     159
     160function jmolMessageHandler(applet, messageStr, number) {
     161    re_defaultdirectory =/defaultdirectory/i;
     162    re_jmolApplet = /jmolApplet/i;
     163    var javaScriptStr = ''+messageStr;
     164    var appletname = ""+applet;
     165    var messagenum = ""+number;
     166    if (javaScriptStr.search(re_defaultdirectory)!=-1){
     167        jmolLastDefaultDir = javaScriptStr;
     168        appletN = appletname[appletname.search(re_jmolApplet),(appletname.length-1)];
     169        jmolStatus.defaultdirectory[appletN]= javaScriptStr;
     170        }
     171   }
     172
     173
     174function jmolCntrlPanels(whichActive,cntrlPanels){ //The default definition for a group of jmolCntrlPanels
     175    this.whichActive = whichActive; //array index for the active, front, panel
     176    this.cntrlPanels= cntrlPanels; //array of jmolCntrlPanel
     177    }
     178
     179function makeCntrlPanels(url, n, functionnames){
     180    var panels = new Array();
     181    //Applet options: size, background color, spinning etc...
     182    panelID = 'size_jmol'+n;
     183    tabID = 'tab_'+panelID;
     184    //size control
     185    panelHTML ='3-D display size: <select class="jmol" title ="Select a size" onchange="jmol_pulldown(this);">';
     186    panelHTML += '<option value = "jmolResizeApplet('+miniature+','+n+');"> Miniature ('+miniature+'px)</option>';
     187    panelHTML += '<option  value = "jmolResizeApplet('+small+','+n+');"> Small ('+small+'px)</option>';
     188    panelHTML += '<option selected = "" value = "jmolResizeApplet('+medium+','+n+');"> Medium ('+medium+'px)</option>';
     189    panelHTML += '<option value = "jmolResizeApplet('+large+','+n+');"> Large ('+large+'px)</option>';
     190    panelHTML += '</';
     191    panelHTML += 'select><br/>';
     192    panelHTML +='<ul><li><a href="javascript:void(jmol_popup(\''+n+'\'))">Arbitrarily resizable in own window</a></li>';
     193    //static image to save
     194    panelHTML +='<li><a href="javascript:void(jmol_image('+n+'))">Get static image to save</a></li>';
     195    panelHTML +='<hr/>';
     196    //spin on
     197    panelHTML +='<input class="worksheet" type="checkbox" value="spin on" onchange="jmol_spin(this.checked,'+n+');" title="Enable/disable spin"/>Spin on';
     198    //background color
     199    panelHTML += '';
     200    panels[0] = new jmolCntrlPanel(0, panelID, tabID, "Display",panelHTML);
     201    //Function Display Options
     202    panelID = 'disp_jmol'+n;
     203    tabID = 'tab_'+panelID;
     204    if(functionnames ==''||functionnames==undefined){//no names for the functions so cannot build list, will have to get after Jmol launched
     205        panelHTML = '<a href="javascript:void(getSurfacesFromJmol('+n+'))">Click to request functions from Jmol</a> so that you can adjust function color and mesh.';
     206        }else{//step through functionnames and make list of functions.
     207        panelHTML ='<table><tr><td>Function Name</td><td>On</td><td>Color</td><td>Translucent</td><td>Mesh</td><td>Mesh Color</td></tr>';
     208        var funcs=functionnames.split(',');
     209        for(i in funcs){
     210            }
     211        str+='</table>';
     212        }
     213    panels[1] = new jmolCntrlPanel(1, panelID, tabID, "Color, Mesh, etc...",panelHTML);
     214    //Axes to be done
     215    //State will be hidden long term
     216    panelID = 'jmolStateDiv'+n;
     217    tabID = 'tab_'+panelID;
     218    panelHTML ='# Blank script';
     219    panels[2] = new jmolCntrlPanel(2, panelID, tabID,"State", panelHTML);
     220    return (new jmolCntrlPanels(0, panels)); //this will then be plugged into jmolStatus.cntrls[n]
     221    }
     222
     223function setMaxLiveJmol(maxLive) { //sets maximum applets live at once.
     224    jmolStatus.maxLiveAllowed = maxLive;
     225    }
     226
     227function jmol_applet(size, url, cell_num, functionnames) { //makes a new applet. Presently ignoring size, kept for backwards compatibility
     228    size = medium; //overriding value from server.  Probably should accept server value.
     229    jmolSetDocument(false);
     230    //Where am I?  Need to know in cases where I need to write directly to this cell.  Not used initially.
     231    cell_ID = 'cell_output_html_'+cell_num;
     232    //write everything to the cell using cell writer so that it will appear next time the cell is opened.
     233    cntrlPanels = makeCntrlPanels(url, jmol_count, functionnames);
     234    controlStr = makeControlStr(url, jmol_count, cntrlPanels);
     235    str = newJmolTableStr(jmolStatus, size, size, url, wakeMessage, sleepMessage, captionStr, controlStr);
     236    //add debugging div
     237    //str += '<div id="JmolDebug">Jmol Debugging goes here</div>';
     238    //sleep some if necessary
     239    limitlive(jmol_count, jmolStatus);
     240    //now we can start the new one
     241    cell_writer.write(str);
     242    var scriptStr = 'script "'+url+'"; isosurface fullylit; pmesh o* fullylit; set antialiasdisplay on;';
     243    scriptStr += 'set MessageCallback "jmolMessageHandler"; show defaultdirectory; delay 1; javascript "jmolAppletLive('+ jmol_count +');jmolUpdateState('+ jmol_count +');";';
     244    jmolSetAppletColor("white");
     245    //we will still set all the data for this applet so that other asynchronously created applets do not grab its ID.
     246    jmolStatus.urls[jmol_count]=url;
     247    jmolStatus.widths[jmol_count] = size;
     248    jmolStatus.heights[jmol_count]= size;
     249    jmolStatus.numLive = jmolStatus.numLive+1;
     250    jmolStatus.jmolArray[jmol_count] = 2; //it's now  "loading".
     251    jmolStatus.controlStrs[jmol_count] = controlStr;
     252    jmolStatus.captionStrs[jmol_count] = captionStr;
     253    jmolStatus.cntrls[jmol_count]=cntrlPanels;
    15254    jmol_count += 1;
    16     return s;
     255    //Now we wait for the server by calling a function that waits if the div is not yet written.
     256    launchNewJmol(size,scriptStr,(jmol_count-1));
     257    return str;
     258    }
     259
     260function launchNewJmol(size,scriptStr,n){
     261        if (!get_element("Jmol"+ n)){
     262            var launchStr = 'launchNewJmol('+size+',\''+scriptStr+'\','+n+')';
     263//            alert("Waiting for Jmol"+n+" div.");
     264            setTimeout(launchStr, 500);
     265        }else{
     266            get_element("Jmol"+ n).innerHTML = jmolApplet([size, size], scriptStr, n);
     267//            jmolStatus.jmolArray[n]=0; //it's done loading and is "live".
     268        }
     269    }
     270
     271function jmolAppletLive(n){//called after an applet is loaded to say set state to live
     272        jmolStatus.jmolArray[n]=0;
     273    }
     274function newJmolTableStr(jmolStatus, width, height, url, wakeMessage, sleepMessage, captionStr, controlStr){
     275    //if captionStr or controlStr is the empty string, '', then the caption or the controls  respectively will not be shown.
     276    n = jmolStatus.jmolArray.length;
     277    Id = 'Jmol'+n;
     278    tableId = 'Jmol_Table_'+Id;
     279    tableStr = '<table id="'+tableId+'" border="1"><tr><td id="'+tableId+'_cell_0_0">';
     280        if (controlStr!='') {
     281            tableStr+='<div id=\'Adv_but_'+Id+'\'><button onClick="$(\'#'+tableId+'_cell_0_1\').toggle();">Toggle Advanced Controls</button></div>';
     282            }   
     283    tableStr +='<div id = '+Id+'>';
     284    tableStr += 'Loading Jmol 3-D viewer...</div>'; 
     285            tableStr+='</td>';
     286    if (controlStr!=''){
     287            //tempCntrlStr = '<a href="javascript:void(wakeJmol('+n+',jmolStatus))">'+ wakeMessage +'</a>';
     288            tempCntrlStr ='<button onClick="javascript:void(sleepJmol('+n+',jmolStatus))">'+sleepMessage+'</button>';
     289        tempCntrlStr += '<button onClick="javascript:void(jmol_help())">Help for Jmol 3-D viewer</button>'+controlStr;
     290        tableStr += '<td id="'+tableId+'_cell_0_1" style="display:none;">'+tempCntrlStr+'</td>';
     291            }
     292    tableStr += '</tr>';
     293    if (captionStr !=''){
     294            tableStr +='<tr><td>'+captionStr+'</td></tr>';
     295        }
     296    tableStr += '</table>';
     297    return (tableStr);
     298    }
     299
     300function makeControlStr(url, n, cntrlPanels){
     301    //This function makes the string that contains the controls other than the default wake and sleep links.
     302    //These are extracted from the cntrlPanels structure passed from the calling routine
     303    cntrlID= 'cntrl_jmol'+n;
     304    str = '<div id="'+cntrlID+'" class="ui-tabs">';
     305    //make tabs
     306    str+= '<ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header">';
     307    for (i in cntrlPanels.cntrlPanels){
     308        if(cntrlPanels.cntrlPanels[i].state==0){
     309            classStr = "ui-tabs-selected ui-widget-content";
     310            }else{
     311            classStr ="ui-state-default";
     312            }
     313         if(cntrlPanels.cntrlPanels[i].state==2){
     314            classStr = "hidden";
     315            }
     316        str+='<li id="'+cntrlPanels.cntrlPanels[i].tabID+'" class="'+classStr+'">';
     317        whichWake = cntrlPanels.cntrlPanels[i].isActive;
     318        tabName = cntrlPanels.cntrlPanels[i].tabName;
     319        str+='<a href="javascript:void(switchJmolCntrl(jmolStatus,'+n+','+i+'))">'+tabName+'</a></li>';
     320        }
     321    str += '</ul>';
     322    //make panels
     323    for (i in cntrlPanels.cntrlPanels){
     324        panelID = cntrlPanels.cntrlPanels[i].panelID;
     325        if(cntrlPanels.cntrlPanels[i].state==0){
     326            classStr = "ui-tabs-panel";
     327            }else{
     328            classStr ="ui-tabs-panel ui-tabs-hide";
     329            }       
     330        str+='<div id="'+panelID+'" class ="'+classStr+'">';
     331        str+= cntrlPanels.cntrlPanels[i].panelHTML;
     332        str+= '</div>';
     333        }
     334    str+='</div>';
     335    return str;
     336    }
     337
     338function getSurfacesFromJmol(n){
     339    var surfaceListStr = jmolGetPropertyAsString("stateInfo", "modelState", n);
     340    var scriptArray=parseJmolStateInfoForSurfaces(surfaceListStr);
     341    var surfaceArray = makeJmolSurfaceArray2(scriptArray);
     342    var dispStr='';
     343    if (scriptArray[0]==''||scriptArray[0]==null||scriptArray[0]=='null'||scriptArray[0]==undefined||scriptArray[0]=='undefined') {//no surfaces ?!
     344        dispStr = 'No surfaces recovered from Jmol.  Sorry.';
     345        }
     346//    for (i in scriptArray){
     347//        dispStr +=scriptArray[i]+'<br/>';
     348//        }
     349    dispStr +='<table  border="1"><tr><td>Function</td><td>Color</td><td>Translucency</td><td>On?</td><td>Mesh Color</td><td>Mesh on?</td></tr>';
     350    for (i in surfaceArray){
     351//        dispStr +='Surface #'+i+'<br/>';
     352        dispStr +='<tr>';
     353//        dispStr +='Type:'+surfaceArray[i].type+'<br/>';
     354//        dispStr +='ID:' +surfaceArray[i].ID+'<br/>';
     355        dispStr +='<td>'+surfaceArray[i].ID+'</td>';
     356//        dispStr +='Source:' +surfaceArray[i].source+'<br/>';
     357//        dispStr +='Source Type:'+surfaceArray[i].sourceType+'<br/>';
     358//        dispStr +='Color:' +surfaceArray[i].color+'<br/>';
     359        var scriptStr = 'color $'+surfaceArray[i].ID+' $COLOR$';
     360        var boxIdStr = 'colorBox_'+n+'_'+i;
     361        dispStr +='<td>'+JmolColorPickerBoxStr(scriptStr,surfaceArray[i].color,boxIdStr,n)+'</td>';
     362//        dispStr +='Fill State:' +surfaceArray[i].fillState+'<br/>';
     363        dispStr +='<td><select class="jmol" title ="Select transparency" onchange="jmolSurfColor(this.value,\''+surfaceArray[i].ID+'\','+n+');">';
     364        dispStr +='<option selected="" value ="'+surfaceArray[i].fillState+'">Default</option>';
     365        var fillState='opaque';
     366        dispStr +='<option value = "'+ fillState +'">opaque</option>';
     367        fillState = 'translucent 32';
     368        dispStr +='<option value = "'+ fillState +'">translucent 32</option>';
     369        fillState ='translucent 64';
     370        dispStr +='<option value = "'+ fillState +'">translucent 64</option>';
     371        fillState = 'translucent 96';
     372        dispStr +='<option value = "'+ fillState +'">translucent 96</option>';
     373        fillState ='translucent 128';
     374        dispStr +='<option value = "'+ fillState +'">translucent 128</option>';
     375        dispStr +='</';
     376        dispStr += 'select></td>';
     377//        dispStr +='Visibility:' +surfaceArray[i].visibility+'<br/>';
     378        var checkedStr = 'checked = "true"';
     379        re_off = /off/i;
     380        if (surfaceArray[i].visibility.match(re_off)){
     381            checkedStr = '';
     382            }
     383        dispStr +='<td><input class="worksheet" type="checkbox" '+checkedStr+' onchange="jmol_show_element(this.checked,\''+surfaceArray[i].ID+'\',\''+surfaceArray[i].type+'\','+n+');" title="Show function"/></td>';
     384//        dispStr +='Mesh ID:' +surfaceArray[i].mesh_ID+'<br/>';
     385//        dispStr +='Mesh Color:' +surfaceArray[i].meshColor+'<br/>';
     386        if (surfaceArray[i].mesh_ID ==''){//we don't have a mesh so  need to make one
     387            scriptStr = surfaceArray[i].type+' '+surfaceArray[i].ID+'_mesh '+surfaceArray[i].sourceType+' '+surfaceArray[i].source+'noFill mesh;';
     388            scriptStr += surfaceArray[i].type+' fullylit off;';
     389            scriptStr += 'color '+surfaceArray[i].type+' opaque [x000000];';
     390            result = jmolScriptWait(scriptStr, n);
     391            surfaceArray[i].mesh_ID=surfaceArray[i].ID+'_mesh';
     392            //mesh doesn't stay off
     393//            scriptStr = surfaceArray[i].type+' '+surfaceArray[i].mesh_ID+' off;';
     394//            result = jmolScriptWait(scriptStr, n);
     395            surfaceArray[i].meshColor = '[x000000]';
     396            surfaceArray[i].mesh_visibility = 'off';
     397            //we've changed the state, so save
     398            storeDefaultDir(n);
     399            jmolUpdateState(n);
     400            }
     401        scriptStr = 'color $'+surfaceArray[i].mesh_ID+' $COLOR$';
     402        boxIdStr = 'colorBox_'+n+'_'+i+'_mesh';
     403        dispStr +='<td>'+JmolColorPickerBoxStr(scriptStr,surfaceArray[i].meshColor,boxIdStr,n)+'</td>';
     404//        dispStr +='Mesh Fill State:' +surfaceArray[i].meshState+'<br/>';
     405//        dispStr +='Mesh Visibility:' +surfaceArray[i].mesh_visibility+'<br/>';
     406        checkedStr = 'checked = "true"';
     407        if (surfaceArray[i].mesh_visibility.match(re_off)){
     408            checkedStr = '';
     409            }
     410        dispStr +='<td><input class="worksheet" type="checkbox" '+checkedStr+' onchange="jmol_show_element(this.checked,\''+surfaceArray[i].mesh_ID+'\',\''+surfaceArray[i].type+'\','+n+');" title="Show mesh"/></td>';
     411         dispStr +='</tr>';
     412        }
     413    dispStr +='</table>';
     414    displayID = 'disp_jmol'+n;
     415    get_element(displayID).innerHTML= dispStr;
     416    }
     417
     418function parseJmolStateInfoForSurfaces(stateInfoStr){
     419    //Returns an array of strings containing the script commands for creating and loading surfaces, pmesh or isosurface.
     420    var tempStrArray=stateInfoStr.split(';');
     421    scriptArray = new Array();
     422    re_isosurface = /\s*isosurface/;
     423    re_pmesh =/\s*pmesh/;
     424    linecount = 0;
     425    for (i in tempStrArray){
     426        if(tempStrArray[i].match(re_isosurface)||tempStrArray[i].match(re_pmesh)){
     427            scriptArray[linecount]=tempStrArray[i]; //Safari doesn't like .append()?
     428            linecount=linecount+1;
     429            }
     430        }
     431    return scriptArray;
     432    }
     433
     434function makeJmolSurfaceArray2(scriptArray){
     435    //generates an array of surfaceState objects.  One for each surface.
     436    var surfaceArray = new Array();
     437    var surface_count = 0;
     438    var lastID = '';
     439    var lastSurface = -1;
     440    var lastIsMesh = false;
     441    for (i in scriptArray){
     442        properties = parseScriptLine(scriptArray[i],lastIsMesh);
     443        k = 0;
     444        which = -1;
     445        while (k < surface_count){//if we get a match we're looking at a second load, so just update info.
     446           if((properties.ID == surfaceArray[k].ID && surfaceArray[k].ID!='')||(properties.mesh_ID==surfaceArray[k].mesh_ID && surfaceArray[k].mesh_ID!='')
     447                  ||(properties.source == surfaceArray[k].source && surfaceArray[k].source!='')){
     448               which = k;
     449               k=surface_count; // found a match we're done
     450               } else {
     451               k=k+1;
     452               } //end if
     453            }//end while k<surface_count
     454        if (properties.ID=='' && properties.mesh_ID=='' && properties.source == '' && lastSurface>=0) {//this is just update to previous line...
     455             which = lastSurface;
     456             }//end update to previous line
     457        if (which == -1) {//new surface
     458            surfaceArray[surface_count] = new surfaceState(properties.type, properties.ID, properties.source, properties.sourceType,
     459                     properties.color, properties.fillState, properties.visibility, properties.mesh_ID, properties.meshColor,
     460                     properties.meshState, properties.mesh_visibility);
     461            lastSurface = surface_count;
     462            surface_count = surface_count + 1;
     463            } else {//existing surface update only things that are not empty strings and don't corrupt existing labels.
     464            if (properties.type!=''){
     465                surfaceArray[which].type = properties.type;
     466               }
     467            if (properties.sourceType!=''&& surfaceArray[which].sourceType==''){
     468                surfaceArray[which].sourceType = properties.sourceType;
     469               }
     470            if (properties.ID!='' && surfaceArray[which].ID==''){
     471               surfaceArray[which] = properties.ID;
     472               }
     473            if (properties.source!='' && surfaceArray[which].source==''){
     474               surfaceArray[which].source = properties.source;
     475               }
     476            if (properties.color!='') {
     477               surfaceArray[which].color = properties.color;
     478               }
     479            if (properties.fillState!=''){
     480               surfaceArray[which].fillState = properties.fillState;
     481               }
     482            if (properties.visibility!='') {
     483               surfaceArray[which].visibility = properties.visibility;
     484               }
     485            if (properties.mesh_ID!='' && surfaceArray[which].mesh_ID=='') {
     486               surfaceArray[which].mesh_ID = properties.mesh_ID;
     487               }
     488            if (properties.meshColor!='') {
     489               surfaceArray[which].meshColor = properties.meshColor;
     490               }
     491            if (properties.mesh_visibility!='') {
     492               surfaceArray[which].mesh_visibility = properties.mesh_visibility;
     493               }
     494            if (properties.meshState!='') {
     495               surfaceArray[which].meshState = properties.meshState;
     496               }
     497            lastSurface = which;
     498            }//end new or old surface
     499            if (properties.ID=='' && properties.mesh_ID!='') {
     500                lastIsMesh=true;
     501                }else{
     502                lastIsMesh=false;
     503                }     
     504        }//end stepping through scriptArray
     505    return (surfaceArray);
     506    }
     507
     508function parseScriptLine(scriptLine, lastIsMesh){
     509    var properties = {
     510        type: '',
     511        source: '',
     512        sourceType: '',
     513        ID: '',
     514        color: '',
     515        fillState: '',
     516        visibility: '',
     517        mesh_ID: '',
     518        meshColor: '',
     519        meshState: '',
     520        mesh_visibility: '',
     521        }
     522    re_wordboundary = /\s+/;
     523    var wordList = scriptLine.split(re_wordboundary);
     524    firstIndex = 0;
     525    if (wordList[0]=='') {
     526        firstIndex = 1;
     527        }
     528    if (wordList[firstIndex] == 'isosurface') {
     529       properties.type = 'isosurface';
     530       properties = parseIsosurfaceCmd(properties, wordList);
     531       }
     532    if (wordList[firstIndex] == 'pmesh') {
     533       properties.type = 'pmesh';
     534       properties = parsePmeshCmd(properties, wordList);
     535       }
     536    if (wordList[firstIndex] == 'color') {
     537       properties = parseColorCmd(properties, wordList);
     538       }
     539    if (lastIsMesh == true) {//check that the mesh values and non-mesh are not flipped
     540       if(properties.color!=''&&properties.meshColor==''){
     541           properties.meshColor=properties.color;
     542           properties.color='';
     543           }
     544       if(properties.visibility!=''&&properties.mesh_visibility==''){
     545           properties.mesh_visibility =properties.visibility;
     546           properties.visibility ='';
     547           }
     548       if(properties.fillState!=''&&properties.meshState==''){
     549           properties.meshState =properties.fillState;
     550           properties.fillState ='';
     551           }
     552       }
     553    return (properties);
     554    }
     555
     556function parseColorCmd(properties, wordList){
     557    re_dollarsign = /^$/;
     558    re_colorcode=/\[x.{6}\]/;
     559    re_translucent =/translucent/i;
     560    firstIndex = 0;
     561    if (wordList[0]=='') {
     562        firstIndex = 1;
     563        }
     564    parseFrom = firstIndex+2;
     565    if(wordList[firstIndex+1].match(re_dollarsign)) {
     566        properties.ID = wordList[firstIndex+1].replace('$','').toLowerCase();
     567        }
     568    for (i=parseFrom; i<wordList.length; i++){
     569        if (wordList[i]=='opaque') {
     570           properties.fillState = 'opaque';
     571           }//end opaque
     572        if (wordList[i].match(re_translucent)){
     573           properties.fillState = 'translucent';
     574           if (wordList[i+1].match(re_number)){
     575               properties.fillState='translucent '+wordList[i+1];
     576               }//end is it followed by number?
     577           }//end translucent
     578        if (wordList[i].match(re_colorcode)){
     579           properties.color = wordList[i];
     580           }//end colorcode
     581        }
     582    return properties;
     583    }
     584
     585function parsePmeshCmd(properties, wordList){
     586    return (parseIsosurfaceCmd(properties,wordList));
     587    }
     588
     589function parseIsosurfaceCmd(properties, wordList){
     590    firstIndex = 0;
     591    if (wordList[0]=='') {
     592        firstIndex = 1;
     593        }
     594    parseFrom = firstIndex+3;
     595    re_quoted = /".*"/;
     596    re_number = /d*\.*d*/;
     597    re_quote_global = /"/g;
     598    re_mesh = /mesh/i;
     599    re_nomesh = /nomesh/i;
     600    re_fill = /fill/i;
     601    re_nofill = /nofill/i;
     602    re_hidden = /hidden/i;
     603    if (wordList[firstIndex + 1]=='ID') {//modifying an existing surface
     604        properties.ID = (wordList[firstIndex + 2].replace(re_quote_global,'')).toLowerCase(); //if we're lucky and the name is not broken into two words?
     605        }else{
     606        properties.ID = (wordList[firstIndex + 1].replace(re_quote_global,'')).toLowerCase(); //if it is the loaded object name we will have to remove the quotes.
     607        if (wordList[firstIndex + 1].match(re_quoted)) {
     608            properties.source = wordList[firstIndex + 1];
     609            }//end if this word is in quotes
     610        parseFrom = firstIndex + 2;
     611        } //end wordList[firstIndex + 1]=='ID'
     612    for (i=parseFrom; i<wordList.length; i++){
     613        if (wordList[i].match(re_mesh)) {
     614           properties.mesh_visibility = 'on';
     615           }//end mesh
     616        if (wordList[i].match(re_nomesh)){
     617           properties.mesh_visibility = 'off';
     618           }//end nomesh
     619        if (wordList[i].match(re_fill)){
     620           properties.visibility = 'on';
     621           }//end fill
     622        if (wordList[i].match(re_nofill)){
     623           properties.visibility = 'off';
     624           }//end nofill
     625        if (wordList[i]=='opaque') {
     626           properties.fillState = 'opaque';
     627           }//end opaque
     628        if (wordList[i]=='translucent'){
     629           if (wordList[i+1].match(re_number)){
     630               properties.fillState='translucent '+wordList[i+1];
     631               }else{
     632               properties.fillState = 'translucent';
     633               }//end is it followed by number?
     634           }//end translucent
     635        if (wordList[i].match(re_quoted)) {
     636            properties.source = wordList[i];
     637            //check for sourceType
     638            re_pmesh = /pmesh/i;
     639            if(wordList[i-1].match(re_pmesh)){
     640                properties.sourceType = 'pmesh';
     641                }//end check for pmesh source type.
     642            if(properties.type=='pmesh'){
     643                properties.sourceType = 'pmesh';
     644                }//setting to match type if pmesh.
     645            }//end if this word is in quotes
     646        if (wordList[i].match(re_hidden)) {
     647            properties.visibility='off';
     648            }//end hidden
     649        }//end for
     650    //decide if this is only a mesh surface.
     651    if (properties.mesh_visibility=='on' && (properties.visibility=='off')) {//just mesh
     652        properties.mesh_ID = properties.ID;
     653        properties.ID = '';
     654        properties.meshColor = properties.color;
     655        properties.color = '';
     656        properties.mesh_visibility = properties.visibility;
     657        properties.visibility = '';
     658        }//end if mesh
     659    return properties;
     660    }
     661
     662function surfaceState(type, ID, source, sourceType, color, fillState, visibility, mesh_ID, meshColor, meshState, mesh_visibility){
     663    this.type = type; //'isosurface' or 'pmesh'
     664    this.ID = ID; //the ID string used by Jmol
     665    this.source=source; //the source filename (not the full path, should it be?)
     666    this.sourceType = sourceType; // "pmesh" if necessary for isosurface command
     667    this.color = color; //hex value for the color of the surface, default is yellow [xFFFF00]
     668    this.fillState = fillState; // "opaque" or "transparent" or "transparent 0.XX"
     669    this.visibility = visibility; //"on" or "off"
     670    this.mesh_ID = mesh_ID; //the ID string used by Jmol
     671    this.meshColor = meshColor; //hex value for the color of the mesh, default is black [x000000]
     672    this.meshState = meshState; //  "opaque" or "transparent" or "transparent 0.XX"
     673    this.mesh_visibility = mesh_visibility; // "on" or "off"
     674    }
     675
     676function switchJmolCntrl(jmolStatus,n,whichWake){//whichWake is the numerical index of the panel to wake
     677    //making use of the jsquery-ui defaults loaded in with SAGE, but cannot use their functions to switch tabs (don't know why).
     678    //Check to see if whichWake is already awake
     679    isActive = jmolStatus.cntrls[n].whichActive
     680    if(whichWake== isActive){
     681        return;
     682        }
     683    //first sleep the active panel.
     684    get_element(jmolStatus.cntrls[n].cntrlPanels[isActive].panelID).setAttribute('class','ui-tabs-panel ui-tabs-hide');
     685    get_element(jmolStatus.cntrls[n].cntrlPanels[isActive].tabID).setAttribute('class', 'ui-state-default');
     686    jmolStatus.cntrls[n].cntrlPanels[isActive].state=1;
     687    //Now unhide the control requested.
     688    get_element(jmolStatus.cntrls[n].cntrlPanels[whichWake].tabID).setAttribute('class', 'ui-tabs-selected ui-widget-content');
     689    get_element(jmolStatus.cntrls[n].cntrlPanels[whichWake].panelID).setAttribute('class','ui-tabs-panel');
     690    jmolStatus.cntrls[n].cntrlPanels[whichWake].state=0;
     691    jmolStatus.cntrls[n].whichActive=whichWake;
     692    }
     693
     694function sleepJmol(n,jmolStatus) {
     695    if(jmolStatus.jmolArray[n]==0){//it's awake, so put to sleep
     696        //get a picture to replace the applet
     697        jmolStatus.pictureStrs[n] = get_jmol_image(n, jmolStatus);
     698        //make sure the state is up-to-date
     699        jmolUpdateState(n);
     700        //Different browsers pass different versions of null and undefined.
     701        if(jmolStatus.pictureStrs[n]=="null"||jmolStatus.pictureStrs[n]==""||jmolStatus.pictureStrs[n]==undefined||jmolStatus.pictureStrs[n]==null||jmolStatus.pictureStrs[n]=="undefined"){//don't have a picture put up text instead
     702            get_element("Jmol"+n).innerHTML = 'Sleeping...<br/>Static plot unavailable. <br/>  Click Wake Up to get live plot.';
     703            }else{
     704            var imageID = 'Jmol_Image'+n;
     705            //The below does not work with Safari, doesn't show alternate text when no image data.
     706            var imageStr = '<image id='+imageID+' alt="If no plot appears here click Wake Up" src="data:image/jpeg;base64, ' + jmolStatus.pictureStrs[n] + '">';
     707            get_element("Jmol"+n).innerHTML = 'Sleeping...<button onClick="javascript:void(wakeJmol('+n+',jmolStatus))">Make Interactive</button><br/>'+imageStr;
     708           }
     709        jmolStatus.jmolArray[n]=1; //we've turned it off
     710        //make sure the controls that only work with live Jmol are hidden
     711        var cellID = 'Jmol_Table_Jmol'+n+'_cell_0_1';
     712        get_element(cellID).setAttribute("style","display: none;");
     713        var togname = '#Adv_but_Jmol'+n;
     714        $(togname).toggle();       
     715            jmolStatus.numLive = jmolStatus.numLive-1;
     716       }
     717    }
     718
     719function wakeJmol(n,jmolStatus) {
     720        if (jmolStatus.jmolArray[n] == -1) return; //this one has been deleted cannot wake.
     721        limitlive(n, jmolStatus);
     722        width = jmolStatus.widths[n];
     723        height = jmolStatus.heights[n];
     724        url = jmolStatus.urls[n];
     725        jmolSetDocument(false);
     726//      scriptStr = 'script "'+url+'"; isosurface fullylit; pmesh o* fullylit; set antialiasdisplay on;';
     727        re_linebreak = /<br>/gi;
     728//        scriptStr = get_element("jmolStateDiv"+n).innerHTML.replace(re_linebreak,'\n');
     729        var scriptStr = jmolStatus.stateScripts[n];
     730//to avoid a problem with testing of numbers in Jmol.js  quote the appletID #
     731        var nquote = n;
     732        get_element("Jmol"+ nquote).innerHTML = jmolApplet([width,height], scriptStr, nquote);
     733        if (jmolStatus.jmolArray[n]!=0){//it wasn't on, if it was we've just done a reset so don't need to update status
     734                jmolStatus.jmolArray[n]=0; //we've turned it on
     735                jmolStatus.numLive = jmolStatus.numLive+1;
     736        var togname = '#Adv_but_Jmol'+n;
     737        $(togname).toggle();       
     738                }
     739        }
     740
     741function limitlive(nWake, jmolStatus){
     742        //called before waking an old or initiating a new Jmol
     743        //nWake = index of the Jmol being initiated or wakened.
     744        //will attempt to shut down a Jmol as far away as possible.
     745        //needs to be more sophisticated about updating jmolStatus because
     746        //applets may have been removed without updating.
     747    j = 0;
     748    loading= false;
     749    while (j<jmolStatus.jmolArray.length){
     750        if(jmolStatus.jmolArray[j]==2){
     751            loading = true;           
     752            }
     753        j=j+1;
     754        }
     755    if (loading){ //if any are still loading we wait
     756        var launchStr = 'limitlive('+nWake+',jmolStatus)';
     757//        alert("Waiting for Jmol"+n+" div.");
     758        setTimeout(launchStr, 1000); }else{
     759            while (jmolStatus.numLive >= jmolStatus.maxLiveAllowed) {
     760                //search only from zero
     761                k=0;
     762                while (jmolStatus.jmolArray[k]!=0){
     763                        k = k +1;
     764                        }
     765                //search only from max
     766                i = jmolStatus.jmolArray.length-1;
     767                while (jmolStatus.jmolArray[i]!=0){
     768                                i = i -1;
     769                        }
     770                if (Math.abs(nWake-i) > Math.abs(nWake-k)){
     771                        nSleep = i;}else{
     772                        nSleep = k;}
     773                sleepJmol(nSleep, jmolStatus);
     774                }
     775        }
     776        }
     777
     778function jmol_delete_all_output() {
     779    //called by the delete_all_output function of the notebook to get jmol parameters cleaned up.
     780    jmol_count=0;
     781    jmolStatus.numLive=0;
     782    jmolStatus.jmolArray=new Array();
     783}
     784
     785function jmol_delete_check() {
     786    //called when cells are evaluated to see if any jmols have been deleted.  If so update their status.
     787    liveCount = jmolStatus.jmolArray.length;
     788    for ( k = 0; k< liveCount; k++) {
     789        testId= 'Jmol_Table_Jmol'+k; //looking for the whole table Jmol is in, since if the table is there it is sleeping.
     790        if (!get_element(testId)) { //we need to set this as deleted and maybe free up the ID?
     791            jmolStatus.jmolArray[k] = -1;
     792            //for the time being old IDs will not be reused.  Shouldn't be real big problem as completely resets
     793            //each time a page is opened.
     794        }
     795    }
     796    for ( i = 0; i < liveCount; i++){ //reset the number of live Jmols
     797        if (jmolStatus.jmolArray[i]!=0) {liveCount = liveCount-1;}
     798    }
     799    jmolStatus.numLive = liveCount;
    17800}
    18801
    19802function jmol_image(jmol_count) {
    20     var myImage = jmolGetPropertyAsString("image", "", jmol_count), s;
    21     mywindow = window.open("", "Jmol Image",
    22                            "menubar=no,width=600,height=600,toolbar=no");
    23     s = '<HTML><TITLE>Jmol Image</TITLE><BODY>';
    24     s += '<img src="data:image/jpeg;base64,' + myImage + '">';
    25     s += '<p>To save this image, you can try right-clicking on the image to copy it or save it to a file, or you may be able to just drag the image to your desktop.</p>';
    26     s += '</BODY></HTML>';
    27     mywindow.document.write(s);
     803  var myImage = jmolGetPropertyAsString("image","",jmol_count)
     804  mywindow = window.open("","Jmol Image","menubar=no,width=600,height=600,toolbar=no");
     805  s = '<HTML><TITLE>Jmol Image</TITLE><BODY>';
     806  s += '<img src="data:image/jpeg;base64,' + myImage + '">';
     807  s += '<p>To save this image, you can try right-clicking on the image to copy it or save it to a file, or you may be able to just drag the image to your desktop.</p>';
     808  s += '</BODY></HTML>';
     809  mywindow.document.write(s);
    28810}
    29811
    30 function jmol_popup(url) {
    31     var win = window.open("", "jmol viewer",
    32                           "width=600,height=600,resizable=1,statusbar=0");
     812
     813function get_jmol_image(n, jmolStatus){
     814    var pictureStr="";
     815    if(jmolStatus.jmolArray[n] == 0) {//it's live
     816        pictureStr = jmolGetPropertyAsString("image","",n);
     817        }
     818    return(pictureStr);
     819    }
     820
     821function jmol_popup(n) {
     822    win = window.open ("", "jmol viewer", "width=600,height=600,resizable=1,statusbar=0");
    33823    win.document.body.innerHTML = "";
    34824    win.document.title = "Sage 3d Viewer";
    35825    win.document.writeln("<h1 align=center>Sage 3d Viewer</h1>");
    36826    jmolSetDocument(win.document);
    37     jmolApplet("100%", "script" + url, jmol_count);
     827//    scriptStr = 'script "'+url+'"; isosurface fullylit; pmesh o* fullylit; set antialiasdisplay on;';
     828    re_linebreak = /<br>/gi;
     829    var scriptStr = get_element("jmolStateDiv"+n).innerHTML;
     830    scriptStr = scriptStr.replace(re_linebreak,'\n')
     831    scriptStr = jmolStatus.stateScripts[n];//comment out to use the script in jmolStateDiv.
     832    jmolApplet("100%", scriptStr, n);
    38833    win.focus();
    39834}
     835
     836function jmol_help(){
     837    win = window.open("/java/jmol/appletweb/JmolHelp.html","Jmol Help","width=400, height=600");
     838    win.focus();
     839}
     840
     841/* Tools adapted from the Jmol Widgets Libray
     842Jmol JAVASCRIPT WIDGET LIBRARY
     843
     844This is a compilation of Javascript widgets modified to follow the standard syntax from
     845Jmol.js and to work with Jmol.js.  These widgets have been taken from a number of places. 
     846Sources are acknowledged immediately before each block of code.  As you update please keep
     847the source of the code up-to-date as well.
     848
     849The widgets
     850USE OTHER FUNCTIONS IN THIS JAVASCRIPT LIBRARY AT YOUR OWN RISK AS THEIR FUNCTION AND
     851SYNTAX MAY CHANGE!!!
     852
     853------
     854JmolColorPickerBoxStr(scriptStr, rgb, boxIdStr,  appletId).
     855Returns a string that builds a colorpicker box.
     856All parameters are strings although appletId could potentially be a number, but it is used to make a string.
     857  scriptStr should contain $COLOR$ where you wish the color string to be passed to Jmol in the script you provide.
     858  rgb  (in this version expect hex color in Jmol format)
     859    is the browser standard 0-255 red-green-blue values specified as and array [red, green, blue] default = [127,127,127] a dark grey.
     860  boxIdStr should be a string that is unique to the web document, if not provided it will be set to colorBoxJ, J=0, 1, 2... in the order created.
     861  appletId is the standard Jmol id of applet you want the colorpicker to send the script to.  Default = "0".
     862------
     863
     864Updates & versions (most recent first please):
     865/* Jmol Simple JavaScript Color Picker
     866 by Jonathan Gutow, IE fixes thanks to Angel Herraez
     867V1.1
     868June 15, 2010
     869
     870requires
     871   Jmol.js
     872
     873Usage
     874Where ever you want a popup color picker box include a script like
     875
     876<script type="text/javascript">
     877var scriptStr2 = 'select carbon; color atom $COLOR$;';
     878JmolColorPickerBox("colorBox1", "rgb(100,100,100)", scriptStr2, "0");
     879</script>
     880
     881The only function that will not change name or syntax is JmolColorPickerBox(scriptStr, rgb, boxIdStr,  appletId).
     882
     883USE OTHER FUNCTIONS IN THE JAVASCRIPT LIBRARY AT YOUR OWN RISK.
     884All parameters are strings although appletId could potentially be a number, but it is used to make a string.
     885  scriptStr should contain $COLOR$ where you wish the color string to be passed to Jmol in the script you provide.
     886  rgb is the browser standard 0-255 red-green-blue values specified as an array [red, green, blue] default = [127,127,127] a dark grey.
     887  boxIdStr should be a string that is unique to the web document, if not provided it will be set to colorBoxJ, J=0, 1, 2... in the order created.
     888  appletId is the standard Jmol id of applet you want the colorpicker to send the script to.  Default = "0".
     889
     890
     891*/
     892
     893//globals and their defaults
     894
     895var JmolColorPickerStatus = {
     896    lastPicked: '', //last picked color...not used at present
     897    funcName: '', //where to pass to next after pickedColor()
     898    passThrough: '' //name of the global variable or structure containing information to be passed
     899    }
     900
     901var JmolColorPickerBoxes=new Array();//array of boxInfo
     902
     903function boxInfo(boxID, appletID, scriptStr){//used when using a predefined colorPickerBox
     904    this.boxID=boxID;
     905    this.appletID=appletID; //applet ID
     906    this.scriptStr=scriptStr; //script with $COLOR$ where the color should be placed.
     907    }
     908
     909function changeClass(someObj,someClassName) {
     910    someObj.setAttribute("class",someClassName);
     911    someObj.setAttribute("className",someClassName);  // this is for IE
     912}
     913
     914//Build the ColorPicker Div.
     915
     916// detect if browser supports data:URI   (IE6 & IE7 do not)
     917    var dataURIsupported = true;
     918    var testImg64 = new Image();
     919    testImg64.onload = testImg64.onerror = function() {
     920        if(this.width != 1 || this.height != 1) { dataURIsupported = false; }
     921    }
     922    testImg64.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
     923
     924function makeColorPicker(){
     925    JmolColorPickerDiv = get_element("JmolColorPickerDiv");
     926    if(! JmolColorPickerDiv){
     927        var colorPickerCSS = document.createElement('style');
     928        colorPickerCSS.type = 'text/css';
     929        CSSStr ='.JmolColorPicker_vis {border-style:solid;border-width:thin;clear:both;display:block;overflow:visible;position:absolute;margin-left:-52px;width:104px;z-index:2;}';
     930        CSSStr +='.JmolColorPicker_hid {height:0;min-height:0;display:none;overflow:hidden;z-index:0;}';
     931        if (colorPickerCSS.styleSheet) { // IE
     932            colorPickerCSS.styleSheet.cssText = CSSStr;
     933        } else { // W3C
     934            content = document.createTextNode(CSSStr);
     935            colorPickerCSS.appendChild(content);
     936        }
     937        document.getElementsByTagName('head')[0].appendChild(colorPickerCSS);
     938        JmolColorPickerDiv = document.createElement("div");
     939        JmolColorPickerDiv.setAttribute("id", "JmolColorPickerDiv");
     940        changeClass(JmolColorPickerDiv,"JmolColorPicker_hid");
     941        }
     942   var rgbs=[[255,0,0]
     943       ,[255,128,0]
     944       ,[255,255,0]
     945       ,[128,255,0]
     946       ,[0,255,0]
     947       ,[0,255,128]
     948       ,[0,255,255]
     949       ,[0,128,255]
     950       ,[0,0,255]
     951       ,[128,0,255]
     952       ,[255,0,255]
     953       ,[255,0,128]
     954       ,[255,255,255]
     955   ];
     956   var hues=[[190,100],
     957             [175,95],
     958             [150,90],
     959             [135,80],
     960             [100,68],
     961             [85,55],
     962             [70,40],
     963             [60,30],
     964             [50,20],
     965             [35,0]
     966     ];
     967    var tempwidth = 8*(rgbs.length);
     968    var htmlStr = '<div id="JmolColorPickerHover" style="font-size:2px;width:'+tempwidth+'px;text-align:right;background-color:white;cursor:default;">';
     969    if (dataURIsupported) {
     970        htmlStr += '<image id="JmolColorPickerCancel" onclick="pickedColor(\'cancel\');" src="data:image/bmp;base64,Qk3CAQAAAAAAADYAAAAoAAAACwAAAAsAAAABABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdnZ2j4+PoKCgqampqampoKCgj4+PAAAAAAAAAAAAAAAAAAAAAAAAsbGxwsLCysrKysrKwsLCAAAAAAAAAAAAAAAAZWVlAAAAAAAAAAAA29vb5OTk5OTkAAAAAAAAAAAAj4+PAAAAdnZ2oKCgAAAAAAAAAAAA9PT0AAAAAAAAAAAAwsLCoKCgAAAAfn5+qampysrKAAAAAAAAAAAAAAAAAAAA5OTkysrKqampAAAAfn5+qampysrK5OTkAAAAAAAAAAAA9PT05OTkysrKqampAAAAdnZ2oKCgwsLCAAAAAAAAAAAAAAAAAAAA29vbwsLCoKCgAAAAZWVlj4+PAAAAAAAAAAAA5OTkAAAAAAAAAAAAsbGxj4+PAAAATExMAAAAAAAAAAAAwsLCysrKysrKAAAAAAAAAAAAdnZ2AAAAAAAAAAAAAAAAj4+PoKCgqampqampoKCgAAAAAAAAAAAAAAAAAAAAAAAATExMZWVldnZ2fn5+fn5+dnZ2ZWVlAAAAAAAAAAAA">';
     971    } else {
     972        htmlStr += '<span id="JmolColorPickerCancel" onclick="pickedColor(\'cancel\');" style="font-size:10px; padding:0 2px; background-color:#A0A0A0; font-family:Verdana, Arial, Helvetica, sans-serif;">X</span>';
     973    }
     974    htmlStr += '</div>';         
     975    htmlStr += '<table cellspacing="0" cellpadding="0" border="0" style="font-size:2px; cursor:default;"><tbody>';
     976    for (j = 0; j < hues.length;j++){
     977    htmlStr += '<tr>'
     978    var f = (hues[j][0])/100.0;
     979       for (k = 0; k < rgbs.length; k++){
     980       if(rgbs[k][0]==255&&rgbs[k][1]==255&&rgbs[k][2]==255) f =(hues[j][1])/100.0;;
     981       r = Math.min(Math.max(Math.round(rgbs[k][0] * f),Math.round(255-rgbs[k][0])*(f-1)^2),255);
     982       g = Math.min(Math.max(Math.round(rgbs[k][1] * f),Math.round(255-rgbs[k][1])*(f-1)^2),255);
     983       b = Math.min(Math.max(Math.round(rgbs[k][2] * f),Math.round(255-rgbs[k][2])*(f-1)^2),255);
     984          htmlStr +='<td style="background-color: rgb(' + r + "," + g + ","+ b + ');">';
     985          htmlStr +='<div style="width: 8px; height: 8px;" onclick=\'pickedColor("rgb('+r+','+g+','+b+')");\' ';
     986          htmlStr +='onmouseover=\'hoverColor("rgb('+r+','+g+','+b+')");\'></div>';
     987          htmlStr +='</td>';
     988       }//for k
     989   htmlStr +='</tr>';
     990   }//for j
     991   htmlStr += '</tbody></table>';
     992    content = document.createTextNode("loading color picker...");
     993    JmolColorPickerDiv.appendChild(content);
     994    JmolColorPickerDiv.innerHTML = htmlStr;
     995    return(JmolColorPickerDiv);   
     996}
     997
     998// IE6 puts the SELECT control on top of the popup colorpicker DIV, so we trick that:
     999var IEversion = 999;
     1000if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) { //test for MSIE x.x;
     1001    IEversion=new Number(RegExp.$1); // capture x.x portion and store as a number
     1002}
     1003
     1004function pickedColor(colorStr){
     1005    var pickerDiv = get_element("JmolColorPickerDiv");
     1006//    var debug = get_element("JmolDebug");
     1007//    var tempStr = debug.innerHTML;
     1008//    tempStr+='<br/>The parent of the picker div is on reaching pickedColor is: '+pickerDiv.parentNode.id;
     1009    if(colorStr!='cancel'){
     1010        var boxNum = JmolColorPickerStatus.passThrough;
     1011        get_element(JmolColorPickerBoxes[boxNum].boxID).style.background = colorStr;
     1012        var rgbCodes = colorStr.replace(/rgb/i,'').replace('(','[').replace(')',']');
     1013        var scriptStr = JmolColorPickerBoxes[boxNum].scriptStr.replace('$COLOR$', rgbCodes);
     1014        jmolScript(scriptStr,JmolColorPickerBoxes[boxNum].appletID);
     1015        storeDefaultDir(JmolColorPickerBoxes[boxNum].appletID);
     1016        jmolUpdateState(JmolColorPickerBoxes[boxNum].appletID);
     1017    }
     1018//    tempStr += '<br/>The picked color is: '+colorStr+'.<br/>'+pickerDiv.id; 
     1019    pickerDiv.setAttribute("class","JmolColorPicker_hid");
     1020//    tempStr += ' has class: '+pickerDiv.getAttribute("class")+' after call to pickedColor.'
     1021//    debug.innerHTML = tempStr;
     1022}
     1023function hoverColor(colorStr){
     1024    get_element("JmolColorPickerHover").style.background = colorStr;
     1025}
     1026
     1027function popUpPicker(whereID, funcName, passThrough){
     1028    var pickerDiv = get_element("JmolColorPickerDiv");
     1029    if (!pickerDiv) {//make a new picker
     1030        pickerDiv =  makeColorPicker();
     1031        }
     1032    JmolColorPickerStatus.funcName = funcName;
     1033    JmolColorPickerStatus.passThrough = passThrough;
     1034    var where = get_element(whereID);
     1035    where.appendChild(pickerDiv);
     1036    changeClass(pickerDiv,"JmolColorPicker_vis");
     1037}
     1038
     1039
     1040function JmolColorPickerBoxStr(scriptStr, startColor, boxID, appletID){
     1041    if (!appletID) appletID = "0";
     1042    var boxNum = JmolColorPickerBoxes.length;
     1043    if (!boxID) boxID = 'colorBox'+boxNum;
     1044    if (!startColor) startColor = '[x999999]';
     1045    var presentColor = startColor.replace('\[x','#').replace('\]','');
     1046    var colorBoxId = ''+boxID+'_color';
     1047    JmolColorPickerBoxes[boxNum]= new boxInfo(colorBoxId, appletID, scriptStr);   
     1048    var htmlStr = '<div id='+boxID+'><table style="font-size:0px; cursor:default;" cellspacing="0" cellpadding="0" border="1" onclick=\'popUpPicker(';
     1049    htmlStr += '"'+boxID+'","colorBoxUpdate",'+boxNum+');\' ';
     1050    htmlStr += '><tbody>';
     1051    htmlStr += '<tr><td><div id ="'+colorBoxId+'" style="height: 12px; width: 12px;background-color:'+presentColor+';"></div></td><td>';
     1052    var boxArrowName = 'colorBoxArrow'+boxNum;
     1053    if (dataURIsupported) {
     1054        // up arrowhead:   "data:image/bmp;base64,Qk3mAQAAAAAAADYAAAAoAAAACwAAAAwAAAABABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIAAAAAAAAAAAAAAAAAAAAAAAAAAAAyMjIyMjIAAAAyMjIyMjIyMjIAAAAAAAAAAAAAAAAAAAAyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIAAAAAAAAAAAAyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAA"
     1055        // down arrowhead: "data:image/bmp;base64,Qk3mAQAAAAAAADYAAAAoAAAACwAAAAwAAAABABgAAAAAALABAAAAAAAAAAAAAAAAAAAAAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIAAAAAAAAAAAAyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIAAAAAAAAAAAAAAAAAAAAyMjIyMjIyMjIAAAAyMjIyMjIAAAAAAAAAAAAAAAAAAAAAAAAAAAAyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAA"
     1056        htmlStr += '<image id="'+ boxArrowName+'" src="data:image/bmp;base64,Qk3mAQAAAAAAADYAAAAoAAAACwAAAAwAAAABABgAAAAAALABAAAAAAAAAAAAAAAAAAAAAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIAAAAAAAAAAAAyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIAAAAAAAAAAAAAAAAAAAAyMjIyMjIyMjIAAAAyMjIyMjIAAAAAAAAAAAAAAAAAAAAAAAAAAAAyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAAyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIAAAA">';
     1057    } else {
     1058        htmlStr += '<span id="'+ boxArrowName+'" style="font-size:10px; padding:0 2px; background-color:#A0A0A0; font-family:Verdana, Arial, Helvetica, sans-serif;">V</span>';
     1059    }
     1060    htmlStr += '</td></tr></tbody></table></div>';
     1061    return(htmlStr);
     1062}
     1063
     1064
     1065function colorBoxUpdate(pickedColor, boxNum){
     1066    get_element(JmolColorPickerBoxes[boxNum].boxID).style.background = pickedColor;
     1067    var pickerDiv = get_element("JmolColorPickerDiv");
     1068    changeClass(pickerDiv, "JmolColorPicker_hid");
     1069    var rgbCodes = pickedColor.replace(/rgb/i,'').replace('(','[').replace(')',']');
     1070    var scriptStr = JmolColorPickerBoxes[boxNum].scriptStr.replace('$COLOR$', rgbCodes);
     1071    jmolScript(scriptStr,JmolColorPickerBoxes[boxNum].appletID);
     1072    storeDefaultDir(JmolColorPickerBoxes[boxNum].appletID);
     1073    jmolUpdateState(JmolColorPickerBoxes[boxNum].appletID);
     1074}
     1075
     1076/* End of Jmol Simple JavaScript Color Picker
     1077*/
  • sagenb/data/sage/js/notebook_lib.js

    diff -r b0a0157ab2ad -r 1f6311a9060b sagenb/data/sage/js/notebook_lib.js
    a b  
    23492349
    23502350    // Set the cell to not evaluated.
    23512351    cell_set_not_evaluated(id);
     2352
     2353    // Check if the cell contained a Jmol
     2354    jmol_delete_check();
    23522355}
    23532356
    23542357
     
    30423045    // a running cell.
    30433046    cell_set_running(id);
    30443047
     3048    // Check if a Jmol has been deleted
     3049    jmol_delete_check();
     3050
    30453051    // Finally make the request back to the server to do the actual calculation.
    30463052    cell_input = get_cell(id);
    30473053    if (newcell) {
     
    45344540        // produced that output.
    45354541        cell_set_not_evaluated(id);
    45364542    }
     4543    // Update the jmol handler so that it knows there are no Jmols left
     4544    jmol_delete_all_output();
     4545
    45374546    // Finally tell the server to do the actual delete.  We first
    45384547    // delete from DOM then contact the server for maximum snappiness
    45394548    // of the user interface.