diff --git a/packages/mindplot/src/components/LocalStorageManager.ts b/packages/mindplot/src/components/LocalStorageManager.ts index 67087661..84d2e47f 100644 --- a/packages/mindplot/src/components/LocalStorageManager.ts +++ b/packages/mindplot/src/components/LocalStorageManager.ts @@ -30,7 +30,8 @@ class LocalStorageManager extends PersistenceManager { this.forceLoad = forceLoad; } - saveMapXml(mapId: string, mapXml: string) { + saveMapXml(mapId: string, mapDoc: Document, pref = null, events = null): void { + const mapXml = new XMLSerializer().serializeToString(mapDoc); localStorage.setItem(`${mapId}-xml`, mapXml); } diff --git a/packages/mindplot/src/components/PersistenceManager.ts b/packages/mindplot/src/components/PersistenceManager.ts index 6424cf15..d953580c 100644 --- a/packages/mindplot/src/components/PersistenceManager.ts +++ b/packages/mindplot/src/components/PersistenceManager.ts @@ -24,7 +24,7 @@ abstract class PersistenceManager { // eslint-disable-next-line no-use-before-define static _instance: PersistenceManager; - save(mindmap: Mindmap, editorProperties, saveHistory: boolean, events, sync: boolean) { + save(mindmap: Mindmap, editorProperties, saveHistory: boolean, events?) { $assert(mindmap, 'mindmap can not be null'); $assert(editorProperties, 'editorProperties can not be null'); @@ -33,11 +33,9 @@ abstract class PersistenceManager { const serializer = XMLSerializerFactory.createInstanceFromMindmap(mindmap); const domMap = serializer.toXML(mindmap); - const mapXml = new XMLSerializer().serializeToString(domMap); - const pref = JSON.stringify(editorProperties); try { - this.saveMapXml(mapId, mapXml, pref, saveHistory, events, sync); + this.saveMapXml(mapId, domMap, pref, saveHistory, events); } catch (e) { console.error(e); events.onError(e); @@ -54,7 +52,7 @@ abstract class PersistenceManager { abstract loadMapDom(mapId: string): Document; - abstract saveMapXml(mapId: string, mapXml, pref, saveHistory, events, sync); + abstract saveMapXml(mapId: string, mapXml: Document, pref?, saveHistory?: boolean, events?); abstract unlockMap(mindmap: Mindmap): void; diff --git a/packages/mindplot/src/components/RestPersistenceManager.ts b/packages/mindplot/src/components/RestPersistenceManager.ts index 463f0a51..b68410d4 100644 --- a/packages/mindplot/src/components/RestPersistenceManager.ts +++ b/packages/mindplot/src/components/RestPersistenceManager.ts @@ -51,10 +51,10 @@ class RESTPersistenceManager extends PersistenceManager { this.session = options.session; } - saveMapXml(mapId: string, mapXml: Document, pref: string, saveHistory: boolean, events, sync: boolean): void { + saveMapXml(mapId: string, mapXml: Document, pref: string, saveHistory: boolean, events): void { const data = { id: mapId, - xml: mapXml, + xml: new XMLSerializer().serializeToString(mapXml), properties: pref, }; @@ -71,73 +71,77 @@ class RESTPersistenceManager extends PersistenceManager { }, 10000); const persistence = this; - $.ajax({ - type: 'put', - url: `${this.documentUrl.replace('{id}', mapId)}?${query}`, - dataType: 'json', - data: JSON.stringify(data), - contentType: 'application/json; charset=utf-8', - async: !sync, - - success(successData) { - persistence.timestamp = successData; + fetch( + `${this.documentUrl.replace('{id}', mapId)}?${query}`, + { + method: 'PUT', + body: JSON.stringify(data), + headers: { 'Content-Type': 'application/json; charset=utf-8', Accept: 'application/json' }, + keepalive: true, + }, + ).then(async (response: Response) => { + if (response.ok) { + persistence.timestamp = await response.text(); events.onSuccess(); - }, - complete() { - // Clear event timeout ... - if (persistence.clearTimeout) { - clearTimeout(persistence.clearTimeout); - } - persistence.onSave = false; - }, - error(xhr) { - const { responseText } = xhr; - let userMsg = { severity: 'SEVERE', message: $msg('SAVE_COULD_NOT_BE_COMPLETED') }; - - const contentType = xhr.getResponseHeader('Content-Type'); - if (contentType != null && contentType.indexOf('application/json') !== -1) { - let serverMsg = null; - try { - serverMsg = $.parseJSON(responseText); - serverMsg = serverMsg.globalSeverity ? serverMsg : null; - } catch (e) { - // Message could not be decoded ... - } - userMsg = persistence._buildError(serverMsg); - } else if (this.status === 405) { + } else { + console.log(`Saving error: ${response.status}`); + let userMsg; + if (response.status === 405) { userMsg = { severity: 'SEVERE', message: $msg('SESSION_EXPIRED') }; + } else { + const responseText = await response.text(); + const contentType = response.headers['Content-Type']; + if (contentType != null && contentType.indexOf('application/json') !== -1) { + let serverMsg = null; + try { + serverMsg = JSON.parse(responseText); + serverMsg = serverMsg.globalSeverity ? serverMsg : null; + } catch (e) { + // Message could not be decoded ... + } + userMsg = persistence._buildError(serverMsg); + } } events.onError(userMsg); - persistence.onSave = false; - }, + } + + // Clear event timeout ... + if (persistence.clearTimeout) { + clearTimeout(persistence.clearTimeout); + } + persistence.onSave = false; + }).catch(() => { + const userMsg = { severity: 'SEVERE', message: $msg('SAVE_COULD_NOT_BE_COMPLETED') }; + events.onError(userMsg); + + // Clear event timeout ... + if (persistence.clearTimeout) { + clearTimeout(persistence.clearTimeout); + } + persistence.onSave = false; }); } } discardChanges(mapId: string) { - $.ajax({ - url: this.revertUrl.replace('{id}', mapId), - async: false, - method: 'post', - headers: { 'Content-Type': 'application/json; charset=utf-8', Accept: 'application/json' }, - error(xhr, ajaxOptions, thrownError) { - console.error(`Request error => status:${xhr.status} ,thrownError: ${thrownError}`); - }, - }); + fetch(this.revertUrl.replace('{id}', mapId), + { + method: 'POST', + headers: { 'Content-Type': 'application/json; charset=utf-8', Accept: 'application/json' }, + keepalive: true, + }); } unlockMap(mindmap: Mindmap) { const mapId = mindmap.getId(); - $.ajax({ - url: this.lockUrl.replace('{id}', mapId), - async: false, - method: 'put', - headers: { 'Content-Type': 'text/plain' }, - data: 'false', - error(xhr, ajaxOptions, thrownError) { - console.error(`Request error => status:${xhr.status} ,thrownError: ${thrownError}`); + fetch( + this.lockUrl.replace('{id}', mapId), + { + method: 'POST', + headers: { 'Content-Type': 'text/plain' }, + body: 'false', }, - }); + ); } private _buildError(jsonSeverResponse) { diff --git a/packages/mindplot/src/components/widget/IMenu.ts b/packages/mindplot/src/components/widget/IMenu.ts index 1a4fbac8..d5941584 100644 --- a/packages/mindplot/src/components/widget/IMenu.ts +++ b/packages/mindplot/src/components/widget/IMenu.ts @@ -73,7 +73,7 @@ class IMenu { persistenceManager.unlockMap(mindmap); } - save(saveElem: JQuery, designer: Designer, saveHistory: boolean, sync?: boolean) { + save(saveElem: JQuery, designer: Designer, saveHistory: boolean) { // Load map content ... const mindmap = designer.getMindmap(); const mindmapProp = designer.getMindmapProperties(); @@ -106,7 +106,7 @@ class IMenu { } } }, - }, sync); + }); } isSaveRequired(): boolean { diff --git a/packages/mindplot/src/components/widget/Menu.ts b/packages/mindplot/src/components/widget/Menu.ts index 3785a4cf..ff320609 100644 --- a/packages/mindplot/src/components/widget/Menu.ts +++ b/packages/mindplot/src/components/widget/Menu.ts @@ -297,9 +297,9 @@ class Menu extends IMenu { Menu._registerTooltip('save', $msg('SAVE'), 'meta+S'); if (!readOnly) { - $(window).bind('beforeunload', () => { + window.addEventListener('beforeunload', () => { if (this.isSaveRequired()) { - this.save(saveElem, designer, false, true); + this.save(saveElem, designer, false); } this.unlockMap(designer); }); @@ -310,7 +310,7 @@ class Menu extends IMenu { if (this.isSaveRequired()) { this.save(saveElem, designer, false); } - }, 30000, + }, 10000, ); } } diff --git a/yarn.lock b/yarn.lock index f31bcad6..60ca492b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5381,6 +5381,14 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" +create-react-context@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c" + integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw== + dependencies: + gud "^1.0.0" + warning "^4.0.3" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -7682,6 +7690,11 @@ growl@1.10.5: resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== +gud@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" + integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== + gzip-size@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" @@ -9911,7 +9924,7 @@ loglevel@^1.6.8: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114" integrity sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA== -loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -11637,6 +11650,11 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +promise-polyfill@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.1.0.tgz#30059da54d1358ce905ac581f287e184aedf995d" + integrity sha512-OzSf6gcCUQ01byV4BgwyUCswlaQQ6gzXc23aLQWhicvfX9kfsUiUhgt3CCQej8jDnl8/PhGF31JdHX2/MzF3WA== + promise-retry@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" @@ -11660,7 +11678,7 @@ promzard@^0.3.0: dependencies: read "1" -prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.0.0, prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.7.2: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -11884,6 +11902,16 @@ react-dom@^17.0.0: object-assign "^4.1.1" scheduler "^0.20.2" +react-form-validator-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/react-form-validator-core/-/react-form-validator-core-1.1.1.tgz#d084b94b9ef66bed3847fa8851b45cc2f8960a5c" + integrity sha512-5SG9pKrRptrhrt/dZg0bL28VvyGeuXftfhx6qwJLNdUqs2GgEnrV07BBtGpWyoBKXmO+fplD+O70DbI03CMqUQ== + dependencies: + create-react-context "^0.3.0" + promise-polyfill "8.1.0" + prop-types "^15.0.0" + react-lifecycles-compat "^3.0.2" + react-ga@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-3.3.0.tgz#c91f407198adcb3b49e2bc5c12b3fe460039b3ca" @@ -11925,6 +11953,19 @@ react-is@^17.0.1, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-lifecycles-compat@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-material-ui-form-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/react-material-ui-form-validator/-/react-material-ui-form-validator-3.0.0.tgz#9cc732147fab0062535d41a8b158537d6794e684" + integrity sha512-WoQvsGCV6cxxGlTvoKOZoLvWtg5KWMRVD9EFfMfJBYYUAZBOR9yXg1OSlu/MgOP7sPiiIUAwPLYVWIds7oLXKQ== + dependencies: + prop-types "^15.0.0" + react-form-validator-core "1.1.1" + react-query@^3.6.0: version "3.34.12" resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.34.12.tgz#dcaaf7b629f0868aae8afef9fb7692f6ea7643bf" @@ -14316,6 +14357,13 @@ walker@^1.0.7: dependencies: makeerror "1.0.12" +warning@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + watchpack@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25"