[sagenb] 90/157: Enable JSmol

felix salfelder felix-guest at moszumanska.debian.org
Mon Dec 22 16:51:55 UTC 2014


This is an automated email from the git hooks/post-receive script.

felix-guest pushed a commit to branch master
in repository sagenb.

commit c1d9aa3dc88bcb75547993607127c89fd03f0a19
Author: Volker Braun <vbraun.name at gmail.com>
Date:   Sat Oct 4 22:05:50 2014 +0100

    Enable JSmol
---
 sagenb/data/sage/html/notebook/base.html |  12 +--
 sagenb/data/sage/js/jmol_lib.js          | 108 ++++++++++++---------------
 sagenb/flask_version/worksheet.py        |  73 ++++++++++++++++++-
 sagenb/notebook/cell.py                  | 121 +++++++++++++++++++------------
 4 files changed, 195 insertions(+), 119 deletions(-)

diff --git a/sagenb/data/sage/html/notebook/base.html b/sagenb/data/sage/html/notebook/base.html
index 0acff77..2da83d3 100644
--- a/sagenb/data/sage/html/notebook/base.html
+++ b/sagenb/data/sage/html/notebook/base.html
@@ -32,6 +32,10 @@ INPUT:
 <script type="text/javascript" src="/javascript/jquery/plugins/colorpicker/js/colorpicker.min.js"></script>
 <script type="text/javascript" src="/javascript/jquery/plugins/achtung/ui.achtung-mod.min.js"></script>
 
+<!-- Jmol - embedded 3D graphics **needs to be before jmol_lib.js** -->
+<script type="text/javascript" src="/jsmol/JSmol.min.nojq.js"></script>
+<!-- <script type="text/javascript" src="/jsmol/js/Jmol2.js"></script> -->
+
 {% if not worksheet.is_published() or worksheet.notebook().conf()['pub_interact'] %}
 <script type="text/javascript" src="/javascript/sage/js/notebook_lib.js"></script>
 <script type="text/javascript" src="/javascript/dynamic/notebook_dynamic.js"></script>
@@ -43,14 +47,6 @@ INPUT:
 <script type="text/javascript" src="/javascript/mathjax/MathJax.js?config=TeX-AMS_HTML-full,../../dynamic/mathjax_sage.js"></script>
 {% endif %}
 
-<!-- Jmol - embedded 3D graphics **needs to be before jquery plugin loads, maybe?**-->
-<script type="text/javascript" src="/jsmol/JSmol.min.nojq.js"></script>
-<script type="text/javascript" src="/jsmol/js/Jmol2.js"></script>
-<!-- This must stay in head -->
-<script>//jmolInitialize("/java/jmol");
-//jmolSetCallback("menuFile","/java/jmol/appletweb/SageMenu.mnu");
-</script>
-
 <!-- Sage3d - accelerated 3D graphics -->
 <script type="text/javascript" src="/javascript/sage3d/sage3d.js"></script>
 
diff --git a/sagenb/data/sage/js/jmol_lib.js b/sagenb/data/sage/js/jmol_lib.js
index 6da4a66..bd87c7b 100644
--- a/sagenb/data/sage/js/jmol_lib.js
+++ b/sagenb/data/sage/js/jmol_lib.js
@@ -4,33 +4,33 @@
   Jonathan Gutow <gutow at uwosh.edu> February 2014 
 */
 
