[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