Files
2025-12-04 09:57:17 +01:00

307 lines
9.8 KiB
PHP

<?php
class jsMol2wp{
var $fileURL = '';
var $instance = 0;
var $acc = '';
var $appletID = '';
var $type = '';
var $load = '';
public function __construct($acc, $type, $caption, $id, $fileURL, $isosurface){
$this->path = plugins_url().'/jsmol2wp/';
$this->acc = $acc;
$this->type = $type;
$p = get_post();
# determine the instance if there are multiple copies
# of the shortcode in this post
# we want to do this without preg_match to work on different PHP versions
$m = explode('[jsmol', get_the_content());
array_shift($m);
foreach($m as $i => $match){
$t = explode(']', $match);
# there could be nested shortcodes or other shortcodes in the text
# but trim off what is safe to trim off
if(count($t) > 1){
array_pop($t);
$match = implode(']', $t);
}
# odd bug requires recasting as a string to get stripos to work
$match = (string)$match;
# catenate the post_id to the instance to make the id unique
# when displaying multiple posts per page
if( ($acc == '' || stripos($match, $acc) > 0 ) &&
($caption == '' || stripos($match, $caption) > 0) &&
($fileURL == '' || stripos($match, $fileURL) > 0) &&
($isosurface == '' || stripos($match, $isosurface) > 0) &&
($id == '' || stripos($match, $id) > 0)
) $this->instance = $p->ID."_$i";
}
if($fileURL != ''){
# use a passed url if it's there
$this->fileURL = $fileURL;
}else{
# otherwise, look for an attachment
# $attachment = get_page_by_title($acc, OBJECT, 'attachment' );
$attachment = self::getAttachmentPost("$acc.$type");
if(!is_null($attachment) && isset($attachment->guid)){
$this->fileURL = $attachment->guid;
}
}
$this->isosurface = $isosurface;
if($isosurface != ''){
# isosurface will be an uploaded file or a URL
# replace if it's an attachment
$attachment = self::getAttachmentPost($isosurface);
if(!is_null($attachment) && isset($attachment->guid)){
$this->isosurface = $attachment->guid;
}
}
$this->appletID = "jmolApplet".$this->instance;
}
function makeViewer($acc, $type, $load, $caption, $commands, $wrap, $debug){
# not used?
$mydiv = "myDiv".$this->instance;
# initialize output
$html = "";
$template = $this->getTemplate($load);
$template = str_replace('jmolApplet0',$this->appletID, $template );
$template = str_replace('XXXX',$acc, $template );
$template = str_replace('__caption__',$caption, $template );
$template = $this->makeScriptButtons($commands, $template, $wrap);
$html .= $template;
if($debug != 'false'){
$html .= $this->debug($debug);
}
return $html;
}
function makeScriptButtons($commands, $template, $wrap = 4){
$buttons = '';
$customButtons = '';
$jmolCommandInput = '';
$notButtons = 0;
$applet = $this->appletID;
$commands = str_replace("\n",' ', strip_tags($commands));
if($commands != ''){
$commandsSet = explode('|||', $commands);
foreach($commandsSet as $i => $command){
list($label, $script) = explode('=', $command."=",2);
$label = trim($label);
$script = trim($script,"\n=");
# if there is no script, assume that the line is raw Jmol script
switch($label){
case '':
# if label is not set, we assume the user wants Jmol script not
# wrapped in a button
$buttons .= "Jmol.script($applet,\"$script\");\n";
# if it's the first one, append to the load for the reset script
if($i == 0) $this->load .= $script;
$notButtons++;
break;
case 'jmolCommandInput':
# this is a special case to add a command line input
$jmolCommandInput .= "Jmol.jmolCommandInput($applet);\n";
$notButtons++;
break;
default:
$customButtons .= "jmolButton('$script','$label')\n";
}
$j = $i-$notButtons;
if($j%$wrap == 0 && $j != 0) $customButtons .= "jmolBr();\n";
}
}
if(strpos($this->load, 'isosurface') > 0){
$buttons .= 'jmolButton("if(surfaceflag == false);isosurface on;surfaceflag = true;else;isosurface off;surfaceflag = false;endif","isosurface");';
}
$buttons .= "jmolButton('reset;select all;$this->load','reset')\njmolBr();\n";
$buttons .= $customButtons;
$buttons .= $this->standardButtons($wrap).$jmolCommandInput;
$template = str_replace('__commands__',$buttons, $template );
return $template;
}
/*
jmolBr() to make $wrap buttons/row
*/
function standardButtons($wrap){
$str = "Jmol.setButtonCss(null,\"style='width:100px'\")\n";
$stdButtons = array();
switch ($this->type){
case 'pdb':
$stdButtons = explode("\n",
'jmolButton("color cpk", "'.__('color cpk','jsmol2wp').'");
jmolButton("color group", "'.__('color group','jsmol2wp').'");
jmolButton("color amino", "'.__('color amino','jsmol2wp').'");
jmolButton("color structure", "'.__('color structure','jsmol2wp').'");
jmolButton("trace only");
jmolButton("cartoon only");
jmolButton("backbone only");
jmolButton("spacefill 23%;wireframe 0.15","ball&stick");'
);
break;
default:
$stdButtons = explode("\n",
'jmolButton("color cpk");
jmolButton("color grey");
jmolButton("spacefill","spacefill");
jmolButton("if(dotsflag);dots off;dotsflag = false;else;dots on;dotsflag = true;endif","dots");
jmolButton("spacefill off;wireframe 0.15","wireframe");
jmolButton("spacefill 23%;wireframe 0.15","ball&stick");'
);
break;
}
foreach($stdButtons as $i => $button){
if($i%$wrap == 0 && $i != 0) $str .= "jmolBr();\n";
$str .= $button;
}
return $str;
}
/*
Gets the template and creates the molecule load and format commands
*/
function getTemplate($load){
$template = file_get_contents(dirname(__FILE__).'/jsmol_template.htm');
# if load is set, it is used and we don't guess
if($load != ''){
$loadStr = $load;
}else{
# otherwise try to guess the right load string
$loadStr = '';
if($this->load != ''){
$loadStr = $this->load;
}else{
if($this->acc != '' && ($this->acc{0} == '$'||$this->acc{0} == ':')){
$loadStr = "load $this->acc;spacefill 23%;wireframe 0.15;color cpk;spin off;";
$this->type = 'mol';
}
# if the type is pdb, look for it at rcsb.org
if($this->type == 'pdb'){
$loadStr = "load \"https://files.rcsb.org/view/$this->acc.pdb\";";
}
# if there is a local file, override the guessed remote load and if needed, guess the type
if($this->fileURL != ''){
$this->type = pathinfo($this->fileURL, PATHINFO_EXTENSION);
$loadStr = "load $this->fileURL;";
}
# add the default format
switch ($this->type){
case 'obj':
#this is going to only be with a fileURL?
$loadStr = str_replace(
"load",
"isosurface OBJ ",
$loadStr);
$loadStr .= " spacefill 23%;wireframe 0.15;color cpk;spin off;";
break;
case 'xyz':
case 'mol':
case 'mol2':
#change the default load coloring and display
$loadStr .= ' spacefill 23%;wireframe 0.15;color cpk;spin off;';
break;
case 'mrc':
return "Support for binary type: $this->type is not implemented yet";
break;
case 'pdb':
$loadStr .= ' spacefill off;wireframe off;cartoons on;color structure;spin off;';
break;
default:
}
}
}
# add isosurface if it's present
if($this->isosurface != ''){
$loadStr .= " isosurface $this->isosurface;";
}
# add the acc label
if($this->acc != '') $loadStr .= "set echo top center; echo ".ltrim($this->acc,'$:').';';
# save the loadstr for use by the reset button. Do this before set lang if needed
$this->load = $loadStr;
# set default language if available from WP
$lang = get_locale();
if($lang != 'en_US'){
$loadStr = "set language $lang;".$loadStr;
}
$template = str_replace('__load__', $loadStr, $template);
$template = str_replace('http://chemapps.stolaf.edu/jmol/jsmol/',$this->path, $template );
$template = str_replace('__j2s__',$this->path."j2s", $template );
# button text
$template = str_replace('__toggle_spin__',__('Toggle Spin', 'jsmol2wp'), $template );
# help file link
$template = str_replace('__help__', "<a href='$this->path/help.htm'>".__('About/Help','jsmol2wp')."</a>", $template );
return $template;
}
static function getAttachmentPost($filename){
$attachment = null;
$args = array('post_type' => 'attachment', 'posts_per_page'=>-1, 'post_status' => 'any', 'post_parent' => null);
$media = get_posts( $args );
foreach($media as $p){
$attFileName = basename($p->guid);
if($filename == $attFileName){
$attachment = $p;
break;
}
}
wp_reset_postdata();
# if the above fails, check for a case where the extension was not given in type
if(is_null($attachment)) $attachment = get_page_by_title($filename, OBJECT, 'attachment' );
return $attachment;
}
function debug($debug){
$str = '<pre>';
# file path
switch($debug){
case 'short':
$str .= "applet ID: $this->appletID\n";
$str .= "acc: $this->acc\n";
$str .= "type:$this->type\n";
break;
case 'full':
default:
$str .= print_r($this,true);
$dirpath = dirname(__FILE__);
$str .= "Directory path:$dirpath\n";
$fileTests = array(
'JSmol.min.nojq.js' => "$this->path",
'package.js' => "$this->path/j2s/core/"
);
$str .= "test whether various files are readable by wp_remote_fopen\n";
foreach($fileTests as $file => $path){
if(!wp_remote_fopen("$path$file")){
$str .= "can't load $path$file\n";
}else{
$str .= "$file load OK\n";
}
}
$str .= 'file_get_contents: ';
$str .= file_get_contents(__FILE__) ? 'Enabled' : 'Disabled';
if($this->fileURL != ''){
$str .= "\npath to uploaded file:".$this->fileURL."\n";
$tmp = wp_remote_fopen($this->fileURL);
$str .= "Excerpt from file:".substr($tmp, 0, 20)."...\n";
$attachment = get_page_by_title($this->acc, OBJECT, 'attachment' );
if(is_null($attachment)) $str .= "attachment for $this->acc not found\n";
}
break;
}
$str .= "</pre>";
return $str;
}
}