From 65c890a8036140ec65edbdedacc08a27fe2b93e5 Mon Sep 17 00:00:00 2001 From: Taras Semenenko Date: Thu, 25 May 2017 16:53:44 +0300 Subject: [PATCH 1/2] Add nprogress instead of spin --- pootle/static/css/editor.css | 14 ++++++++++++++ pootle/static/js/editor/app.js | 25 +++++++++++++++++-------- pootle/static/js/package.json | 1 + pootle/templates/editor/_editor.html | 2 -- pootle/templates/editor/main.html | 3 +++ 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/pootle/static/css/editor.css b/pootle/static/css/editor.css index 8acb3c3c4c8..be6dbbbf5e8 100644 --- a/pootle/static/css/editor.css +++ b/pootle/static/css/editor.css @@ -158,6 +158,20 @@ textarea.translation, margin: 180px auto; } +.editor-progress-container +{ + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: 99; +} + +.editor-progress +{ + height: 5px; +} + .editor-overlay { background-color: rgba(255, 255, 255, 0.8); diff --git a/pootle/static/js/editor/app.js b/pootle/static/js/editor/app.js index 69996a9885c..0a1b29b5e76 100644 --- a/pootle/static/js/editor/app.js +++ b/pootle/static/js/editor/app.js @@ -26,6 +26,8 @@ import cx from 'classnames'; import Levenshtein from 'levenshtein'; import mousetrap from 'mousetrap'; import assign from 'object-assign'; +import NProgress from 'nprogress'; +import 'nprogress/nprogress.css'; import UnitAPI from 'api/UnitAPI'; import cookie from 'utils/cookie'; @@ -51,6 +53,10 @@ import ReactEditor from './index'; // be the actual entry point, entirely superseding the `app` module. PTL.reactEditor = ReactEditor; +NProgress.configure({ + parent: '#js-editor-progress', + showSpinner: false, +}); const CTX_STEP = 1; @@ -135,7 +141,6 @@ PTL.editor = { /* Cached elements */ this.backToBrowserEl = q('.js-back-to-browser'); - this.$editorActivity = $('#js-editor-act'); this.$editorBody = $('.js-editor-body'); this.editorTableEl = q('.js-editor-table'); this.$filterStatus = $('#js-filter-status'); @@ -166,8 +171,8 @@ PTL.editor = { this.isUnitDirty = false; - this.isLoading = true; this.showActivity(); + this.isLoading = true; this.fetchingOffsets = []; @@ -405,9 +410,7 @@ PTL.editor = { return; } - this.delayedActivityTimer = setTimeout(() => { - this.showActivity(); - }, 3000); + this.showActivity(); }); $(document).ajaxStop(() => { clearTimeout(this.delayedActivityTimer); @@ -642,7 +645,6 @@ PTL.editor = { this.isUnitDirty = false; this.keepState = false; this.isLoading = false; - this.hideActivity(); }, /* Things to do when no results are returned */ @@ -1028,11 +1030,18 @@ PTL.editor = { showActivity() { this.hideMsg(); - this.$editorActivity.spin().fadeIn(300); + if (this.isLoading) { + return; + } + clearTimeout(this.delayedActivityTimer); + this.delayedActivityTimer = setTimeout(() => NProgress.start(), 2000); }, hideActivity() { - this.$editorActivity.spin(false).fadeOut(300); + if (!this.isLoading) { + clearTimeout(this.delayedActivityTimer); + NProgress.done(); + } }, /* Displays an informative message */ diff --git a/pootle/static/js/package.json b/pootle/static/js/package.json index f88b5283615..104c50e3b46 100644 --- a/pootle/static/js/package.json +++ b/pootle/static/js/package.json @@ -42,6 +42,7 @@ "diff-match-patch": "^1.0.0", "imports-loader": "^0.6.3", "mousetrap": "^1.5.3", + "nprogress": "^0.2.0", "object-assign": "^2.0.0", "react": "^0.14.6", "react-addons-pure-render-mixin": "^0.14.6", diff --git a/pootle/templates/editor/_editor.html b/pootle/templates/editor/_editor.html index e1b6ec83152..22c4e089cf9 100644 --- a/pootle/templates/editor/_editor.html +++ b/pootle/templates/editor/_editor.html @@ -1,8 +1,6 @@ {% load locale %}
-
- diff --git a/pootle/templates/editor/main.html b/pootle/templates/editor/main.html index 0675de0b23d..01a8f5a932c 100644 --- a/pootle/templates/editor/main.html +++ b/pootle/templates/editor/main.html @@ -20,6 +20,9 @@ {% block pre_content %} {% include 'editor/_toolbar.html' %} +
+
+
{% endblock %} {% block content %} From f17364b49129fce97eb57862c435c5b0ed2564f6 Mon Sep 17 00:00:00 2001 From: Taras Semenenko Date: Fri, 26 May 2017 15:16:54 +0300 Subject: [PATCH 2/2] Add unitAPI wrapper to the editor methods --- pootle/static/js/editor/app.js | 159 ++++++++++++------------- pootle/static/js/shared/api/UnitAPI.js | 22 ++-- 2 files changed, 89 insertions(+), 92 deletions(-) diff --git a/pootle/static/js/editor/app.js b/pootle/static/js/editor/app.js index 0a1b29b5e76..b8e9becc114 100644 --- a/pootle/static/js/editor/app.js +++ b/pootle/static/js/editor/app.js @@ -128,14 +128,15 @@ PTL.editor = { this.setActiveUnit = debounce((body, newUnit) => { this.fetchUnits().always(() => { - UnitAPI.fetchUnit(newUnit.id, body) - .then( - (data) => { - this.setEditUnit(data); - this.renderUnit(); - }, - this.error - ); + this.unitAPI({ + method: 'fetchUnit', + params: { uId: newUnit.id, body }, + success: (data) => { + this.setEditUnit(data); + this.renderUnit(); + }, + error: this.error, + }); }); }, 250); @@ -403,22 +404,6 @@ PTL.editor = { this.unitIndex(e); }); - /* XHR activity indicator */ - $(document).ajaxStart(() => { - clearTimeout(this.delayedActivityTimer); - if (this.isLoading) { - return; - } - - this.showActivity(); - }); - $(document).ajaxStop(() => { - clearTimeout(this.delayedActivityTimer); - if (!this.isLoading) { - this.hideActivity(); - } - }); - /* Load MT providers */ this.settings.mt.forEach((provider) => { require.ensure([], () => { @@ -665,6 +650,11 @@ PTL.editor = { return true; }, + unitAPI({ method, params, success, error, always }) { + this.showActivity(); + return UnitAPI[method](params).then(success, error).always(always, () => this.hideActivity()); + }, + /* * Text utils @@ -1491,11 +1481,13 @@ PTL.editor = { if (previousUids.length > 0) { reqData.previous_uids = previousUids; } - return UnitAPI.fetchUnits(reqData) - .then( - (data) => this.storeUnitData(data, { isInitial: initial }), - this.error - ).always(() => this.markAsFetched(offsetToFetch)); + return this.unitAPI({ + method: 'fetchUnits', + params: { body: reqData }, + success: (data) => this.storeUnitData(data, { isInitial: initial }), + error: this.error, + always: () => this.markAsFetched(offsetToFetch), + }); } /* eslint-disable new-cap */ return $.Deferred((deferred) => deferred.reject(false)); @@ -1636,11 +1628,12 @@ PTL.editor = { }; assign(body, suggData); } - UnitAPI.addTranslation(this.units.getCurrent().id, body) - .then( - (data) => this.processSubmission(data), - this.error - ); + this.unitAPI({ + method: 'addTranslation', + params: { uId: this.units.getCurrent().id, body }, + success: (data) => this.processSubmission(data), + error: this.error, + }); }, processSubmission(data) { @@ -1675,11 +1668,12 @@ PTL.editor = { const body = assign({}, this.getValueStateData(ReactEditor.stateValues), this.getReqData(), captchaCallbacks); - UnitAPI.addSuggestion(this.units.getCurrent().id, body) - .then( - (data) => this.processSuggestion(data), - this.error - ); + this.unitAPI({ + method: 'addSuggestion', + params: { uId: this.units.getCurrent().id, body }, + success: (data) => this.processSuggestion(data), + error: this.error, + }); }, processSuggestion() { @@ -1960,14 +1954,15 @@ PTL.editor = { /* Gets more context units */ moreContext(amount = CTX_STEP) { - return ( - UnitAPI.getContext(this.units.getCurrent().id, - { gap: this.ctxGap, qty: amount }) - .then( - (data) => this.handleContextSuccess(data), - this.error - ) - ); + return this.unitAPI({ + method: 'getContext', + params: { + uId: this.units.getCurrent().id, + body: { gap: this.ctxGap, qty: amount }, + }, + success: (data) => this.handleContextSuccess(data), + error: this.error, + }); }, /* Shrinks context lines */ @@ -2056,11 +2051,12 @@ PTL.editor = { e.preventDefault(); this.updateCommentDefaultProperties(); - UnitAPI.addComment(this.units.getCurrent().id, $(e.target).serializeObject()) - .then( - (data) => this.processAddComment(data), - this.error - ); + this.unitAPI({ + method: 'addComment', + params: { uId: this.units.getCurrent().id, body: $(e.target).serializeObject() }, + success: (data) => this.processAddComment(data), + error: this.error, + }); }, processAddComment(data) { @@ -2081,11 +2077,12 @@ PTL.editor = { removeComment(e) { e.preventDefault(); - UnitAPI.removeComment(this.units.getCurrent().id) - .then( - () => $('.js-comment-first').fadeOut(200), - this.error - ); + this.unitAPI({ + method: 'removeComment', + params: { uId: this.units.getCurrent().id }, + success: () => $('.js-comment-first').fadeOut(200), + error: this.error, + }); }, @@ -2101,15 +2098,12 @@ PTL.editor = { return; } - const $node = $('.translate-container'); - $node.spin(); - - UnitAPI.getTimeline(this.units.getCurrent().id) - .then( - (data) => this.renderTimeline(data), - this.error - ) - .always(() => $node.spin(false)); + this.unitAPI({ + method: 'getTimeline', + params: { uId: this.units.getCurrent().id }, + success: (data) => this.renderTimeline(data), + error: this.error, + }); }, renderTimeline(data) { @@ -2277,11 +2271,12 @@ PTL.editor = { }, rejectSuggestion(suggId, { requestData = {} } = {}) { - UnitAPI.rejectSuggestion(this.units.getCurrent().id, suggId, requestData) - .then( - (data) => this.processRejectSuggestion(data, suggId), - this.error - ); + this.unitAPI({ + method: 'rejectSuggestion', + params: { uId: this.units.getCurrent().id, suggId, body: requestData }, + success: (data) => this.processRejectSuggestion(data, suggId), + error: this.error, + }); }, processRejectSuggestion(data, suggId) { @@ -2310,11 +2305,12 @@ PTL.editor = { }, acceptSuggestion(suggId, { requestData = {}, skipToNext = false } = {}) { - UnitAPI.acceptSuggestion(this.units.getCurrent().id, suggId, requestData) - .then( - (data) => this.processAcceptSuggestion(data, suggId, skipToNext), - this.error - ); + this.unitAPI({ + method: 'acceptSuggestion', + params: { uId: this.units.getCurrent().id, suggId, body: requestData }, + success: (data) => this.processAcceptSuggestion(data, suggId, skipToNext), + error: this.error, + }); }, processAcceptSuggestion(data, suggId, skipToNext) { @@ -2353,11 +2349,12 @@ PTL.editor = { const isFalsePositive = $check.hasClass('false-positive'); const opts = isFalsePositive ? null : { mute: 1 }; - UnitAPI.toggleCheck(this.units.getCurrent().id, checkId, opts) - .then( - () => this.processToggleCheck(checkId, isFalsePositive), - this.error - ); + this.unitAPI({ + method: 'toggleCheck', + params: { uId: this.units.getCurrent().id, checkId, body: opts }, + success: () => this.processToggleCheck(checkId, isFalsePositive), + error: this.error, + }); }, processToggleCheck(checkId, isFalsePositive) { diff --git a/pootle/static/js/shared/api/UnitAPI.js b/pootle/static/js/shared/api/UnitAPI.js index 0923efb20f6..c35c786f6da 100644 --- a/pootle/static/js/shared/api/UnitAPI.js +++ b/pootle/static/js/shared/api/UnitAPI.js @@ -14,14 +14,14 @@ const UnitAPI = { apiRoot: PTL.unitApiRoot, - fetchUnits(body) { + fetchUnits({ body }) { return fetch({ body, url: this.apiRoot, }); }, - fetchUnit(uId, body = {}) { + fetchUnit({ uId, body = {} }) { return fetch({ body, queue: 'unitWidget', @@ -29,7 +29,7 @@ const UnitAPI = { }); }, - addTranslation(uId, body) { + addTranslation({ uId, body }) { return fetch({ body, method: 'POST', @@ -37,20 +37,20 @@ const UnitAPI = { }); }, - getContext(uId, body) { + getContext({ uId, body }) { return fetch({ body, url: `${this.apiRoot}${uId}/context/`, }); }, - getTimeline(uId) { + getTimeline({ uId }) { return fetch({ url: `${this.apiRoot}${uId}/timeline/`, }); }, - addComment(uId, body) { + addComment({ uId, body }) { return fetch({ body, method: 'POST', @@ -58,7 +58,7 @@ const UnitAPI = { }); }, - removeComment(uId) { + removeComment({ uId }) { return fetch({ method: 'DELETE', url: `${this.apiRoot}${uId}/comment/`, @@ -67,7 +67,7 @@ const UnitAPI = { /* Unit suggestions */ - addSuggestion(uId, body) { + addSuggestion({ uId, body }) { return fetch({ body, method: 'POST', @@ -75,7 +75,7 @@ const UnitAPI = { }); }, - acceptSuggestion(uId, suggId, body) { + acceptSuggestion({ uId, suggId, body }) { return fetch({ body, method: 'POST', @@ -83,7 +83,7 @@ const UnitAPI = { }); }, - rejectSuggestion(uId, suggId, body) { + rejectSuggestion({ uId, suggId, body }) { return fetch({ body, method: 'DELETE', @@ -93,7 +93,7 @@ const UnitAPI = { /* Quality checks */ - toggleCheck(uId, checkId, body = {}) { + toggleCheck({ uId, checkId, body = {} }) { return fetch({ body, method: 'POST',