aboutsummaryrefslogtreecommitdiff
path: root/htdocs/js/mathy.js
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2017-11-07 20:44:10 -0500
committerPaul Duncan <pabs@pablotron.org>2017-11-07 20:44:10 -0500
commit074c8ca2a16bc4849e8ecea5a123d4d9a2995898 (patch)
treeae2597166fb9da56ff34bf8abafc59548bc0cad5 /htdocs/js/mathy.js
downloadmathy-074c8ca2a16bc4849e8ecea5a123d4d9a2995898.tar.bz2
mathy-074c8ca2a16bc4849e8ecea5a123d4d9a2995898.zip
initial commit
Diffstat (limited to 'htdocs/js/mathy.js')
-rw-r--r--htdocs/js/mathy.js245
1 files changed, 245 insertions, 0 deletions
diff --git a/htdocs/js/mathy.js b/htdocs/js/mathy.js
new file mode 100644
index 0000000..13794fc
--- /dev/null
+++ b/htdocs/js/mathy.js
@@ -0,0 +1,245 @@
+jQuery(function($) {
+ "use strict";
+
+ var TEMPLATES = new LuigiTemplate.Cache({
+ save: [
+ "<li>",
+ "<a ",
+ "href='#' ",
+ "title='Load \"%{name|h}\".' ",
+ "data-name='%{name|h}' ",
+ "data-text='%{text|h}' ",
+ ">",
+ "%{name|h}",
+ "</a>",
+ "</li>",
+ ],
+
+ none: [
+ "<li class='disabled'>",
+ "<a ",
+ "href='#' ",
+ "title='No saved results.' ",
+ ">",
+ "No saved results...",
+ "</a>",
+ "</li>",
+ ],
+ });
+
+ var Preview = window.Preview = {
+ delay: 150, // delay after keystroke before updating
+
+ preview: null, // filled in by Init below
+ buffer: null, // filled in by Init below
+
+ timeout: null, // store setTimout id
+ mjRunning: false, // true when MathJax is processing
+ mjPending: false, // true when a typeset has been queued
+ oldText: null, // used to check if an update is needed
+
+ //
+ // Get the preview and buffer DIV's
+ //
+ Init: function () {
+ this.preview = document.getElementById("MathPreview");
+ this.buffer = document.getElementById("MathBuffer");
+ },
+
+ //
+ // Switch the buffer and preview, and display the right one.
+ // (We use visibility:hidden rather than display:none since
+ // the results of running MathJax are more accurate that way.)
+ //
+ SwapBuffers: function () {
+ var buffer = this.preview, preview = this.buffer;
+ this.buffer = buffer; this.preview = preview;
+ buffer.style.visibility = "hidden"; buffer.style.position = "absolute";
+ preview.style.position = ""; preview.style.visibility = "";
+ },
+
+ //
+ // This gets called when a key is pressed in the textarea.
+ // We check if there is already a pending update and clear it if so.
+ // Then set up an update to occur after a small delay (so if more keys
+ // are pressed, the update won't occur until after there has been
+ // a pause in the typing).
+ // The callback function is set up below, after the Preview object is set up.
+ //
+ Update: function () {
+ if (this.timeout) {clearTimeout(this.timeout)}
+ this.timeout = setTimeout(this.callback, this.delay);
+ },
+
+ //
+ // Creates the preview and runs MathJax on it.
+ // If MathJax is already trying to render the code, return
+ // If the text hasn't changed, return
+ // Otherwise, indicate that MathJax is running, and start the
+ // typesetting. After it is done, call PreviewDone.
+ //
+ CreatePreview: function () {
+ var syntax = $('#menu-syntax .active a').data();
+
+ Preview.timeout = null;
+ if (this.mjPending) return;
+ var text = "\\[" + editor.getValue() + "\\]";
+ if (text === this.oldtext) return;
+ if (this.mjRunning) {
+ this.mjPending = true;
+ MathJax.Hub.Queue(["CreatePreview",this]);
+ } else {
+ this.buffer.innerHTML = this.oldtext = text;
+ this.mjRunning = true;
+ MathJax.Hub.Queue(
+ ["Typeset",MathJax.Hub,this.buffer],
+ ["PreviewDone",this]
+ );
+ }
+ },
+
+ //
+ // Indicate that MathJax is no longer running,
+ // and swap the buffers to show the results.
+ //
+ PreviewDone: function () {
+ this.mjRunning = this.mjPending = false;
+ this.SwapBuffers();
+ }
+ };
+
+ //
+ // Cache a callback to the CreatePreview action
+ //
+ Preview.callback = MathJax.Callback(["CreatePreview",Preview]);
+ Preview.callback.autoReset = true; // make sure it can run more than once
+
+ function add_text(el, text, pos) {
+ var val = el.value,
+ head = val.substring(0, el.selectionStart),
+ tail = val.substring(el.selectionEnd, val.length);
+
+ // update value
+ el.value = head + text + tail;
+
+ // get offset
+ if (pos === undefined)
+ pos = text.length;
+
+ // update caret position
+ el.selectionStart = el.selectionEnd = head.length + pos;
+ }
+
+ $('#input').keyup(function(ev) {
+ window.Preview.Update();
+ });
+
+ var autosave_timeout = null,
+ editor = ace.edit('editor');
+ editor.setShowPrintMargin(false);
+ editor.setTheme('ace/theme/monokai');
+ editor.getSession().setMode('ace/mode/latex');
+ editor.getSession().on('change', function(e) {
+ window.Preview.Update();
+ if (autosave_timeout) {
+ clearTimeout(autosave_timeout);
+ autosave_timeout = null;
+ }
+ autosave_timeout = setTimeout(function() {
+ localStorage.setItem('mathy_last', editor.getValue());
+ }, 1000);
+ });
+
+ (function() {
+ var last = localStorage.getItem('mathy_last');
+ if (!last)
+ return;
+ editor.setValue(last);
+ })();
+
+ $('#add').click(function() {
+ var el = $('#input')[0];
+ add_shit(el, 'shit');
+ try { el.focus(); } catch (e) {}
+ return false;
+ });
+
+ $('#saves').on('click', 'a', function() {
+ if ($(this).parent().hasClass('disabled'))
+ return false;
+
+ var text = $(this).data('text');
+ $('body').trigger('click');
+
+ setTimeout(function() {
+ editor.setValue(text);
+ }, 10);
+
+ return false;
+ }).parent().on('show.bs.dropdown', function() {
+ var saves = localStorage.getItem('mathy_saves');
+ saves = saves ? JSON.parse(saves) : [];
+
+ var html = '';
+ if (saves.length > 0) {
+ html = $.map(saves, function(row) {
+ return TEMPLATES.run('save', row);
+ }).join('');
+ } else {
+ html = TEMPLATES.run('none');
+ }
+
+ $('#saves').html(html);
+ });
+
+ $('#btn-save').click(function() {
+ // get name
+ var name = prompt('Enter name:', '');
+ if (!name)
+ return false;
+
+ // build sortable name
+ var sort = name
+ .replace(/\s+/g, ' ')
+ .replace(/^\s+|\s+$/g, '')
+ .toLowerCase();
+
+ // load saves
+ var saves = localStorage.getItem('mathy_saves');
+ saves = saves ? JSON.parse(saves) : [];
+
+ if ($.grep(saves, function(row) {
+ return row.save == sort;
+ }).length > 0) {
+ if (!confirm("Replace existing \"" + name + " \"?"))
+ return false;
+ }
+
+ // append to results
+ saves.push({
+ name: name,
+ sort: sort,
+ text: editor.getValue(),
+ });
+
+ // write saves
+ localStorage.setItem('mathy_saves', JSON.stringify(saves.sort(function(a, b) {
+ return b.sort < a.sort;
+ })));
+
+ return false;
+ });
+
+ $('#help').on('click', 'a', function() {
+ var text = $(this).data('text').replace(/^\s+|\s+$/g, '');
+ $('body').trigger('click');
+
+ setTimeout(function() {
+ editor.setValue(text);
+ }, 10);
+
+ return false;
+ });
+
+ Preview.Init();
+});