├── README.md ├── caret.js ├── index.php ├── mathematica.css ├── mathematica.gif ├── mathematica.ico ├── mathematica.js ├── mathematica.php ├── mathematica.png └── todo /README.md: -------------------------------------------------------------------------------- 1 | Web Interface for Mathematica 2 | ========================================= 3 | 4 | A simple clean **web interface** for a local install of the **Mathematica** kernel. 5 | This is *not* meant as a replacement for Mathematica's rich Notebook interface but 6 | rather, a simple interface for that *quick computation* that is required when you 7 | (or your colleagues) are offsite and all you have is a browser. 8 | 9 | ###### Pre-requisites: 10 | 11 | * **Mathematica** installed on a networked machine 12 | * Web-server (Apache, nginx, etc.) running PHP 13 | 14 | ###### Installation: 15 | 16 | 1. Copy out the files here into a directory inside your DocumentRoot (e.g. `C:/www/mathematica/`) 17 | 2. Change the appropriate variables in `mathematica.php` 18 | 19 | 20 | ###### Screenshot: 21 | 22 | ![alt text](https://raw.github.com/forhadahmed/mathematica/master/mathematica.png "Mathematica Web Screenshot") 23 | 24 | 25 | ###### Notes: 26 | 27 | * Tested with Mathematica 8 on Windows - no major issues. Linux has some issues with graphics but mostly works. 28 | * **Evaluated expressions are independent** - you cannot use a value assigned in a previous expression 29 | 30 | 31 | -------------------------------------------------------------------------------- /caret.js: -------------------------------------------------------------------------------- 1 | // Set caret position easily in jQuery 2 | // Written by and Copyright of Luke Morton, 2011 3 | // Licensed under MIT 4 | (function ($) { 5 | // Behind the scenes method deals with browser 6 | // idiosyncrasies and such 7 | $.caretTo = function (el, index) { 8 | if (el.createTextRange) { 9 | var range = el.createTextRange(); 10 | range.move("character", index); 11 | range.select(); 12 | } else if (el.selectionStart != null) { 13 | el.focus(); 14 | el.setSelectionRange(index, index); 15 | } 16 | }; 17 | 18 | // Another behind the scenes that collects the 19 | // current caret position for an element 20 | 21 | // TODO: Get working with Opera 22 | $.caretPos = function (el) { 23 | if ("selection" in document) { 24 | var range = el.createTextRange(); 25 | try { 26 | range.setEndPoint("EndToStart", document.selection.createRange()); 27 | } catch (e) { 28 | // Catch IE failure here, return 0 like 29 | // other browsers 30 | return 0; 31 | } 32 | return range.text.length; 33 | } else if (el.selectionStart != null) { 34 | return el.selectionStart; 35 | } 36 | }; 37 | 38 | // The following methods are queued under fx for more 39 | // flexibility when combining with $.fn.delay() and 40 | // jQuery effects. 41 | 42 | // Set caret to a particular index 43 | $.fn.caret = function (index, offset) { 44 | if (typeof(index) === "undefined") { 45 | return $.caretPos(this.get(0)); 46 | } 47 | 48 | return this.queue(function (next) { 49 | if (isNaN(index)) { 50 | var i = $(this).val().indexOf(index); 51 | 52 | if (offset === true) { 53 | i += index.length; 54 | } else if (typeof(offset) !== "undefined") { 55 | i += offset; 56 | } 57 | 58 | $.caretTo(this, i); 59 | } else { 60 | $.caretTo(this, index); 61 | } 62 | 63 | next(); 64 | }); 65 | }; 66 | 67 | // Set caret to beginning of an element 68 | $.fn.caretToStart = function () { 69 | return this.caret(0); 70 | }; 71 | 72 | // Set caret to the end of an element 73 | $.fn.caretToEnd = function () { 74 | return this.queue(function (next) { 75 | $.caretTo(this, $(this).val().length); 76 | next(); 77 | }); 78 | }; 79 | }(jQuery)); -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mathematica Web 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 24 | 25 | 26 |
27 | 28 | 29 | 38 | 39 |
30 | 31 | 32 | 33 | 34 | 35 | 36 |
Mathematica
37 |
40 |
41 | 42 |
43 | 44 |
45 | 46 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /mathematica.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* CSS Document */ 3 | 4 | div,table, input { 5 | font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; 6 | font-size: 12px; 7 | } 8 | 9 | 10 | .current { 11 | width:95%; 12 | border:hidden; 13 | font-family:'Courier New', Courier, monospace; 14 | outline:none; 15 | } 16 | 17 | body { 18 | margin-left: 0px; 19 | margin-top: 8px; 20 | margin-right: 0px; 21 | margin-bottom: 35px; 22 | } 23 | 24 | .button { 25 | border: 1px solid #DDD; 26 | border-radius: 3px; 27 | text-shadow: 0 1px 1px white; 28 | -webkit-box-shadow: 0 1px 1px #fff; 29 | -moz-box-shadow: 0 1px 1px #fff; 30 | box-shadow: 0 1px 1px #fff; 31 | font: bold 10px Sans-Serif; 32 | white-space: nowrap; 33 | padding: 3px 3px; 34 | vertical-align: middle; 35 | color: #666; 36 | background: transparent; 37 | cursor: pointer; 38 | } 39 | .button:hover, .button:focus { 40 | border-color: #999; 41 | background: -webkit-linear-gradient(top, white, #E0E0E0); 42 | background: -moz-linear-gradient(top, white, #E0E0E0); 43 | background: -ms-linear-gradient(top, white, #E0E0E0); 44 | background: -o-linear-gradient(top, white, #E0E0E0); 45 | -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.25), inset 0 0 1px #fff; 46 | -moz-box-shadow: 0 1px 1px rgba(0,0,0,0.25), inset 0 0 1px #fff; 47 | box-shadow: 0 1px 1px rgba(0,0,0,0.25), inset 0 0 1px #fff; 48 | } 49 | .button:active { 50 | border: 1px solid #AAA; 51 | border-bottom-color: #CCC; 52 | border-top-color: #999; 53 | -webkit-box-shadow: inset 0 1px 1px #aaa; 54 | -moz-box-shadow: inset 0 1px 1px #aaa; 55 | box-shadow: inset 0 1px 1px #aaa; 56 | background: -webkit-linear-gradient(top, #E6E6E6, gainsboro); 57 | background: -moz-linear-gradient(top, #E6E6E6, gainsboro); 58 | background: -ms-linear-gradient(top, #E6E6E6, gainsboro); 59 | background: -o-linear-gradient(top, #E6E6E6, gainsboro); 60 | } 61 | 62 | .header { 63 | position: fixed; 64 | background-color:#FFF; 65 | right: 0; 66 | top: 0; 67 | border-bottom: 1px dotted #ff9900; 68 | width:100%; 69 | height: 30px; 70 | } 71 | 72 | .footer { 73 | position: fixed; 74 | background-color:#FFF; 75 | right: 0; 76 | bottom: 0; 77 | border-top: 1px dotted #ff9900; 78 | width:100%; 79 | height: 30px; 80 | } 81 | 82 | .prompt { 83 | font-weight:bold; 84 | font-size:10px; 85 | } 86 | 87 | .output { 88 | padding-top: 8px; 89 | padding-left:4px; 90 | padding-bottom: 8px; 91 | } 92 | 93 | .error { 94 | color: red; 95 | } 96 | -------------------------------------------------------------------------------- /mathematica.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forhadahmed/mathematica/280ae289c4b01ec2ec0a74817e18f968815a27f5/mathematica.gif -------------------------------------------------------------------------------- /mathematica.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forhadahmed/mathematica/280ae289c4b01ec2ec0a74817e18f968815a27f5/mathematica.ico -------------------------------------------------------------------------------- /mathematica.js: -------------------------------------------------------------------------------- 1 | var row = ""; 2 | var math = ""; 3 | var maths = Array(); 4 | var history = 0; 5 | 6 | 7 | function mathematica_process(output) 8 | { 9 | if (output.indexOf("png") >= 0) { 10 | $('#rows > tbody:last').append("
"); 11 | } else if (output.indexOf("^") >= 0) { 12 | $('#rows > tbody:last').append("syntax error"); 13 | } else { 14 | $('#rows > tbody:last').append("unknown error"); 15 | } 16 | 17 | maths.push(math); 18 | history = maths.length; 19 | mathematica_prompt(); 20 | } 21 | 22 | 23 | function mathematica_query() 24 | { 25 | math = $("#input").val().trim(); 26 | 27 | if (math == "") { 28 | mathematica_unprompt(); 29 | mathematica_prompt(); 30 | return; 31 | } 32 | 33 | mathematica_unprompt(); 34 | 35 | $.ajax({url: "mathematica.php?math="+encodeURIComponent(math)}) 36 | .done (function(output) { mathematica_process(output); }) 37 | .error(function(output) { mathematica_process(output); }); 38 | } 39 | 40 | function mathematica_unprompt() 41 | { 42 | $("#input").attr('readonly','readonly'); 43 | $("#input").attr("id", "ID"); 44 | } 45 | 46 | 47 | function mathematica_keypress(e) 48 | { 49 | code = (e.keyCode ? e.keyCode : e.which); 50 | if (code == 13) mathematica_query(); 51 | } 52 | 53 | function mathematica_keydown(e) 54 | { 55 | code = (e.keyCode ? e.keyCode : e.which); 56 | 57 | if (code == 38) { // UP 58 | if (history > 0) $("#input").val(maths[--history]); 59 | $("#input").caretToEnd(); 60 | } 61 | 62 | if (code == 40) { // DOWN 63 | if (history < maths.length-1) $("#input").val(maths[++history]); 64 | $("#input").caretToEnd(); 65 | } 66 | } 67 | 68 | 69 | function mathematica_prompt() 70 | { 71 | $('#rows > tbody:last').append(row.replace("ID", "input").replace("X", "")); 72 | $('#input').val(''); 73 | $("#input").focus(); 74 | $('html, body').animate({ scrollTop: $("#input").offset().top }, 0); 75 | $("#f").css("bottom", "0"); 76 | $("#input").keypress(function(e) { mathematica_keypress (e)} ); 77 | $("#input").keydown (function(e) { mathematica_keydown (e)} ); 78 | } 79 | 80 | 81 | function mathematica_clear() 82 | { 83 | $("#rows").html(''); 84 | mathematica_prompt(); 85 | history = maths.length; 86 | } 87 | 88 | 89 | $(document).ready(function(){ 90 | row = $("#row").html(); 91 | mathematica_prompt(); 92 | $("#clear").click(function(e) { mathematica_clear(); }); 93 | }); 94 | 95 | -------------------------------------------------------------------------------- /mathematica.php: -------------------------------------------------------------------------------- 1 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /mathematica.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forhadahmed/mathematica/280ae289c4b01ec2ec0a74817e18f968815a27f5/mathematica.png -------------------------------------------------------------------------------- /todo: -------------------------------------------------------------------------------- 1 | filter commands that can cause harm 2 | warning to users if they set a variable that their setting will not be permanent 3 | show "loading" gif when user presses enter for a computation 4 | going up in history causes caret to be placed at the beginning of line (should be at end) 5 | global settings tweaks 6 | toggle between text output and rendered output 7 | mobile site 8 | FIX BUGS! 9 | --------------------------------------------------------------------------------