diff --git a/README.md b/README.md index 6705fe8..c257632 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,22 @@ The operators variable is an array of arrays. The outside array contains all of Demo of mathquill4quill with custom operator buttons +### List of previous formulas + +Previous formulas can be saved and re-used. The available related configurations are: + +```javascript +enableMathQuillFormulaAuthoring(quill, { + displayHistory: true, // defaults to false + historyCacheKey: '__my_app_math_history_cachekey_', // optional + historySize: 20 // optional (defaults to 10) +}); +``` + +This works by saving formula to a list (and local storage by default) everytime a new formula is used. Then displaying this list when a user opens the formula tooltip. + +![ezgif com-video-to-gif](https://user-images.githubusercontent.com/31671215/75315157-c96b5200-5816-11ea-99c2-f5414ee8e241.gif) + ### Autofocus For user convenience, mathquill4quill defaults to focusing the math input field when the formula button is pressed. You can disable this behavior via the `autofocus` option in the `enableMathQuillFormulaAuthoring()` function. Example: diff --git a/mathquill4quill.css b/mathquill4quill.css index 4ac7372..e997947 100644 --- a/mathquill4quill.css +++ b/mathquill4quill.css @@ -22,6 +22,35 @@ align-items: center; } +.mathquill4quill-history-button { + overflow: hidden; + margin: 5px; + width: 270px; + height: 65px; + min-height: 60px; + background-color: #fff; + border-color: #000; + border-radius: 7px; + border-width: 2px; + cursor: pointer; + transition: background-color 0.3s linear; + opacity: 1; +} + +.mathquill4quill-history-button:hover { + background-color: rgb(239, 240, 241); + opacity: 0.7; +} + +.mathquill4quill-history-container { + display: flex; + flex-direction: column; + align-items: center; + width: 300px; + height: 150px; + overflow: auto; +} + .mathquill4quill-latex-input { visibility: hidden !important; padding: 0 !important; diff --git a/mathquill4quill.js b/mathquill4quill.js index bf8fd40..6439bc5 100644 --- a/mathquill4quill.js +++ b/mathquill4quill.js @@ -68,6 +68,31 @@ window.mathquill4quill = function(dependencies) { return true; } + function fetchHistoryList(key) { + try { + return JSON.parse(localStorage.getItem(key)) || []; + } catch (e) { + return []; + } + } + + function addItemToHistoryList(key) { + const item = getCacheItem(key); + if (item && item.length > 0) { + const index = historyList.indexOf(item); + if (index != -1) { + historyList.splice(index, 1); + } + historyList.unshift(item); + if (historyList.length > historySize) historyList.pop(); + try { + localStorage.setItem(historyCacheKey, JSON.stringify(historyList)); + } catch (e) { + // eslint-disable-line no-empty + } + } + } + function getTooltip() { return quill.container.getElementsByClassName("ql-tooltip")[0]; } @@ -123,7 +148,10 @@ window.mathquill4quill = function(dependencies) { mqField.latex(cachedLatex); } - saveButton.addEventListener("click", () => removeCacheItem(cacheKey)); + saveButton.addEventListener("click", () => { + addItemToHistoryList(cacheKey); + removeCacheItem(cacheKey); + }); return mqField; } @@ -232,14 +260,98 @@ window.mathquill4quill = function(dependencies) { }; } + function newHistoryList() { + const history = historyList || []; + let historyDiv = null; + + function applyHistoryButtonStyles(button) { + button.setAttribute("class", "mathquill4quill-history-button"); + } + + function applyHistoryContainerStyles(container) { + container.setAttribute("class", "mathquill4quill-history-container"); + } + + function createHistoryButton(latex, mqField) { + const button = document.createElement("button"); + button.setAttribute("type", "button"); + + katex.render(latex, button, { + throwOnError: false + }); + button.onclick = () => { + mqField.write(latex); + mqField.focus(); + }; + + return button; + } + + return { + render(mqField) { + fixToolTipHeight(); + + if (historyDiv != null || !displayHistory || history.length === 0) { + return; + } + + const tooltip = getTooltip(); + + historyDiv = document.createElement("div"); + let container = document.createElement("div"); + applyHistoryContainerStyles(container); + let header = document.createElement("p"); + header.innerHTML = "Past formulas (max " + historySize + ")"; + historyDiv.appendChild(header); + + history.forEach(element => { + const button = createHistoryButton(element, mqField); + applyHistoryButtonStyles(button); + container.appendChild(button); + }); + historyDiv.appendChild(container); + tooltip.appendChild(historyDiv); + }, + destroy() { + if (historyDiv == null) { + return; + } + + historyDiv.remove(); + historyDiv = null; + } + }; + } + + // If tooltip hangs below Quill div, Quill will position tooltip in bad place if function is clicked twice + // This addresses the position issue + function fixToolTipHeight() { + const tooltip = getTooltip(); + + if ( + tooltip.getBoundingClientRect().top - + quill.container.getBoundingClientRect().top < + 0 + ) { + tooltip.style.top = "0px"; + } + } + if (!areAllDependenciesMet()) { return; } const tooltip = getTooltip(); + const historyCacheKey = + options.historyCacheKey || "__mathquill4quill_historylist_cache__"; + let historyList = fetchHistoryList(historyCacheKey); + const historySize = options.historySize || 10; + const displayHistory = options.displayHistory || false; + const mqInput = newMathquillInput(); const operatorButtons = newOperatorButtons(); + const historyListButtons = newHistoryList(); const observer = new MutationObserver(() => { const isFormulaTooltipActive = @@ -250,9 +362,11 @@ window.mathquill4quill = function(dependencies) { if (isFormulaTooltipActive) { const mqField = mqInput.render(); operatorButtons.render(mqField); + historyListButtons.render(mqField); } else { mqInput.destroy(); operatorButtons.destroy(); + historyListButtons.destroy(); } });