/* Jmol 11.7 script library Jmol.js 12:17 AM 4/20/2009 Bob Hanson checkbox heirarchy -- see http://chemapps.stolaf.edu/jmol/docs/examples-11/check.htm based on: * * Copyright (C) 2004-2005 Miguel, Jmol Development, www.jmol.org * * Contact: hansonr@stolaf.edu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA. */ // for documentation see www.jmol.org/jslibrary try{if(typeof(_jmol)!="undefined")exit() // place "?NOAPPLET" on your command line to check applet control action with a textarea // place "?JMOLJAR=xxxxx" to use a specific jar file // bob hanson -- jmolResize(w,h) -- resizes absolutely or by percent (w or h 0.5 means 50%) // angel herraez -- update of jmolResize(w,h,targetSuffix) so it is not tied to first applet // bob hanson -- jmolEvaluate -- evaluates molecular math 8:37 AM 2/23/2007 // bob hanson -- jmolScriptMessage -- returns all "scriptStatus" messages 8:37 AM 2/23/2007 // bob hanson -- jmolScriptEcho -- returns all "scriptEcho" messages 8:37 AM 2/23/2007 // bob hanson -- jmolScriptWait -- 11:31 AM 5/2/2006 // bob hanson -- remove trailing separatorHTML in radio groups -- 12:18 PM 5/6/2006 // bob hanson -- adds support for dynamic DOM script nodes 7:04 AM 5/19/2006 // bob hanson -- adds try/catch for wiki - multiple code passes 7:05 AM 5/19/2006 // bob hanson -- auto-initiates to defaultdir/defaultjar -- change as desired. // bob hanson -- adding save/restore orientation w/ and w/o delay 11:49 AM 5/25/2006 // bob hanson -- adding AjaxJS service 11:16 AM 6/3/2006 // bob hanson -- fix for iframes not available for finding applet // bob hanson -- added applet fake ?NOAPPLET URL flag // bob hanson -- added jmolSetCallback(calbackName, funcName) 3:32 PM 6/13/2006 // used PRIOR to jmolApplet() or jmolAppletInline() // added 4th array element in jmolRadioGroup -- title // added and id around link, checkbox, radio, menu // fixing AJAX loads for MSIE/Opera-Mozilla incompatibility // -- renamed Jmol-11.js from Jmol-new.js; JmolApplet.jar from JmolAppletProto.jar // renamed Jmol.js for Jmol 11 distribution // -- modified jmolRestoreOrientation() to be immediate, no 1-second delay // bob hanson -- jmolScriptWait always returns a string -- 11:23 AM 9/16/2006 // bh -- jmolCommandInput() // bh -- jmolSetTranslation(TF) -- forces translation even if there might be message callback issues // bh -- minor fixes suggested by Angel // bh -- adds jmolSetSyncId() and jmolGetSyncId() // bh 3/2008 -- adds jmolAppendInlineScript() and jmolAppendInlineArray() // bh 3/2008 -- fixes IE7 bug in relation to jmolLoadInlineArray() // bh 6/2008 -- adds jmolSetAppletWindow() // Angel H. 6/2008 -- added html " var t = "" if (labelHtml.toLowerCase().indexOf("")>=0) { t += eospan eospan = ""; } t += "" +eospan; if (_jmol.debugAlert) alert(t); return _jmolDocumentWrite(t); } function jmolStartNewRadioGroup() { ++_jmol.radioGroupCount; } function jmolRadioGroup(arrayOfRadioButtons, separatorHtml, groupName, id, title) { /* array: [radio1,radio2,radio3...] where radioN = ["script","label",isSelected,"id","title"] */ _jmolInitCheck(); var type = typeof arrayOfRadioButtons; if (type != "object" || type == null || ! arrayOfRadioButtons.length) { alert("invalid arrayOfRadioButtons"); return; } if (separatorHtml == undefined || separatorHtml == null) separatorHtml = "  "; var len = arrayOfRadioButtons.length; jmolStartNewRadioGroup(); if (!groupName) groupName = "jmolRadioGroup" + (_jmol.radioGroupCount - 1); var t = ""; for (var i = 0; i < len; ++i) { if (i == len - 1) separatorHtml = ""; var radio = arrayOfRadioButtons[i]; type = typeof radio; if (type == "object") { t += _jmolRadio(radio[0], radio[1], radio[2], separatorHtml, groupName, (radio.length > 3 ? radio[3]: (id ? id : groupName)+"_"+i), (radio.length > 4 ? radio[4] : 0), title); } else { t += _jmolRadio(radio, null, null, separatorHtml, groupName, (id ? id : groupName)+"_"+i, title); } } t+="" if (_jmol.debugAlert) alert(t); return _jmolDocumentWrite(t); } function jmolRadio(script, labelHtml, isChecked, separatorHtml, groupName, id, title) { _jmolInitCheck(); if (_jmol.radioGroupCount == 0) ++_jmol.radioGroupCount; var t = _jmolRadio(script, labelHtml, isChecked, separatorHtml, groupName, (id ? id : groupName + "_" + _jmol.radioCount), title ? title : 0); if (_jmol.debugAlert) alert(t); return _jmolDocumentWrite(t); } function jmolLink(script, label, id, title) { _jmolInitCheck(); if (id == undefined || id == null) id = "jmolLink" + _jmol.linkCount; if (label == undefined || label == null) label = script.substring(0, 32); ++_jmol.linkCount; var scriptIndex = _jmolAddScript(script); var t = "" + label + ""; if (_jmol.debugAlert) alert(t); return _jmolDocumentWrite(t); } function jmolCommandInput(label, size, id, title) { _jmolInitCheck(); if (id == undefined || id == null) id = "jmolCmd" + _jmol.cmdCount; if (label == undefined || label == null) label = "Execute"; if (size == undefined || isNaN(size)) size = 60; ++_jmol.cmdCount; var t = ""; if (_jmol.debugAlert) alert(t); return _jmolDocumentWrite(t); } function _jmolCommandKeyPress(e, id, target) { var keycode = (window.event ? window.event.keyCode : e ? e.which : 0); if (keycode == 13) { jmolScript(document.getElementById(id).value, target) } } function jmolMenu(arrayOfMenuItems, size, id, title) { _jmolInitCheck(); if (id == undefined || id == null) id = "jmolMenu" + _jmol.menuCount; ++_jmol.menuCount; var type = typeof arrayOfMenuItems; if (type != null && type == "object" && arrayOfMenuItems.length) { var len = arrayOfMenuItems.length; if (typeof size != "number" || size == 1) size = null; else if (size < 0) size = len; var sizeText = size ? " size='" + size + "' " : ""; var t = "" if (labelHtml.toLowerCase().indexOf("")>=0) { t += eospan eospan = ""; } t += "" +eospan + separatorHtml; return t; } function _jmolFindApplet(target) { // first look for the target in the current window var applet = _jmolFindAppletInWindow(_jmol.appletWindow != null ? _jmol.appletWindow : window, target); // THEN look for the target in child frames if (applet == undefined) applet = _jmolSearchFrames(window, target); // FINALLY look for the target in sibling frames if (applet == undefined) applet = _jmolSearchFrames(top, target); // look starting in top frame return applet; } function _jmolGetApplet(targetSuffix){ var target = "jmolApplet" + (targetSuffix ? targetSuffix : "0"); var applet = _jmolFindApplet(target); if (applet) return applet if(!_jmol.alerted)alert("could not find applet " + target); _jmol.alerted = true; return null } function _jmolSearchFrames(win, target) { var applet; var frames = win.frames; if (frames && frames.length) { // look in all the frames below this window try{ for (var i = 0; i < frames.length; ++i) { applet = _jmolSearchFrames(frames[i], target); if (applet) return applet; } }catch(e) { if (_jmol.debugAlert) alert("Jmol.js _jmolSearchFrames cannot access " + win.name + ".frame[" + i + "] consider using jmolSetAppletWindow()") } } return applet = _jmolFindAppletInWindow(win, target) } function _jmolFindAppletInWindow(win, target) { var doc = win.document; // getElementById fails on MacOSX Safari & Mozilla if (_jmol.useHtml4Object || _jmol.useIEObject) return doc.getElementById(target); else if (doc.applets) return doc.applets[target]; else return doc[target]; } function _jmolAddScript(script) { if (! script) return 0; var index = _jmol.scripts.length; _jmol.scripts[index] = script; return index; } function _jmolClick(scriptIndex, targetSuffix, elementClicked) { _jmol.element = elementClicked; jmolScript(_jmol.scripts[scriptIndex], targetSuffix); } function _jmolMenuSelected(menuObject, targetSuffix) { var scriptIndex = menuObject.value; if (scriptIndex != undefined) { jmolScript(_jmol.scripts[scriptIndex], targetSuffix); return; } var len = menuObject.length; if (typeof len == "number") { for (var i = 0; i < len; ++i) { if (menuObject[i].selected) { _jmolClick(menuObject[i].value, targetSuffix); return; } } } alert("?Que? menu selected bug #8734"); } _jmol.checkboxMasters = {}; _jmol.checkboxItems = {}; function jmolSetCheckboxGroup(chkMaster,chkBox) { var id = chkMaster; if(typeof(id)=="number")id = "jmolCheckbox" + id; chkMaster = document.getElementById(id); if (!chkMaster)alert("jmolSetCheckboxGroup: master checkbox not found: " + id); var m = _jmol.checkboxMasters[id] = {}; m.chkMaster = chkMaster; m.chkGroup = {}; for (var i = 1; i < arguments.length; i++){ var id = arguments[i]; if(typeof(id)=="number")id = "jmolCheckbox" + id; checkboxItem = document.getElementById(id); if (!checkboxItem)alert("jmolSetCheckboxGroup: group checkbox not found: " + id); m.chkGroup[id] = checkboxItem; _jmol.checkboxItems[id] = m; } } function _jmolNotifyMaster(m){ //called when a group item is checked var allOn = true; var allOff = true; for (var chkBox in m.chkGroup){ if(m.chkGroup[chkBox].checked) allOff = false; else allOn = false; } if (allOn)m.chkMaster.checked = true; if (allOff)m.chkMaster.checked = false; if ((allOn || allOff) && _jmol.checkboxItems[m.chkMaster.id]) _jmolNotifyMaster(_jmol.checkboxItems[m.chkMaster.id]) } function _jmolNotifyGroup(m, isOn){ //called when a master item is checked for (var chkBox in m.chkGroup){ var item = m.chkGroup[chkBox] item.checked = isOn; if (_jmol.checkboxMasters[item.id]) _jmolNotifyGroup(_jmol.checkboxMasters[item.id], isOn) } } function _jmolCbClick(ckbox, whenChecked, whenUnchecked, targetSuffix) { _jmol.control = ckbox _jmolClick(ckbox.checked ? whenChecked : whenUnchecked, targetSuffix); if(_jmol.checkboxMasters[ckbox.id]) _jmolNotifyGroup(_jmol.checkboxMasters[ckbox.id], ckbox.checked) if(_jmol.checkboxItems[ckbox.id]) _jmolNotifyMaster(_jmol.checkboxItems[ckbox.id]) } function _jmolCbOver(ckbox, whenChecked, whenUnchecked) { window.status = _jmol.scripts[ckbox.checked ? whenUnchecked : whenChecked]; } function _jmolMouseOver(scriptIndex) { window.status = _jmol.scripts[scriptIndex]; } function _jmolMouseOut() { window.status = " "; return true; } function _jmolSetCodebase(codebase) { _jmol.codebase = codebase ? codebase : "."; if (_jmol.debugAlert) alert("jmolCodebase=" + _jmol.codebase); } function _jmolOnloadResetForms() { // must be evaluated ONLY once _jmol.previousOnloadHandler = window.onload; window.onload = function() { with (_jmol) { if (buttonCount+checkboxCount+menuCount+radioCount+radioGroupCount > 0) { var forms = document.forms; for (var i = forms.length; --i >= 0; ) forms[i].reset(); } if (previousOnloadHandler) previousOnloadHandler(); } } } //////////////////////////////////// /////extensions for getProperty///// //////////////////////////////////// function _jmolEvalJSON(s,key){ s=s+"" if(!s)return [] if(s.charAt(0)!="{"){ if(s.indexOf(" | ")>=0)s=s.replace(/\ \|\ /g, "\n") return s } var A = eval("("+s+")") if(!A)return if(key && A[key])A=A[key] return A } function _jmolEnumerateObject(A,key){ var sout="" if(typeof(A) == "string" && A!="null"){ sout+="\n"+key+"=\""+A+"\"" }else if(!isNaN(A)||A==null){ sout+="\n"+key+"="+(A+""==""?"null":A) }else if(A.length){ sout+=key+"=[]" for(var i=0;ib[0]?-1:0) } function _jmolSortMessages(A){ if(!A || typeof(A)!="object")return [] var B = [] for(var i=A.length-1;i>=0;i--)for(var j=0;j=0;) for(var j=0;j< Ret[i].length;j++) s+=Ret[i][j]+"\n" return s } function jmolScriptWaitOutput(script, targetSuffix) { if(!targetSuffix)targetSuffix="0" var ret = "" try{ if (script) { _jmolCheckBrowser(); var applet=_jmolGetApplet(targetSuffix); if (applet) ret += applet.scriptWaitOutput(script); } }catch(e){ } return ret; } function jmolEvaluate(molecularMath, targetSuffix) { //carries out molecular math on a model if(!targetSuffix)targetSuffix="0" var result = "" + jmolGetPropertyAsJavaObject("evaluate", molecularMath, targetSuffix); var s = result.replace(/\-*\d+/,"") if (s == "" && !isNaN(parseInt(result)))return parseInt(result); var s = result.replace(/\-*\d*\.\d*/,"") if (s == "" && !isNaN(parseFloat(result)))return parseFloat(result); return result; } function jmolScriptEcho(script, targetSuffix) { // returns a newline-separated list of all echos from a script if(!targetSuffix)targetSuffix="0" var Ret=jmolScriptWaitAsArray(script, targetSuffix) var s = "" for(var i=Ret.length;--i>=0;) for(var j=Ret[i].length;--j>=0;) if (Ret[i][j][1] == "scriptEcho")s+=Ret[i][j][3]+"\n" return s.replace(/ \| /g, "\n") } function jmolScriptMessage(script, targetSuffix) { // returns a newline-separated list of all messages from a script, ending with "script completed\n" if(!targetSuffix)targetSuffix="0" var Ret=jmolScriptWaitAsArray(script, targetSuffix) var s = "" for(var i=Ret.length;--i>=0;) for(var j=Ret[i].length;--j>=0;) if (Ret[i][j][1] == "scriptStatus")s+=Ret[i][j][3]+"\n" return s.replace(/ \| /g, "\n") } function jmolScriptWaitAsArray(script, targetSuffix) { var ret = "" try{ jmolGetStatus("scriptEcho,scriptMessage,scriptStatus,scriptError",targetSuffix) if (script) { _jmolCheckBrowser(); var applet=_jmolGetApplet(targetSuffix); if (applet) ret += applet.scriptWait(script); ret = _jmolEvalJSON(ret,"jmolStatus") if(typeof ret == "object") return ret } }catch(e){ } return [[ret]] } //////////// save/restore orientation ///////////// function jmolSaveOrientation(id, targetSuffix) { if(!targetSuffix)targetSuffix="0" return _jmol["savedOrientation"+id] = jmolGetPropertyAsArray("orientationInfo","info",targetSuffix).moveTo } function jmolRestoreOrientation(id, targetSuffix) { if(!targetSuffix)targetSuffix="0" var s=_jmol["savedOrientation"+id] if (!s || s == "")return s=s.replace(/1\.0/,"0") return jmolScriptWait(s,targetSuffix) } function jmolRestoreOrientationDelayed(id, delay, targetSuffix) { if(arguments.length < 2)delay=1; if(!targetSuffix)targetSuffix="0" var s=_jmol["savedOrientation"+id] if (!s || s == "")return s=s.replace(/1\.0/,delay) return jmolScriptWait(s,targetSuffix) } //////////// add parameter ///////////// /* * for adding callbacks or other parameters. Use: jmolSetDocument(0) var s= jmolApplet(....) s = jmolAppletAddParam(s,"messageCallback", "myFunctionName") document.write(s) jmolSetDocument(document) // if you want to then write buttons and such normally */ function jmolAppletAddParam(appletCode,name,value){ if(value == "")return appletCode return appletCode.replace(/\\n=0){ jmolApplet = function(w){ var s="" +"
" +"Applet would be here" +"

