From 726f829541df251c30476055bdd3c64316e36f44 Mon Sep 17 00:00:00 2001 From: jos Date: Sun, 30 Jun 2019 20:08:52 +0200 Subject: [PATCH] Show "busy" message when working on a heavy action --- src/css/jsoneditor.css | 27 ++++ src/js/{stringifyPartial.js => jsonUtils.js} | 0 src/js/previewmode.js | 119 +++++++++++++----- src/js/showTransformModal.js | 2 +- ...ngifyPartial.test.js => jsonUtils.test.js} | 4 +- 5 files changed, 116 insertions(+), 36 deletions(-) rename src/js/{stringifyPartial.js => jsonUtils.js} (100%) rename test/{stringifyPartial.test.js => jsonUtils.test.js} (93%) diff --git a/src/css/jsoneditor.css b/src/css/jsoneditor.css index 6ad8e0d..8d065e4 100644 --- a/src/css/jsoneditor.css +++ b/src/css/jsoneditor.css @@ -284,6 +284,11 @@ div.jsoneditor pre.jsoneditor-preview { } +div.jsoneditor.busy pre.jsoneditor-preview { + background: #f5f5f5; + color: #808080; +} + div.jsoneditor code.jsoneditor-preview { background: none; } @@ -299,6 +304,28 @@ div.jsoneditor.jsoneditor-mode-preview pre.jsoneditor-preview { word-break: break-all; } +div.jsoneditor-busy { + position: absolute; + top: 15%; + left: 0; + box-sizing: border-box; + width: 100%; + text-align: center; + display: none; +} + +div.jsoneditor-busy span { + background-color: #FFFFAB; + border: 1px solid yellow; + border-radius: 3px; + padding: 5px 15px; + box-shadow: 0 0 5px rgba(0,0,0,0.4); +} + +div.jsoneditor.busy div.jsoneditor-busy { + display: inherit; +} + textarea.jsoneditor-text, .ace-jsoneditor { min-height: 150px; diff --git a/src/js/stringifyPartial.js b/src/js/jsonUtils.js similarity index 100% rename from src/js/stringifyPartial.js rename to src/js/jsonUtils.js diff --git a/src/js/previewmode.js b/src/js/previewmode.js index c3bd3c5..8b2dbad 100644 --- a/src/js/previewmode.js +++ b/src/js/previewmode.js @@ -12,6 +12,7 @@ var previewmode = {}; var DEFAULT_MODAL_ANCHOR = document.body; // TODO: this constant is defined multiple times var MAX_PREVIEW_CHARACTERS = 100000; // should be enough to fill the editor window +var SIZE_LARGE = 10 * 1024 * 1024; // 10 MB /** * Create a JSON document preview, suitable for processing of large documents @@ -84,6 +85,13 @@ previewmode.create = function (container, options) { this.content = document.createElement('div'); this.content.className = 'jsoneditor-outer'; + this.dom.busy = document.createElement('div') + this.dom.busy.className = 'jsoneditor-busy'; + this.dom.busyContent = document.createElement('span'); + this.dom.busyContent.innerHTML = 'busy...'; + this.dom.busy.appendChild(this.dom.busyContent); + this.content.appendChild(this.dom.busy); + this.dom.previewContent = document.createElement('pre'); this.dom.previewContent.className = 'jsoneditor-preview'; this.dom.previewText = document.createTextNode(''); @@ -104,14 +112,16 @@ previewmode.create = function (container, options) { buttonFormat.className = 'jsoneditor-format'; buttonFormat.title = 'Format JSON data, with proper indentation and line feeds (Ctrl+\\)'; this.menu.appendChild(buttonFormat); - buttonFormat.onclick = function () { - try { - me.format(); - me._onChange(); - } - catch (err) { - me._onError(err); - } + buttonFormat.onclick = function handleFormat() { + me.executeWithBusyMessage(function () { + try { + me.format(); + me._onChange(); + } + catch (err) { + me._onError(err); + } + }, 'formatting...'); }; // create compact button @@ -120,14 +130,17 @@ previewmode.create = function (container, options) { buttonCompact.className = 'jsoneditor-compact'; buttonCompact.title = 'Compact JSON data, remove all whitespaces (Ctrl+Shift+\\)'; this.menu.appendChild(buttonCompact); - buttonCompact.onclick = function () { - try { - me.compact(); - me._onChange(); - } - catch (err) { - me._onError(err); - } + buttonCompact.onclick = function handleCompact() { + me.executeWithBusyMessage(function () { + try { + + me.compact(); + me._onChange(); + } + catch (err) { + me._onError(err); + } + }, 'compacting...'); }; // create sort button @@ -161,13 +174,15 @@ previewmode.create = function (container, options) { buttonRepair.title = 'Repair JSON: fix quotes and escape characters, remove comments and JSONP notation, turn JavaScript objects into JSON.'; this.menu.appendChild(buttonRepair); buttonRepair.onclick = function () { - try { - me.repair(); - me._onChange(); - } - catch (err) { - me._onError(err); - } + me.executeWithBusyMessage(function () { + try { + me.repair(); + me._onChange(); + } + catch (err) { + me._onError(err); + } + }, 'repairing...'); }; // create mode box @@ -256,10 +271,8 @@ previewmode._onChange = function () { */ previewmode._showSortModal = function () { var me = this; - var container = this.options.modalAnchor || DEFAULT_MODAL_ANCHOR; - var json = this.get(); - function onSort (sortedBy) { + function onSort (json, sortedBy) { if (Array.isArray(json)) { var sortedJson = util.sort(json, sortedBy.path, sortedBy.direction); @@ -275,7 +288,16 @@ previewmode._showSortModal = function () { } } - showSortModal(container, json, onSort, me.sortedBy) + this.executeWithBusyMessage(function () { + var container = me.options.modalAnchor || DEFAULT_MODAL_ANCHOR; + var json = me.get(); + + showSortModal(container, json, function (sortedBy) { + me.executeWithBusyMessage(function () { + onSort(json, sortedBy); + }, 'stringifying...'); + }, me.sortedBy) + }, 'parsing...'); } /** @@ -284,12 +306,18 @@ previewmode._showSortModal = function () { */ previewmode._showTransformModal = function () { var me = this; - var anchor = this.options.modalAnchor || DEFAULT_MODAL_ANCHOR; - var json = this.get(); - showTransformModal(anchor, json, function (query) { - var updatedJson = jmespath.search(json, query); - me.set(updatedJson); - }) + + this.executeWithBusyMessage(function () { + var anchor = me.options.modalAnchor || DEFAULT_MODAL_ANCHOR; + var json = me.get(); + + showTransformModal(anchor, json, function (query) { + me.executeWithBusyMessage(function () { + var updatedJson = jmespath.search(json, query); + me.set(updatedJson); + }, 'transforming...') + }) + }, 'parsing...') } /** @@ -448,6 +476,31 @@ previewmode.updateText = function(jsonText) { this.onChangeDisabled = false; }; +/** + * Execute a heavy, blocking action. + * Before starting the action, show a message on screen like "parsing..." + * @param {function} fn + * @param {string} message + */ +previewmode.executeWithBusyMessage = function (fn, message) { + var size = this.getText().length; + + if (size > SIZE_LARGE) { + var me = this; + util.addClassName(me.frame, 'busy'); + me.dom.busyContent.innerText = message; + + setTimeout(function () { + fn(); + util.removeClassName(me.frame, 'busy'); + me.dom.busyContent.innerText = ''; + }, 100); + } + else { + fn(); + } +}; + /** * Validate current JSON object against the configured JSON schema * Throws an exception when no JSON schema is configured diff --git a/src/js/showTransformModal.js b/src/js/showTransformModal.js index 5e66eb5..1221089 100644 --- a/src/js/showTransformModal.js +++ b/src/js/showTransformModal.js @@ -2,7 +2,7 @@ var jmespath = require('jmespath'); var picoModal = require('picomodal'); var Selectr = require('./assets/selectr/selectr'); var translate = require('./i18n').translate; -var stringifyPartial = require('./stringifyPartial').stringifyPartial; +var stringifyPartial = require('./jsonUtils').stringifyPartial; var util = require('./util'); var debounce = util.debounce; diff --git a/test/stringifyPartial.test.js b/test/jsonUtils.test.js similarity index 93% rename from test/stringifyPartial.test.js rename to test/jsonUtils.test.js index 5a2a21f..259b163 100644 --- a/test/stringifyPartial.test.js +++ b/test/jsonUtils.test.js @@ -1,7 +1,7 @@ var assert = require('assert'); -var stringifyPartial = require('../src/js/stringifyPartial').stringifyPartial; +var stringifyPartial = require('../src/js/jsonUtils').stringifyPartial; -describe('stringifyPartial', function () { +describe('jsonUtils', function () { it('should stringify a small object', function () { var json = {