-var jmolApplet; //our generic viewer.
-
-var live_3D_state = false;
+// Turn off the JSmolCore.js: synchronous binary file transfer is
+// requested but not available" warning
+Jmol._alertNoBinary = false
 
 jmol_isReady = function(jmolApplet) {
-  Jmol.script(jmolApplet,"set platformSpeed 6;");
-  //alert("Applet: "+jmolApplet+" has launched.");
-	//TODO will need to activate widgets
- }
+    console.log('Jmol is ready');
+    Jmol.script(jmolApplet, "set platformSpeed 6;");
+    //alert("Applet: "+jmolApplet+" has launched.");
+}
 
 var jmolInfo = { //default values
     width: "100%",
     height: "100%",
+    // debug=true will pop up alert boxes
     debug: false,
     color: "white",
     addSelectionOptions: false,
-    serverURL: "http://chemapps.stolaf.edu/jmol/jsmol/php/jsmol.php", //you can change this to your own server.
-    use: "HTML5",
-    coverImage: "/jsmol/j2s/img/play_make_live.jpg", // initial image instead of applet
-    coverScript: "",	// special script for click of cover image (otherwise equal to script)
+    use: "HTML5 WebGL Java",
+    // Tooltip when the mouse is over the static image
+    coverTitle: 'Click on 3-D image to make it live.  Right-click on live image for a control menu.',
     deferApplet: true,                  // wait to load applet until click
     deferUncover: true,                 // wait to uncover applet until script completed
     //The paths below assume your server is set up with standard JSmol directory.  If not
     //they will need modification for the page to work.
     jarPath: "/jsmol/java", //path to applet .jar files on server.
     j2sPath: "/jsmol/j2s",//path to javascript version.
-    makeLiveImg:"/jsmol/j2s/img/play_make_live.jpg",//path to activate 3-D image.
+    makeLiveImg:"/jsmol/j2s/img/play_make_live.jpg",  //path to activate 3-D image.
     jarFile: "JmolAppletSigned0.jar",
     isSigned: true,
     //disableJ2SLoadMonitor: true,
@@ -40,12 +40,12 @@ var jmolInfo = { //default values
     z: 5,
     zIndexBase: 5,
     menuFile: "/jsmol/appletweb/SageMenu.mnu", //special sagemenu
-    //platformSpeed: 6
+    platformSpeed: 6,
 }
 
 var jmol_count = 0;
 
-var jmolStatus = {//most of these not used in the lightweight version, kept to make widgets easy to add back.
+jmolStatus = {//most of these not used in the lightweight version, kept to make widgets easy to add back.
     maxLiveAllowed: 4,
     numLive: 0,
     loadSigned: false, //when set to true will load signed applets.
@@ -61,75 +61,61 @@ var jmolStatus = {//most of these not used in the lightweight version, kept to m
     stateScripts: new Array(),
     cntrls: new Array(),
     attempts: new Array(),
-    jmolInfo: new Array(),
-    }
+    jmolInfo: new Object(),
+}
 
 //Some default constants
 //applet sizes
 var miniature = 100;
 var small = 250;
-var medium = 400;
-var large = 600;
+var medium = 500;
+var large = 800;
 
 //Check whether to load 3-D live
 //live_3D_state = $('#3D_check').prop('checked');
 //start the watch function
 jmolWatcher = setInterval('jmolActivator();',500);
 
-function jmol_applet(size, image, url, cell_num, functionnames) { //makes a new applet. 
+// makes a new applet and puts it into the dom
+function make_jmol_applet(size, image, script, server_url, cell_num, functionnames) {
     var appletID = jmol_count;
     jmol_count = jmol_count + 1;
     jmolStatus.jmolArray[appletID] = 3; //queued to load.
-    if (size==500){
-        size = medium; //set to medium size otherwise we will keep other sizes.
-        }
-    Jmol.setDocument(document);
-    //Where am I?  Need to know in cases where I need to write directly to this cell.
-    cell_ID = 'sage_jmol'+cell_num;
-    jmolStatus.jmolInfo[appletID] = jQuery.extend({}, jmolInfo);; // shallow copy default values
+    if (size == 500)
+        size = medium; // set to medium size otherwise we will keep other sizes.
+    Jmol.setDocument(false); // manually insert Jmol.getAppletHtml later
+    jmolStatus.jmolInfo[appletID] = jQuery.extend({}, jmolInfo); // shallow copy default values
     jmolStatus.jmolInfo[appletID].coverImage = image; //this should be the image url
-    jmolStatus.jmolInfo[appletID].script = "script "+url; //this should be the script url
-    //Check whether to load 3-D live
-    live_3D_state = $('#3D_check').prop('checked');    
-    if (live_3D_state){
-       jmolStatus.jmolInfo[appletID].deferApplet=false;
-       }else{
-       jmolStatus.jmolInfo[appletID].deferApplet=true;
-       }
+    jmolStatus.jmolInfo[appletID].script = "script "+script; //this should be the script name
+    jmolStatus.jmolInfo[appletID].serverURL = server_url;
+    // jmolStatus.jmolInfo[appletID].deferApplet = jQuery('#3D_check').prop('checked');
     jmolDivStr = "jmol"+appletID;
     jmolStatus.widths[appletID] = size;
     jmolStatus.heights[appletID]= size;
-    //appending to cell_ID
-    $('#'+cell_ID).append('<span>Click on 3-D image to make it live.  Right-click on live image for a control menu.</span>');
+    // appending to cell_ID
+    var cell_ID = 'sage_jmol_' + cell_num;
+    // $('#'+cell_ID).append('<span></span>');
     $('#'+cell_ID).append('<div id="'+jmolDivStr+'" style="height:'+size+'px; width:'+size+'px;" >JSmol here</div>');
-    //launching JSmol/Jmol applet
-    $('#'+jmolDivStr).html(Jmol.getAppletHtml("jmolApplet"+appletID,jmolStatus.jmolInfo[appletID])); 
-    //we will still set all the data for this applet so that other asynchronously created applets do not grab its ID.
-    jmolStatus.signed[appletID]=jmolStatus.loadSigned;
-    jmolStatus.urls[appletID]=url;
-    //    jmolStatus.numLive = jmolStatus.numLive+1;
-    //jmolStatus.controlStrs[appletID] = controlStr;
-    //jmolStatus.captionStrs[appletID] = captionStr;
-    //jmolStatus.cntrls[appletID]=cntrlPanels;
-//Now we wait for the server by calling a function that waits if the div is not yet written.
-//    launchNewJmol(size,scriptStr,appletID);
-//    Jmol.script("jmolApplet"+appletID,"set platformspeed 6;");
+    // launching JSmol/Jmol applet
+    var applet_html = Jmol.getAppletHtml("jmolApplet"+appletID, jmolStatus.jmolInfo[appletID]);
+    $('#'+jmolDivStr).html(applet_html);
+    // we will still set all the data for this applet so that other asynchronously created applets do not grab its ID.
+    jmolStatus.signed[appletID] = jmolStatus.loadSigned;
     return jmolDivStr;//for historical compatibility
-    }
+}
 
 function jmolActivator(){
     if (document.getElementById("loadJmol")){
-        parentdiv = $("#loadJmol").parent();
-        //parentid = $(parentdiv).attr("id");
-        //alert("The parent id is:"+parentid);
-        cell_num = $(parentdiv).children("#loadJmol").html();//this div must have the ID number
-        //alert("Trying to launch JSmol #"+cell_num);
-        $(parentdiv).children("#loadJmol").remove();
-        size = $(parentdiv).children("#sage_jmol_size"+cell_num).html();
-        img = $(parentdiv).children("#sage_jmol_img"+cell_num).html();
-        script = $(parentdiv).children("#sage_jmol_script"+cell_num).html();
-        tmpdiv = jmol_applet(size, img, script, cell_num);
-        $(parentdiv).children("#sage_jmol_status"+cell_num).html("Activated");
+        var parentdiv = jQuery("#loadJmol").parent();
+        // This div contains the ID number
+        var cell_num = parentdiv.children("#loadJmol").html();
+        parentdiv.children("#loadJmol").remove();
+        var size = parentdiv.children("#sage_jmol_size_"+cell_num).html();
+        var img = parentdiv.children("#sage_jmol_img_"+cell_num).html();
+        var script = parentdiv.children("#sage_jmol_script_"+cell_num).html();
+        var server_url = parentdiv.children("#sage_jmol_server_url_"+cell_num).html();
+        make_jmol_applet(size, img, script, server_url, cell_num);
+        parentdiv.children("#sage_jmol_status_"+cell_num).html("Activated");
     }
 }
 
@@ -139,7 +125,7 @@ function live_3D_check(s) {
     INPUT:
         s -- boolean; whether the live 3D box is checked.
     */
-    live_3D_state =s;
+    var live_3D_state = s;
     //alert ('live_3D_state:'+live_3D_state);
     async_request(worksheet_command('live_3D/' + s));
 }
diff --git a/sagenb/flask_version/worksheet.py b/sagenb/flask_version/worksheet.py
index bfe60bc..a6393a6 100644
--- a/sagenb/flask_version/worksheet.py
+++ b/sagenb/flask_version/worksheet.py
@@ -1,8 +1,9 @@
 import os, threading, collections
 from functools import wraps
-from flask import Module, url_for, render_template, request, session, redirect, g, current_app
+from flask import Module, make_response, url_for, render_template, request, session, redirect, g, current_app
 from decorators import login_required, with_lock
 from collections import defaultdict
+from werkzeug.utils import secure_filename
 from flask.ext.babel import Babel, gettext, ngettext, lazy_gettext
 _ = gettext
 
@@ -649,6 +650,74 @@ def worksheet_cells(worksheet, filename):
     from flask.helpers import send_from_directory
     return send_from_directory(worksheet.cells_directory(), filename)
 
+
+########################################################
+# Jmol/JSmol callback to read data files
+########################################################
+ at worksheet_command('jsmol/<celldir>')
+def worksheet_jsmol_data(worksheet, celldir):
+    """
+    Jmol/JSmol callback
+
+    The jmol applet does not take the data inline, but calls back at
+    this URI to get one or more base64-encoded data files.
+    """
+    # Defaults taken from upstream jsmol.php
+    query = request.values.get('query', "http://cactus.nci.nih.gov/chemical/structure/ethanol/file?format=sdf&get3d=True")
+    call = request.values.get('call', u'getRawDataFromDatabase')
+    database = request.values.get('database', '_')
+    encoding = request.values.get('encoding', None)
+
+    # Bugs: It seems that JSmol isn't designed for our use case
+    if query.endswith('.jmol'):
+        # jmol asks for the script.jmol to be base64-encoded but then
+        # doesn't understand the reply
+        encoding = None
+    if query.endswith('.jmol.zip'):
+        # jmol asks for the script.jmol.zip to be base64-encoded but
+        # then doesn't understand the reply, and doesn't understand
+        encoding = u'unzip_SCRIPT'
+
+    if encoding == None:
+        def encoder(x): 
+            return x
+    elif encoding == u'base64':
+        import base64
+        def encoder(x): 
+            return base64.encodestring(x)
+    elif encoding == u'unzip_SCRIPT':   # unofficial
+        import StringIO
+        import zipfile
+        def encoder(x):
+            s = StringIO.StringIO(x)
+            return zipfile.ZipFile(s, 'r').read('SCRIPT')
+    else:
+        return current_app.message(_('Invalid JSmol encoding: ' + str(encoding)))
+
+    if call == u'getRawDataFromDatabase':
+        # Annoyingly, JMol prepends the worksheet url (not: the
+        # request url) to the query. Strip off:
+        pos = query.rfind('/')
+        if pos >= 0:
+            query = query[pos+1:]
+        query = secure_filename(query)   # never trust input
+        filename = os.path.join(worksheet.cells_directory(), celldir, query)
+        with open(filename, 'r') as f:
+            data = f.read()
+            response = make_response(encoder(data))
+    else:
+        return current_app.message(_('Invalid JSmol request: ' + str(call)))
+
+    # Taken from upstream jsmol.php
+    is_binary = '.gz' in query
+    # Non-standard Content-Type taken from upstream jsmol.php
+    if is_binary:
+        response.headers['Content-Type'] = 'Content-Type: text/plain; charset=x-user-defined';
+    else:
+        response.headers['Content-Type'] = 'Content-Type: application/json';
+    return response
+
+
 ##############################################
 # Data
 ##############################################
@@ -719,8 +788,6 @@ def worksheet_upload_data(worksheet):
 
 @worksheet_command('do_upload_data')
 def worksheet_do_upload_data(worksheet):
-    from werkzeug.utils import secure_filename
-
     worksheet_url = url_for_worksheet(worksheet)
     upload_url = worksheet_upload_data.url_for(worksheet)
 
diff --git a/sagenb/notebook/cell.py b/sagenb/notebook/cell.py
index 5acd1e7..28934fa 100755
--- a/sagenb/notebook/cell.py
+++ b/sagenb/notebook/cell.py
@@ -16,6 +16,8 @@ a list of cells.
 import os
 import re
 import shutil
+import textwrap
+import time
 from cgi import escape
 
 from sagenb.misc.misc import (word_wrap, strip_string_literals,
@@ -2232,6 +2234,25 @@ class Cell(Cell_generic):
                 self.worksheet_filename(), self.id())
             return self._url_to_self
 
+    def url_to_worksheet(self):
+        """
+        Returns a URL for the worksheet
+
+        OUTPUT:
+
+        - a string
+
+        EXAMPLES::
+
+            sage: nb = sagenb.notebook.notebook.Notebook(tmp_dir(ext='.sagenb'))
+            sage: nb.user_manager().add_user('sage','sage','sage at sagemath.org',force=True)
+            sage: W = nb.create_new_worksheet('Test', 'sage')
+            sage: C = sagenb.notebook.cell.Cell(0, '2+3', '5', W)
+            sage: C.url_to_worksheet()
+            '/home/sage/0'
+        """
+        return '/home/{0}'.format(self.worksheet_filename())
+
     def files(self):
         """
         Returns a list of all the files in this compute cell's
@@ -2293,6 +2314,55 @@ class Cell(Cell_generic):
         if os.path.exists(dir):
             shutil.rmtree(dir, ignore_errors=True)
 
+    def _jmol_files_html(self, F):
+        """
+        Helper for jmol files in :meth:`files_html`
+        """
+        # If F ends in -size500.jmol then we make the viewer applet
+        # with size 500.
+        i = F.rfind('-size')
+        if i != -1:
+            size = F[i + 5:-5]
+        else:
+            size = 500
+
+        # The ".jmol" script has defaultdirectory pointing
+        # to a zip file [see Graphics3d.show()]. But it is 
+        # relative to the worksheet URL as seen in the browser.
+        # But that doesn't make sense for live help.
+        #
+        # So we need to prepend the worksheet URL, in order
+        # for the zip to be accessed correctly.
+        if self.worksheet().docbrowser():
+            jmol_name = os.path.join(self.directory(), F)
+            with open(jmol_name, 'r') as f:
+                jmol_script = f.read()
+            jmol_script = jmol_script.replace(
+                'defaultdirectory "', 
+                'defaultdirectory "{0}'.format(self.url_to_worksheet()))
+            with open(jmol_name, 'w') as f:
+                f.write(jmol_script)
+
+        image_name = os.path.join(self.url_to_self(),'.jmol_images',F)
+        return textwrap.dedent("""
+        <div id="sage_jmol_{id}" class="3DPlotDiv">
+            <div id="loadJmol" style="display:none;">{id}</div>
+            <div id="sage_jmol_size_{id}" style="display:none;">{size}</div>
+            <div id="sage_jmol_img_{id}" style="display:none;">{image_name}.png?{timestamp}</div>
+            <div id="sage_jmol_script_{id}" style="display:none;">{filename}</div>
+            <div id="sage_jmol_server_url_{id}" style="display:none;">{callback}</div>
+            <div id="sage_jmol_status_{id}" style="display:none;">notActivated</div>
+        </div>
+        """).format(
+            id=self._id,
+            size=size,
+            image_name=image_name,
+            timestamp=time.time(),
+            filename=F,
+            url=os.path.join(self.url_to_self(), F),
+            callback=os.path.join(self.url_to_worksheet(), 'jsmol', str(self._id)),
+        )
+
     def files_html(self, out):
         """
         Returns HTML to display the files in this compute cell's
@@ -2324,7 +2394,6 @@ class Cell(Cell_generic):
             sage: W.quit()
             sage: nb.delete()
         """
-        import time
         D = self.files()
         D.sort()
         if len(D) == 0:
@@ -2355,57 +2424,12 @@ class Cell(Cell_generic):
             elif F.endswith('.svg'):
                 images.append('<embed src="%s" type="image/svg+xml" name="emap">' % url)
             elif F.endswith('.jmol'):
-                # If F ends in -size500.jmol then we make the viewer
-                # applet with size 500.
-                i = F.rfind('-size')
-                if i != -1:
-                    size = F[i + 5:-5]
-                else:
-                    size = 500
-
-                if self.worksheet().docbrowser():
-                    jmol_name = os.path.join(self.directory(), F)
-                    jmol_file = open(jmol_name, 'r')
-                    jmol_script = jmol_file.read()
-                    jmol_file.close()
-                    
-                    # The ".jmol" script has defaultdirectory pointing
-                    # to a zip file [see Graphics3d.show()]. But it is 
-                    # relative to the worksheet URL as seen in the browser.
-                    # But that doesn't make sense for live help.
-                    #
-                    # So we need to prepend the worksheet URL, in order
-                    # for the zip to be accessed correctly.
-                    #
-                    # There is no Worksheet.url_to_self(), so calculate it
-                    # in similar manner to Cell.url_to_self()
-                    url_to_ws = '/home/%s/' % self.worksheet_filename()
-                    jmol_script = jmol_script.replace('defaultdirectory "', 
-                                                      'defaultdirectory "' + url_to_ws )
-
-                    jmol_file = open(jmol_name, 'w')
-                    jmol_file.write(jmol_script)
-                    jmol_file.close()
-
-                image_name = os.path.join(self.url_to_self(),'.jmol_images',F)
-                #script = '<div id = "jmol_static%s"><script>jmol_applet(%s, "%s.png?%d", "%s?%d",%s);</script></div>' % (self._id,size, image_name, time.time(), url, time.time(), self._id)
-                script = '\n<div id="sage_jmol%s" class="3DPlotDiv">'%(self._id)
-                script += '\n  <div id = "loadJmol" style="display:none;">%s</div>'%(self._id)
-                script += '\n  <div id="sage_jmol_size%s" class="JmolSize" style="display:none;">%s</div>'%(self._id,size)
-                script += '\n  <div id="sage_jmol_img%s" class="JmolImg" style="display:none;">%s.png?%d </div>'%(self._id, image_name, time.time())
-                script += '\n  <div id="sage_jmol_script%s" class="JmolScript" style="display:none;">%s?%d</div>'%(self._id, url, time.time())
-                script += '\n  <div id="sage_jmol_status%s" class="JmolStatus" style="display:none;">notActivated</div>'%(self._id)
-                script += '\n</div>'
-                #script = '<div id = "jmol_static%s">Sleeping...<button onClick="javascript:void(jmol_launch(%s, \'%s?%d\', %s))">Make Interactive</button>'  % (self._id, size, url, time.time(), self._id)
-                #script += '<br><img src="%s.png?%d" alt="If no image appears re-execute the cell. 3-D viewer has been updated."></div>' % (image_name, time.time())
-                images.append(script)
+                images.append(self._jmol_files_html(F))
                 jmolimagebase = F
                 hasjmol=True
             elif F.endswith('.jmol.zip'):
                 # jmol data
                 jmoldatafile=os.path.join(self.directory(),F)
-                #link ='<div class="jmol_data"><a href="%s?%d">Download 3-D as Jmol file/data</a></div>'% (jmoldatafile, time.time())
-                #images.append(link)
             elif F.endswith('.canvas3d'):
                 script = '<div><script>canvas3d.viewer("%s");</script></div>' % url
                 images.append(script)
@@ -2418,6 +2442,9 @@ class Cell(Cell_generic):
                     link_text = link_text[:10] + '...' + link_text[-20:]
                 files.append('<a target="_new" href="%s" class="file_link">%s</a>' % (url, link_text))
 
+        # TODO: remove this fugly in-place upgrading of worksheets
+        # and all the associated variables. If the worksheet is old
+        # just require a reevaluation.
         if(hasjmol and not hasjmolimages):
             # This is probably an old worksheet. Generate the missing jmol static image(s)
             # Note: this is problematic in the notebook as it uses tools from Sage to

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/sagenb.git



More information about the debian-science-commits mailing list