" +"

" return _jmolDocumentWrite(s) } _jmolFindApplet = function(){return jmolApplet0} jmolApplet0 = { script: function(script){document.getElementById("fakeApplet").value="\njmolScript:\n"+script} ,scriptWait: function(script){document.getElementById("fakeApplet").value="\njmolScriptWait:\n"+script} ,loadInline: function(data,script){document.getElementById("fakeApplet").value="\njmolLoadInline data:\n"+data+"\n\nscript:\n"+script} } } /////////////////////////////////////////// // This should no longer be needed, jmolResizeApplet() is better; kept for backwards compatibility /* Resizes absolutely (pixels) or by percent of window (w or h 0.5 means 50%). targetSuffix is optional and defaults to zero (first applet in page). Both w and h are optional, but needed if you want to use targetSuffix. h defaults to w w defaults to 100% of window If either w or h is between 0 and 1, then it is taken as percent/100. If either w or h is greater than 1, then it is taken as a size (pixels). */ function jmolResize(w,h,targetSuffix) { _jmol.alerted = true; var percentW = (!w ? 100 : w <= 1 && w > 0 ? w * 100 : 0); var percentH = (!h ? percentW : h <= 1 && h > 0 ? h * 100 : 0); if (_jmol.browser=="msie") { var width=document.body.clientWidth; var height=document.body.clientHeight; } else { var netscapeScrollWidth=15; var width=window.innerWidth - netscapeScrollWidth; var height=window.innerHeight-netscapeScrollWidth; } var applet = _jmolGetApplet(targetSuffix); if(!applet)return; applet.style.width = (percentW ? width * percentW/100 : w)+"px"; applet.style.height = (percentH ? height * percentH/100 : (h ? h : w))+"px"; //title=width + " " + height + " " + (new Date()); } // 13 Jun 09 -- makes jmolResize() obsolete (kept for backwards compatibility) function jmolResizeApplet(size,targetSuffix) { // See _jmolGetAppletSize() for the formats accepted as size [same used by jmolApplet()] // Special case: an empty value for width or height is accepted, meaning no change in that dimension. _jmol.alerted = true; var applet = _jmolGetApplet(targetSuffix); if(!applet)return; var sz = _jmolGetAppletSize(size, "px"); sz[0] && (applet.style.width = sz[0]); sz[1] && (applet.style.height = sz[1]); } function _jmolGetAppletSize(size, units) { /* Accepts single number or 2-value array, each one can be one of: percent (text string ending %), decimal 0 to 1 (percent/100), number, or text string (interpreted as nr.) [width, height] array of strings is returned, with units added if specified. Percent is relative to container div or element (which should have explicitly set size). */ var width, height; if ( (typeof size) == "object" && size != null ) { width = size[0]; height = size[1]; } else { width = height = size; } return [_jmolFixDim(width, units), _jmolFixDim(height, units)]; } function _jmolFixDim(x, units) { var sx = "" + x; return (sx.length == 0 ? (units ? "" : _jmol.allowedJmolSize[2]) : sx.indexOf("%") == sx.length-1 ? sx : (x = parseFloat(x)) <= 1 && x > 0 ? x * 100 + "%" : (isNaN(x = Math.floor(x)) ? _jmol.allowedJmolSize[2] : x < _jmol.allowedJmolSize[0] ? _jmol.allowedJmolSize[0] : x > _jmol.allowedJmolSize[1] ? _jmol.allowedJmolSize[1] : x) + (units ? units : "")); }