@operato/shell 10.29.37 → 10.29.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/coverage/lcov-report/index.html +47 -47
- package/coverage/lcov-report/test/fixtures/guarded-define.ts.html +1 -1
- package/coverage/lcov-report/test/fixtures/index.html +1 -1
- package/coverage/lcov-report/test/fixtures/no-registration.ts.html +1 -1
- package/coverage/lcov-report/test/fixtures/registers.ts.html +1 -1
- package/coverage/lcov-report/test/fixtures/unguarded-define.ts.html +1 -1
- package/coverage/lcov.info +1683 -966
- package/dist/src/actions/route.d.ts +1 -8
- package/dist/src/actions/route.js +9 -8
- package/dist/src/actions/route.js.map +1 -1
- package/dist/src/app/app.d.ts +3 -0
- package/dist/src/app/app.js +56 -34
- package/dist/src/app/app.js.map +1 -1
- package/dist/src/app/pages/page-view.d.ts +18 -6
- package/dist/src/app/pages/page-view.js +122 -7
- package/dist/src/app/pages/page-view.js.map +1 -1
- package/dist/src/drafts/draft-store.js +5 -3
- package/dist/src/drafts/draft-store.js.map +1 -1
- package/dist/src/drafts/unsaved-draft-controller.d.ts +9 -3
- package/dist/src/drafts/unsaved-draft-controller.js +77 -20
- package/dist/src/drafts/unsaved-draft-controller.js.map +1 -1
- package/dist/src/router.d.ts +2 -5
- package/dist/src/router.js +25 -22
- package/dist/src/router.js.map +1 -1
- package/dist/test/drafts.test.js +88 -4
- package/dist/test/drafts.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/test/drafts.test.ts +90 -4
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @param location - The path of the page to navigate to.
|
|
12
12
|
* @param replace - Optional. If true, replaces the current page in the browser's history.
|
|
13
13
|
*/
|
|
14
|
-
export declare const navigate: (location: string, replace?: boolean) =>
|
|
14
|
+
export declare const navigate: (location: string, replace?: boolean) => Promise<boolean>;
|
|
15
15
|
/**
|
|
16
16
|
* Navigate to a page with optional query parameters, and dispatch a Redux action to load the page.
|
|
17
17
|
*
|
|
@@ -25,13 +25,6 @@ export declare const navigateWithSilence: ({ pathname: path, search, params }: {
|
|
|
25
25
|
[key: string]: any;
|
|
26
26
|
};
|
|
27
27
|
}) => (dispatch: any) => void;
|
|
28
|
-
/**
|
|
29
|
-
* Load a page by dispatching a Redux action, and handle page navigation if necessary.
|
|
30
|
-
*
|
|
31
|
-
* @param page - The page to load.
|
|
32
|
-
* @param id - The associated resource ID.
|
|
33
|
-
* @param params - Additional parameters to pass to the page.
|
|
34
|
-
*/
|
|
35
28
|
export declare const loadPage: (page: string, id: string, params: {
|
|
36
29
|
[key: string]: any;
|
|
37
30
|
}) => (dispatch: any) => Promise<void>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getPathInfo } from '@operato/utils';
|
|
2
|
+
import { addressController, writeAddress } from '@operato/utils/address.js';
|
|
2
3
|
import { HOMEPAGE, UPDATE_PAGE } from '../actions/const.js';
|
|
3
4
|
import { store } from '../store.js';
|
|
4
5
|
/**
|
|
@@ -15,11 +16,7 @@ import { store } from '../store.js';
|
|
|
15
16
|
* @param replace - Optional. If true, replaces the current page in the browser's history.
|
|
16
17
|
*/
|
|
17
18
|
export const navigate = (location, replace) => {
|
|
18
|
-
|
|
19
|
-
history.replaceState(history.state, '', location);
|
|
20
|
-
else
|
|
21
|
-
history.pushState({}, '', location);
|
|
22
|
-
window.dispatchEvent(new Event('popstate'));
|
|
19
|
+
return writeAddress(new URL(location, document.baseURI), { replace });
|
|
23
20
|
};
|
|
24
21
|
/**
|
|
25
22
|
* Navigate to a page with optional query parameters, and dispatch a Redux action to load the page.
|
|
@@ -35,9 +32,9 @@ export const navigateWithSilence = ({ pathname: path, search, params }) => (disp
|
|
|
35
32
|
const page = matchReturn[1] || HOMEPAGE;
|
|
36
33
|
const id = matchReturn[2];
|
|
37
34
|
if (!params) {
|
|
38
|
-
params = {
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
params = addressController().params({
|
|
36
|
+
...addressController().entry,
|
|
37
|
+
url: new URL(path + (search || ''), location.origin)
|
|
41
38
|
});
|
|
42
39
|
}
|
|
43
40
|
// Any other info you might want to extract from the path (like page type),
|
|
@@ -75,8 +72,12 @@ const _preLoadPage = async (page) => {
|
|
|
75
72
|
* @param id - The associated resource ID.
|
|
76
73
|
* @param params - Additional parameters to pass to the page.
|
|
77
74
|
*/
|
|
75
|
+
let loadSequence = 0;
|
|
78
76
|
export const loadPage = (page, id, params) => async (dispatch) => {
|
|
77
|
+
const sequence = ++loadSequence;
|
|
79
78
|
var newPage = await _preLoadPage(page);
|
|
79
|
+
if (sequence !== loadSequence)
|
|
80
|
+
return;
|
|
80
81
|
if (page !== newPage && newPage.indexOf('/') == 0) {
|
|
81
82
|
dispatch(navigateWithSilence({
|
|
82
83
|
pathname: id ? `${newPage}/${id}` : newPage,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../../src/actions/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../../src/actions/route.ts"],"names":[],"mappings":"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","sourcesContent":["import { getPathInfo } from '@operato/utils'\nimport { addressController, writeAddress } from '@operato/utils/address.js'\n\nimport { HOMEPAGE, UPDATE_PAGE } from '../actions/const.js'\nimport { store } from '../store.js'\n\n/**\n * Navigate to a page using one of two methods:\n * 1. Using a page link: <a href='page'>goto page</a> (equivalent to route(page))\n * 2. Using the navigate('page') function.\n *\n * 페이지를 이동하는 방법으로는 다음 두가지가 있다.\n * 1. page link를 사용하는 방법 <a href='page'>goto page</a>\n * 이 방법은 route(page)와 동일하다.\n * 2. navigate('page')를 사용하는 방법\n *\n * @param location - The path of the page to navigate to.\n * @param replace - Optional. If true, replaces the current page in the browser's history.\n */\nexport const navigate = (location: string, replace?: boolean) => {\n return writeAddress(new URL(location, document.baseURI), { replace })\n}\n\n/**\n * Navigate to a page with optional query parameters, and dispatch a Redux action to load the page.\n *\n * @param pathInfo - Object containing pathname, search, and optional params.\n * @param dispatch - Redux dispatch function.\n */\nexport const navigateWithSilence =\n ({ pathname: path, search, params }: { pathname: string; search?: string; params?: { [key: string]: any } }) =>\n (dispatch: any) => {\n const { path: pathname } = getPathInfo(path)\n\n const reg = /\\/([^\\/]+)\\/*([^\\/]*)/\n const decodePath = decodeURIComponent(pathname!)\n const matchReturn = decodePath.match(reg) || []\n const page = matchReturn[1] || HOMEPAGE\n const id = matchReturn[2]\n\n if (!params) {\n params = addressController().params({\n ...addressController().entry,\n url: new URL(path + (search || ''), location.origin)\n })\n }\n\n // Any other info you might want to extract from the path (like page type),\n // you can do here\n dispatch(loadPage(page, id, params))\n }\n\n/**\n * Preload a page by performing any necessary preprocessing before loading.\n *\n * @param page - The page to preload.\n * @returns - The new page path or routing result after preprocessing.\n */\nconst _preLoadPage = async (page: any) => {\n /*\n * _preLoadPage 에서는 page를 load하기 전처리를 수행한다.\n * 예를 들면, page dynamic import 또는 page re-routing\n */\n var state: any = store.getState()\n\n /* override 기능을 위해서 dependency 관계의 역순으로 route를 실행한다. */\n var modules = state.app.modules\n if (modules) {\n for (let i = modules.length - 1; i >= 0; i--) {\n let module = modules[i]\n let _page = module.route && (await module.route(page, module))\n if (_page) {\n return _page\n }\n }\n }\n}\n\n/**\n * Load a page by dispatching a Redux action, and handle page navigation if necessary.\n *\n * @param page - The page to load.\n * @param id - The associated resource ID.\n * @param params - Additional parameters to pass to the page.\n */\nlet loadSequence = 0\nexport const loadPage = (page: string, id: string, params: { [key: string]: any }) => async (dispatch: any) => {\n const sequence = ++loadSequence\n var newPage = await _preLoadPage(page)\n if (sequence !== loadSequence) return\n\n if (page !== newPage && newPage.indexOf('/') == 0) {\n dispatch(\n navigateWithSilence({\n pathname: id ? `${newPage}/${id}` : newPage,\n params\n })\n )\n return\n }\n\n dispatch({\n type: UPDATE_PAGE,\n page: newPage,\n resourceId: id,\n params\n })\n}\n"]}
|
package/dist/src/app/app.d.ts
CHANGED
|
@@ -32,6 +32,9 @@ export declare class ThingsApp extends LitElement {
|
|
|
32
32
|
private main;
|
|
33
33
|
render(): import("lit-html").TemplateResult<1>;
|
|
34
34
|
connectedCallback(): void;
|
|
35
|
+
private stopAddressGuard?;
|
|
36
|
+
private stopAddressRouter?;
|
|
37
|
+
private installAddressRouting;
|
|
35
38
|
disconnectedCallback(): void;
|
|
36
39
|
/** routeToPage 호출 직렬화 — 동시 실행으로 인한 페이지 중복 생성/다중 active 방지 */
|
|
37
40
|
private _routeQueue;
|
package/dist/src/app/app.js
CHANGED
|
@@ -5,11 +5,13 @@ import { customElement, property, query, state } from 'lit/decorators.js';
|
|
|
5
5
|
import { installRouter } from '../router.js';
|
|
6
6
|
import { ScrollbarStyles } from '@operato/styles';
|
|
7
7
|
import { setContextPathPrefix, getPathInfo } from '@operato/utils';
|
|
8
|
+
import { addressController } from '@operato/utils/address.js';
|
|
8
9
|
import { navigateWithSilence, UPDATE_ACTIVE_PAGE, UPDATE_CONTEXT_PATH, UPDATE_MODULES } from '../actions/index.js';
|
|
9
10
|
import { store } from '../store.js';
|
|
10
11
|
import { RouteController } from '../controllers/route-controller.js';
|
|
11
12
|
import { AppController } from '../controllers/app-controller.js';
|
|
12
13
|
import { AppStyle } from './app-style.js';
|
|
14
|
+
import { approveNativeDeparture } from './pages/page-view.js';
|
|
13
15
|
var MODULES_STATE;
|
|
14
16
|
(function (MODULES_STATE) {
|
|
15
17
|
MODULES_STATE[MODULES_STATE["NOT_INITIALIZED"] = 0] = "NOT_INITIALIZED";
|
|
@@ -58,8 +60,9 @@ let ThingsApp = class ThingsApp extends LitElement {
|
|
|
58
60
|
super.connectedCallback();
|
|
59
61
|
this.setBase();
|
|
60
62
|
if (ThingsApp_1.moduleInitialized != MODULES_STATE.NOT_INITIALIZED) {
|
|
61
|
-
/*
|
|
62
|
-
|
|
63
|
+
/* Reconnected shells subscribe to the current entry without manufacturing a traversal event. */
|
|
64
|
+
if (ThingsApp_1.moduleInitialized === MODULES_STATE.INITIALIZED)
|
|
65
|
+
this.installAddressRouting();
|
|
63
66
|
return;
|
|
64
67
|
}
|
|
65
68
|
ThingsApp_1.moduleInitialized = MODULES_STATE.INITIALIZING;
|
|
@@ -105,49 +108,68 @@ let ThingsApp = class ThingsApp extends LitElement {
|
|
|
105
108
|
type: UPDATE_MODULES,
|
|
106
109
|
modules
|
|
107
110
|
});
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
111
|
+
this.installAddressRouting();
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
installAddressRouting() {
|
|
115
|
+
this.stopAddressGuard?.();
|
|
116
|
+
this.stopAddressRouter?.();
|
|
117
|
+
let previousEntry;
|
|
118
|
+
this.stopAddressGuard = addressController().guard({
|
|
119
|
+
approve: change => this.activePage?.canDeactivate(change.signal) ?? true,
|
|
120
|
+
approveSync: () => approveNativeDeparture(this.activePage),
|
|
121
|
+
dirty: () => this.activePage?.addressDirty ?? false,
|
|
122
|
+
committed: () => this.activePage?.discardAddressEdits()
|
|
123
|
+
});
|
|
124
|
+
this.stopAddressRouter = installRouter(async (location, e) => {
|
|
125
|
+
var { pathname } = location;
|
|
126
|
+
var { contextPath } = getPathInfo(pathname);
|
|
127
|
+
if (ThingsApp_1.contextPath !== contextPath) {
|
|
128
|
+
store.dispatch({
|
|
129
|
+
type: UPDATE_CONTEXT_PATH,
|
|
130
|
+
contextPath
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
const currentEntry = addressController().entry;
|
|
134
|
+
// Registration changes the projection, not history. Project both entries with today's owner claims.
|
|
135
|
+
const pageAddress = JSON.stringify([pathname, addressController().params(currentEntry)]);
|
|
136
|
+
const previousAddress = previousEntry && JSON.stringify([previousEntry.url.pathname, addressController().params(previousEntry)]);
|
|
137
|
+
previousEntry = currentEntry;
|
|
138
|
+
if (pageAddress !== previousAddress) {
|
|
128
139
|
store.dispatch(navigateWithSilence(location));
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
140
|
+
}
|
|
141
|
+
ThingsApp_1.callbacks &&
|
|
142
|
+
ThingsApp_1.callbacks.forEach(callback => {
|
|
143
|
+
try {
|
|
144
|
+
callback.call(this, location, e);
|
|
145
|
+
}
|
|
146
|
+
catch (ex) {
|
|
147
|
+
console.error(ex);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
139
150
|
});
|
|
140
151
|
}
|
|
141
152
|
disconnectedCallback() {
|
|
142
153
|
super.disconnectedCallback();
|
|
154
|
+
this.stopAddressGuard?.();
|
|
155
|
+
this.stopAddressRouter?.();
|
|
143
156
|
}
|
|
144
157
|
routeToPage() {
|
|
145
|
-
this._routeQueue = this._routeQueue
|
|
158
|
+
this._routeQueue = this._routeQueue
|
|
159
|
+
.then(() => this._doRouteToPage())
|
|
160
|
+
.catch(e => {
|
|
146
161
|
console.error('[routeToPage]', e);
|
|
147
162
|
});
|
|
148
163
|
return this._routeQueue;
|
|
149
164
|
}
|
|
150
165
|
async _doRouteToPage() {
|
|
166
|
+
const target = { page: this.page, resourceId: this.resourceId, params: this.params, contextPath: this.contextPath };
|
|
167
|
+
const pages = await ThingsApp_1.pages;
|
|
168
|
+
if (target.page !== this.page ||
|
|
169
|
+
target.resourceId !== this.resourceId ||
|
|
170
|
+
target.params !== this.params ||
|
|
171
|
+
target.contextPath !== this.contextPath)
|
|
172
|
+
return;
|
|
151
173
|
const existing = this.renderRoot.querySelector(`main > .page[data-page=${this.page}]`);
|
|
152
174
|
// 이미 활성 상태인 같은 페이지면 active 토글 없이 lifecycle만 갱신
|
|
153
175
|
if (existing && existing.hasAttribute('active')) {
|
|
@@ -162,7 +184,7 @@ let ThingsApp = class ThingsApp extends LitElement {
|
|
|
162
184
|
this.activePage = existing;
|
|
163
185
|
if (!this.activePage) {
|
|
164
186
|
/* 해당 route에 연결된 page가 없는 경우에 main 섹션에 해당 element를 추가해준다. */
|
|
165
|
-
const tagname =
|
|
187
|
+
const tagname = pages[this.page];
|
|
166
188
|
if (tagname) {
|
|
167
189
|
const el = document.createElement(tagname);
|
|
168
190
|
el.setAttribute('class', 'page');
|
package/dist/src/app/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/app/app.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { installRouter } from '../router.js'\n\nimport { ScrollbarStyles } from '@operato/styles'\nimport { setContextPathPrefix, getPathInfo } from '@operato/utils'\n\nimport { navigateWithSilence, UPDATE_ACTIVE_PAGE, UPDATE_CONTEXT_PATH, UPDATE_MODULES } from '../actions/index.js'\nimport { store } from '../store.js'\nimport { RouteController } from '../controllers/route-controller.js'\nimport { AppController } from '../controllers/app-controller.js'\nimport { AppStyle } from './app-style.js'\nimport { PageView } from './pages/page-view.js'\n\nenum MODULES_STATE {\n NOT_INITIALIZED,\n INITIALIZING,\n INITIALIZED\n}\n\n@customElement('things-app')\nexport class ThingsApp extends LitElement {\n static styles = [ScrollbarStyles, AppStyle]\n\n static moduleInitialized: MODULES_STATE = MODULES_STATE.NOT_INITIALIZED\n static modules: Array<any> = []\n\n /* \n 모든 모듈의 routes 리스트가 수집될 때까지, routeToPage(..) 를 hold 시키기 위해서 ThingsApp.pages를 Promise로 정의한다. \n */\n static pagesResolver: (\n value:\n | {\n [path: string]: string\n }\n | PromiseLike<{\n [path: string]: string\n }>\n ) => void\n static pages: Promise<{ [path: string]: string }>\n\n static callbacks: Array<any> = []\n static contextPath?: string\n\n private _routeCtrl = new RouteController(this)\n private _appCtrl = new AppController(this)\n\n @property({ type: String, attribute: 'context-path-prefix' }) contextPathPrefix?: string = undefined\n\n @state() resourceId?: string\n @state() page?: string\n @state() params?: any\n @state() activePage?: PageView\n @state() context: any\n @state() contextPath?: string = ThingsApp.contextPath\n @state() modules: Array<any> = ThingsApp.modules\n\n @query('main') private main!: HTMLElement\n\n render() {\n var params = this.params || {}\n var fullbleed = (this.context && this.context.fullbleed) || (params.fullbleed && params.fullbleed == 'Y')\n var widebleed = (this.context && this.context.widebleed) || (params.widebleed && params.widebleed == 'Y')\n\n return html`\n <div>\n <ox-page-header-bar header></ox-page-header-bar>\n <main></main>\n <ox-page-footer-bar footer></ox-page-footer-bar>\n </div>\n\n <ox-header-bar ?fullbleed=${fullbleed}></ox-header-bar>\n\n <ox-nav-bar ?fullbleed=${fullbleed || widebleed}></ox-nav-bar>\n\n <ox-aside-bar ?fullbleed=${fullbleed || widebleed}></ox-aside-bar>\n\n <ox-footer-bar ?fullbleed=${fullbleed}></ox-footer-bar>\n\n <ox-snack-bar></ox-snack-bar>\n `\n }\n\n connectedCallback() {\n super.connectedCallback()\n\n this.setBase()\n\n if (ThingsApp.moduleInitialized != MODULES_STATE.NOT_INITIALIZED) {\n /* 첫번째 이후로 생성되는 경우에는 강제로 'popstate'를 발생시켜서, routing 기회를 준다 */\n window.dispatchEvent(new CustomEvent('popstate'))\n\n return\n }\n\n ThingsApp.moduleInitialized = MODULES_STATE.INITIALIZING\n\n /* 모듈 임포트를 동적으로 처리한다. */\n import(\n /* webpackPrefetch: true */\n /* webpackPreload: true */\n /* webpackChunkName: \"modules\" */\n '../module-importer.import'\n ).then(async module => {\n var modules: {\n name: string\n bootstrap: (m?: any /* self */) => void\n }[] = module.modules\n\n /* lifecycle - bootstrapping */\n for (let idx = 0; idx < modules.length; idx++) {\n const m = modules[idx]\n try {\n if (m.bootstrap) {\n await m.bootstrap(m)\n }\n } catch (e) {\n console.error(`[${idx} BOOTSTRAP ERROR -${m.name}]`, e)\n }\n }\n\n /* shouldUpdate를 활성화한다. */\n ThingsApp.moduleInitialized = MODULES_STATE.INITIALIZED\n\n /*\n modules를 ThingsApp.modules에 직접 할당 후 registerPages()를 먼저 호출하여\n ThingsApp.pages가 준비된 상태에서 첫 라우팅이 일어나도록 보장한다.\n (registerPages()는 updated()에서도 modules 변경 시 호출되지만, 그 시점은\n 첫 라우팅보다 나중이므로 첫 URL이 404로 빠지는 문제가 발생함)\n */\n ThingsApp.modules = modules\n ThingsApp.registerPages()\n\n /*\n contextPathPrefix 속성이 설정되어 있으면, installRouter 전에 적용한다.\n updated()에서도 setContextPathPrefix가 호출되지만, 그 시점은\n installRouter의 첫 콜백보다 나중이므로 첫 URL 파싱이 실패할 수 있다.\n */\n if (this.contextPathPrefix) {\n setContextPathPrefix(this.contextPathPrefix)\n }\n\n /* modules를 store에 dispatch 함으로써, update를 invoke 시킨다. */\n store.dispatch({\n type: UPDATE_MODULES,\n modules\n })\n\n var lastPathName: string = ''\n\n installRouter(async (location, e) => {\n var { pathname } = location\n var { contextPath } = getPathInfo(pathname)\n\n /* 페이지를 나가기 전에 옮기지 않도록 개입할 기회를 준다 */\n if (\n lastPathName &&\n lastPathName != pathname &&\n this.activePage &&\n this.activePage.canDeactivate &&\n !(await this.activePage.canDeactivate())\n ) {\n history.pushState({}, this.activePage.title, lastPathName)\n return\n }\n\n lastPathName = pathname\n\n if (ThingsApp.contextPath !== contextPath) {\n store.dispatch({\n type: UPDATE_CONTEXT_PATH,\n contextPath\n })\n }\n\n store.dispatch(navigateWithSilence(location) as any)\n\n ThingsApp.callbacks &&\n ThingsApp.callbacks.forEach(callback => {\n try {\n callback.call(this, location, e)\n } catch (ex) {\n console.error(ex)\n }\n })\n })\n })\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback()\n }\n\n /** routeToPage 호출 직렬화 — 동시 실행으로 인한 페이지 중복 생성/다중 active 방지 */\n private _routeQueue: Promise<void> = Promise.resolve()\n\n routeToPage() {\n this._routeQueue = this._routeQueue.then(() => this._doRouteToPage()).catch(e => {\n console.error('[routeToPage]', e)\n })\n return this._routeQueue\n }\n\n private async _doRouteToPage() {\n const existing = this.renderRoot.querySelector(`main > .page[data-page=${this.page}]`) as PageView\n\n // 이미 활성 상태인 같은 페이지면 active 토글 없이 lifecycle만 갱신\n if (existing && existing.hasAttribute('active')) {\n this.activePage = existing\n } else {\n // 다른 active 페이지만 비활성화 (같은 페이지가 다시 active되는 토글 방지)\n this.renderRoot.querySelectorAll('main > .page[active]').forEach(page => {\n if (page !== existing) page.removeAttribute('active')\n })\n\n this.activePage = existing\n\n if (!this.activePage) {\n /* 해당 route에 연결된 page가 없는 경우에 main 섹션에 해당 element를 추가해준다. */\n const tagname = (await ThingsApp.pages)[this.page!]\n if (tagname) {\n const el = document.createElement(tagname) as PageView\n el.setAttribute('class', 'page')\n el.setAttribute('data-page', this.page!)\n\n this.main.appendChild(el)\n\n this.activePage = el\n }\n }\n\n if (this.activePage) {\n this.activePage.setAttribute('active', '')\n }\n }\n\n if (this.activePage) {\n this.activePage.setAttribute('context-path', this.contextPath!)\n this.activePage.lifecycle = {\n ...(this.activePage.lifecycle || {}),\n active: true,\n params: this.params,\n resourceId: this.resourceId,\n page: this.page\n }\n }\n\n store.dispatch({\n type: UPDATE_ACTIVE_PAGE,\n activePage: this.activePage\n })\n }\n\n async updated(changes: PropertyValues<this>) {\n if (changes.has('contextPathPrefix')) {\n setContextPathPrefix(this.contextPathPrefix)\n }\n\n if ((changes.has('page') || changes.has('resourceId') || changes.has('params')) && this.page) {\n this.routeToPage()\n }\n\n if (changes.has('contextPath')) {\n this.setBase()\n }\n }\n\n shouldUpdate() {\n return ThingsApp.moduleInitialized == 2\n }\n\n protected willUpdate() {\n this.page = this._routeCtrl.page\n this.params = this._routeCtrl.params\n this.resourceId = this._routeCtrl.resourceId\n this.context = this._routeCtrl.context\n this.activePage = this._routeCtrl.activePage\n\n ThingsApp.modules = this.modules = this._appCtrl.modules\n ThingsApp.contextPath = this.contextPath = this._appCtrl.contextPath\n ThingsApp.callbacks = (store.getState() as any).route?.callbacks || []\n }\n\n static async registerPages() {\n ThingsApp.pages = new Promise<{ [path: string]: string }>(resolve => (ThingsApp.pagesResolver = resolve))\n\n var reversedModules = [...ThingsApp.modules].reverse()\n const pages: { [path: string]: string } = {}\n\n /* 모듈 참조 순서 역순으로 page를 추가한다. (for overidable) */\n for (const m of reversedModules) {\n if (!m.routes) {\n continue\n }\n\n /* \n 각 모듈의 routes가 모두 완성될 때까지 ThingsApp.pages 구성을 지연한다.\n 각 모듈의 routes를 동적으로도 구성할 수 있도록 하기 위해서이다.\n */\n const routes = await m.routes\n\n routes.forEach((route: any) => {\n if (!pages[route.page]) {\n pages[route.page] = route.tagname\n }\n })\n }\n\n ThingsApp.pagesResolver(pages)\n }\n\n setBase() {\n const base = document.querySelector('base')\n base?.setAttribute('href', this.contextPath ? `${this.contextPath}/` : '/')\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/app/app.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { installRouter } from '../router.js'\n\nimport { ScrollbarStyles } from '@operato/styles'\nimport { setContextPathPrefix, getPathInfo } from '@operato/utils'\nimport { addressController } from '@operato/utils/address.js'\n\nimport { navigateWithSilence, UPDATE_ACTIVE_PAGE, UPDATE_CONTEXT_PATH, UPDATE_MODULES } from '../actions/index.js'\nimport { store } from '../store.js'\nimport { RouteController } from '../controllers/route-controller.js'\nimport { AppController } from '../controllers/app-controller.js'\nimport { AppStyle } from './app-style.js'\nimport { PageView, approveNativeDeparture } from './pages/page-view.js'\n\nenum MODULES_STATE {\n NOT_INITIALIZED,\n INITIALIZING,\n INITIALIZED\n}\n\n@customElement('things-app')\nexport class ThingsApp extends LitElement {\n static styles = [ScrollbarStyles, AppStyle]\n\n static moduleInitialized: MODULES_STATE = MODULES_STATE.NOT_INITIALIZED\n static modules: Array<any> = []\n\n /* \n 모든 모듈의 routes 리스트가 수집될 때까지, routeToPage(..) 를 hold 시키기 위해서 ThingsApp.pages를 Promise로 정의한다. \n */\n static pagesResolver: (\n value:\n | {\n [path: string]: string\n }\n | PromiseLike<{\n [path: string]: string\n }>\n ) => void\n static pages: Promise<{ [path: string]: string }>\n\n static callbacks: Array<any> = []\n static contextPath?: string\n\n private _routeCtrl = new RouteController(this)\n private _appCtrl = new AppController(this)\n\n @property({ type: String, attribute: 'context-path-prefix' }) contextPathPrefix?: string = undefined\n\n @state() resourceId?: string\n @state() page?: string\n @state() params?: any\n @state() activePage?: PageView\n @state() context: any\n @state() contextPath?: string = ThingsApp.contextPath\n @state() modules: Array<any> = ThingsApp.modules\n\n @query('main') private main!: HTMLElement\n\n render() {\n var params = this.params || {}\n var fullbleed = (this.context && this.context.fullbleed) || (params.fullbleed && params.fullbleed == 'Y')\n var widebleed = (this.context && this.context.widebleed) || (params.widebleed && params.widebleed == 'Y')\n\n return html`\n <div>\n <ox-page-header-bar header></ox-page-header-bar>\n <main></main>\n <ox-page-footer-bar footer></ox-page-footer-bar>\n </div>\n\n <ox-header-bar ?fullbleed=${fullbleed}></ox-header-bar>\n\n <ox-nav-bar ?fullbleed=${fullbleed || widebleed}></ox-nav-bar>\n\n <ox-aside-bar ?fullbleed=${fullbleed || widebleed}></ox-aside-bar>\n\n <ox-footer-bar ?fullbleed=${fullbleed}></ox-footer-bar>\n\n <ox-snack-bar></ox-snack-bar>\n `\n }\n\n connectedCallback() {\n super.connectedCallback()\n\n this.setBase()\n\n if (ThingsApp.moduleInitialized != MODULES_STATE.NOT_INITIALIZED) {\n /* Reconnected shells subscribe to the current entry without manufacturing a traversal event. */\n if (ThingsApp.moduleInitialized === MODULES_STATE.INITIALIZED) this.installAddressRouting()\n\n return\n }\n\n ThingsApp.moduleInitialized = MODULES_STATE.INITIALIZING\n\n /* 모듈 임포트를 동적으로 처리한다. */\n import(\n /* webpackPrefetch: true */\n /* webpackPreload: true */\n /* webpackChunkName: \"modules\" */\n '../module-importer.import'\n ).then(async module => {\n var modules: {\n name: string\n bootstrap: (m?: any /* self */) => void\n }[] = module.modules\n\n /* lifecycle - bootstrapping */\n for (let idx = 0; idx < modules.length; idx++) {\n const m = modules[idx]\n try {\n if (m.bootstrap) {\n await m.bootstrap(m)\n }\n } catch (e) {\n console.error(`[${idx} BOOTSTRAP ERROR -${m.name}]`, e)\n }\n }\n\n /* shouldUpdate를 활성화한다. */\n ThingsApp.moduleInitialized = MODULES_STATE.INITIALIZED\n\n /*\n modules를 ThingsApp.modules에 직접 할당 후 registerPages()를 먼저 호출하여\n ThingsApp.pages가 준비된 상태에서 첫 라우팅이 일어나도록 보장한다.\n (registerPages()는 updated()에서도 modules 변경 시 호출되지만, 그 시점은\n 첫 라우팅보다 나중이므로 첫 URL이 404로 빠지는 문제가 발생함)\n */\n ThingsApp.modules = modules\n ThingsApp.registerPages()\n\n /*\n contextPathPrefix 속성이 설정되어 있으면, installRouter 전에 적용한다.\n updated()에서도 setContextPathPrefix가 호출되지만, 그 시점은\n installRouter의 첫 콜백보다 나중이므로 첫 URL 파싱이 실패할 수 있다.\n */\n if (this.contextPathPrefix) {\n setContextPathPrefix(this.contextPathPrefix)\n }\n\n /* modules를 store에 dispatch 함으로써, update를 invoke 시킨다. */\n store.dispatch({\n type: UPDATE_MODULES,\n modules\n })\n\n this.installAddressRouting()\n })\n }\n\n private stopAddressGuard?: () => void\n private stopAddressRouter?: () => void\n\n private installAddressRouting() {\n this.stopAddressGuard?.()\n this.stopAddressRouter?.()\n let previousEntry: ReturnType<typeof addressController>['entry'] | undefined\n\n this.stopAddressGuard = addressController().guard({\n approve: change => this.activePage?.canDeactivate(change.signal) ?? true,\n approveSync: () => approveNativeDeparture(this.activePage),\n dirty: () => this.activePage?.addressDirty ?? false,\n committed: () => this.activePage?.discardAddressEdits()\n })\n\n this.stopAddressRouter = installRouter(async (location, e) => {\n var { pathname } = location\n var { contextPath } = getPathInfo(pathname)\n\n if (ThingsApp.contextPath !== contextPath) {\n store.dispatch({\n type: UPDATE_CONTEXT_PATH,\n contextPath\n })\n }\n\n const currentEntry = addressController().entry\n // Registration changes the projection, not history. Project both entries with today's owner claims.\n const pageAddress = JSON.stringify([pathname, addressController().params(currentEntry)])\n const previousAddress =\n previousEntry && JSON.stringify([previousEntry.url.pathname, addressController().params(previousEntry)])\n previousEntry = currentEntry\n if (pageAddress !== previousAddress) {\n store.dispatch(navigateWithSilence(location) as any)\n }\n\n ThingsApp.callbacks &&\n ThingsApp.callbacks.forEach(callback => {\n try {\n callback.call(this, location, e)\n } catch (ex) {\n console.error(ex)\n }\n })\n })\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback()\n this.stopAddressGuard?.()\n this.stopAddressRouter?.()\n }\n\n /** routeToPage 호출 직렬화 — 동시 실행으로 인한 페이지 중복 생성/다중 active 방지 */\n private _routeQueue: Promise<void> = Promise.resolve()\n\n routeToPage() {\n this._routeQueue = this._routeQueue\n .then(() => this._doRouteToPage())\n .catch(e => {\n console.error('[routeToPage]', e)\n })\n return this._routeQueue\n }\n\n private async _doRouteToPage() {\n const target = { page: this.page, resourceId: this.resourceId, params: this.params, contextPath: this.contextPath }\n const pages = await ThingsApp.pages\n if (\n target.page !== this.page ||\n target.resourceId !== this.resourceId ||\n target.params !== this.params ||\n target.contextPath !== this.contextPath\n )\n return\n const existing = this.renderRoot.querySelector(`main > .page[data-page=${this.page}]`) as PageView\n\n // 이미 활성 상태인 같은 페이지면 active 토글 없이 lifecycle만 갱신\n if (existing && existing.hasAttribute('active')) {\n this.activePage = existing\n } else {\n // 다른 active 페이지만 비활성화 (같은 페이지가 다시 active되는 토글 방지)\n this.renderRoot.querySelectorAll('main > .page[active]').forEach(page => {\n if (page !== existing) page.removeAttribute('active')\n })\n\n this.activePage = existing\n\n if (!this.activePage) {\n /* 해당 route에 연결된 page가 없는 경우에 main 섹션에 해당 element를 추가해준다. */\n const tagname = pages[this.page!]\n if (tagname) {\n const el = document.createElement(tagname) as PageView\n el.setAttribute('class', 'page')\n el.setAttribute('data-page', this.page!)\n\n this.main.appendChild(el)\n\n this.activePage = el\n }\n }\n\n if (this.activePage) {\n this.activePage.setAttribute('active', '')\n }\n }\n\n if (this.activePage) {\n this.activePage.setAttribute('context-path', this.contextPath!)\n this.activePage.lifecycle = {\n ...(this.activePage.lifecycle || {}),\n active: true,\n params: this.params,\n resourceId: this.resourceId,\n page: this.page\n }\n }\n\n store.dispatch({\n type: UPDATE_ACTIVE_PAGE,\n activePage: this.activePage\n })\n }\n\n async updated(changes: PropertyValues<this>) {\n if (changes.has('contextPathPrefix')) {\n setContextPathPrefix(this.contextPathPrefix)\n }\n\n if ((changes.has('page') || changes.has('resourceId') || changes.has('params')) && this.page) {\n this.routeToPage()\n }\n\n if (changes.has('contextPath')) {\n this.setBase()\n }\n }\n\n shouldUpdate() {\n return ThingsApp.moduleInitialized == 2\n }\n\n protected willUpdate() {\n this.page = this._routeCtrl.page\n this.params = this._routeCtrl.params\n this.resourceId = this._routeCtrl.resourceId\n this.context = this._routeCtrl.context\n this.activePage = this._routeCtrl.activePage\n\n ThingsApp.modules = this.modules = this._appCtrl.modules\n ThingsApp.contextPath = this.contextPath = this._appCtrl.contextPath\n ThingsApp.callbacks = (store.getState() as any).route?.callbacks || []\n }\n\n static async registerPages() {\n ThingsApp.pages = new Promise<{ [path: string]: string }>(resolve => (ThingsApp.pagesResolver = resolve))\n\n var reversedModules = [...ThingsApp.modules].reverse()\n const pages: { [path: string]: string } = {}\n\n /* 모듈 참조 순서 역순으로 page를 추가한다. (for overidable) */\n for (const m of reversedModules) {\n if (!m.routes) {\n continue\n }\n\n /* \n 각 모듈의 routes가 모두 완성될 때까지 ThingsApp.pages 구성을 지연한다.\n 각 모듈의 routes를 동적으로도 구성할 수 있도록 하기 위해서이다.\n */\n const routes = await m.routes\n\n routes.forEach((route: any) => {\n if (!pages[route.page]) {\n pages[route.page] = route.tagname\n }\n })\n }\n\n ThingsApp.pagesResolver(pages)\n }\n\n setBase() {\n const base = document.querySelector('base')\n base?.setAttribute('href', this.contextPath ? `${this.contextPath}/` : '/')\n }\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LitElement, PropertyValues } from 'lit';
|
|
2
|
+
import { OxPrompt } from '@operato/popup/ox-prompt.js';
|
|
2
3
|
export type PageLifecycle = {
|
|
3
4
|
active: boolean;
|
|
4
5
|
params: object;
|
|
@@ -10,12 +11,21 @@ export type PageLifecycle = {
|
|
|
10
11
|
* Subclasses can extend PageView to define custom behavior and handle page lifecycle events.
|
|
11
12
|
*/
|
|
12
13
|
export declare class PageView extends LitElement {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
private listDrafts;
|
|
15
|
+
private listDraft;
|
|
16
|
+
/** True only for the current edit's completed IndexedDB write; an unwritten edit still needs protection. */
|
|
17
|
+
get addressEditsKept(): boolean;
|
|
18
|
+
private queryChanged;
|
|
19
|
+
connectedCallback(): void;
|
|
20
|
+
disconnectedCallback(): void;
|
|
21
|
+
/** One page-owned decision, shared by the app dialog and the native traversal adapter. */
|
|
22
|
+
get deactivation(): boolean | Parameters<typeof OxPrompt.open>[0];
|
|
23
|
+
canDeactivate(signal?: AbortSignal): Promise<boolean>;
|
|
24
|
+
protected get addressDiscardText(): string;
|
|
25
|
+
get addressDirty(): boolean;
|
|
26
|
+
protected flushAddressEdits(): void;
|
|
27
|
+
/** Runs only once approval has actually committed, never while a question is pending or canceled. */
|
|
28
|
+
discardAddressEdits(): void;
|
|
19
29
|
/**
|
|
20
30
|
* Determines whether the page should update. This method is called whenever there are
|
|
21
31
|
* changes to the page's properties.
|
|
@@ -79,3 +89,5 @@ export declare class PageView extends LitElement {
|
|
|
79
89
|
*/
|
|
80
90
|
get context(): {};
|
|
81
91
|
}
|
|
92
|
+
/** Presentation adapter used only by cancelable native traversal on engines without precommit. */
|
|
93
|
+
export declare function approveNativeDeparture(page?: PageView): boolean | 'preserve';
|
|
@@ -2,8 +2,12 @@ import { __decorate } from "tslib";
|
|
|
2
2
|
import { LitElement } from 'lit';
|
|
3
3
|
import { property } from 'lit/decorators.js';
|
|
4
4
|
import isEqual from 'lodash-es/isEqual.js';
|
|
5
|
+
import { i18next } from '@operato/i18n';
|
|
6
|
+
import { OxPrompt } from '@operato/popup/ox-prompt.js';
|
|
5
7
|
import { UPDATE_CONTEXT } from '../../actions/const.js';
|
|
6
8
|
import { store } from '../../store.js';
|
|
9
|
+
import { getPathInfo } from '@operato/utils';
|
|
10
|
+
import { UnsavedDraftController } from '../../drafts/unsaved-draft-controller.js';
|
|
7
11
|
function diff(after, before) {
|
|
8
12
|
var changed = false;
|
|
9
13
|
var changes = {};
|
|
@@ -24,18 +28,118 @@ function diff(after, before) {
|
|
|
24
28
|
export class PageView extends LitElement {
|
|
25
29
|
constructor() {
|
|
26
30
|
super(...arguments);
|
|
31
|
+
this.listDrafts = new Map();
|
|
32
|
+
this.listDraft = (event) => {
|
|
33
|
+
const { source, query, action, pathname } = event.detail;
|
|
34
|
+
let binding = this.listDrafts.get(source);
|
|
35
|
+
if (binding && binding.query !== query) {
|
|
36
|
+
binding.controller.dispose();
|
|
37
|
+
this.listDrafts.delete(source);
|
|
38
|
+
binding = undefined;
|
|
39
|
+
}
|
|
40
|
+
if (!binding && action !== 'leave' && action !== 'discard') {
|
|
41
|
+
const state = store.getState();
|
|
42
|
+
const user = state.auth?.user?.id;
|
|
43
|
+
const target = JSON.stringify([
|
|
44
|
+
source.id || Array.from(this.renderRoot.querySelectorAll('ox-grist')).indexOf(source),
|
|
45
|
+
query
|
|
46
|
+
]);
|
|
47
|
+
const controller = new UnsavedDraftController(source, {
|
|
48
|
+
address: () => {
|
|
49
|
+
const current = store.getState();
|
|
50
|
+
return user && current.auth?.user?.id === user
|
|
51
|
+
? { user, domain: getPathInfo(pathname).domain || '', screen: pathname, target }
|
|
52
|
+
: undefined;
|
|
53
|
+
},
|
|
54
|
+
snapshot: () => {
|
|
55
|
+
source.flushEdits();
|
|
56
|
+
return source.draftSnapshot;
|
|
57
|
+
},
|
|
58
|
+
savedRevision: () => source.draftRevision,
|
|
59
|
+
restore: (value, base) => source.restoreUnsavedDraft(value, base)
|
|
60
|
+
});
|
|
61
|
+
binding = { query, controller };
|
|
62
|
+
this.listDrafts.set(source, binding);
|
|
63
|
+
}
|
|
64
|
+
if (!binding)
|
|
65
|
+
return;
|
|
66
|
+
if (action === 'discard')
|
|
67
|
+
void binding.controller.settled();
|
|
68
|
+
if (action === 'edit')
|
|
69
|
+
void binding.controller.flush();
|
|
70
|
+
if (action === 'loaded' && this.active && pathname === location.pathname)
|
|
71
|
+
void binding.controller.offer();
|
|
72
|
+
if (action === 'leave') {
|
|
73
|
+
if (source.draftSnapshot)
|
|
74
|
+
void binding.controller.flush();
|
|
75
|
+
binding.controller.dispose();
|
|
76
|
+
this.listDrafts.delete(source);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
this.queryChanged = () => {
|
|
80
|
+
if (this.active)
|
|
81
|
+
this.updateContext();
|
|
82
|
+
};
|
|
27
83
|
/**
|
|
28
84
|
* Indicates whether the page is currently active.
|
|
29
85
|
*/
|
|
30
86
|
this.active = false;
|
|
31
87
|
}
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
88
|
+
/** True only for the current edit's completed IndexedDB write; an unwritten edit still needs protection. */
|
|
89
|
+
get addressEditsKept() {
|
|
90
|
+
this.flushAddressEdits();
|
|
91
|
+
const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist'));
|
|
92
|
+
const dirty = [...new Set([...grids, ...this.listDrafts.keys()])].filter(source => source.dirtyRecords?.length);
|
|
93
|
+
return dirty.length > 0 && dirty.every(source => this.listDrafts.get(source)?.controller.keeps);
|
|
94
|
+
}
|
|
95
|
+
connectedCallback() {
|
|
96
|
+
super.connectedCallback();
|
|
97
|
+
this.addEventListener('query-state-change', this.queryChanged);
|
|
98
|
+
this.addEventListener('list-draft', this.listDraft);
|
|
99
|
+
}
|
|
100
|
+
disconnectedCallback() {
|
|
101
|
+
super.disconnectedCallback();
|
|
102
|
+
this.removeEventListener('query-state-change', this.queryChanged);
|
|
103
|
+
for (const [source, binding] of this.listDrafts) {
|
|
104
|
+
if (source.draftSnapshot)
|
|
105
|
+
void binding.controller.flush();
|
|
106
|
+
binding.controller.dispose();
|
|
107
|
+
}
|
|
108
|
+
this.listDrafts.clear();
|
|
109
|
+
this.removeEventListener('list-draft', this.listDraft);
|
|
110
|
+
}
|
|
111
|
+
/** One page-owned decision, shared by the app dialog and the native traversal adapter. */
|
|
112
|
+
get deactivation() {
|
|
113
|
+
if (!this.addressDirty)
|
|
114
|
+
return true;
|
|
115
|
+
return {
|
|
116
|
+
type: 'warning',
|
|
117
|
+
title: i18next.t('title.unsaved-draft', { defaultValue: 'there is an unsaved edit' }),
|
|
118
|
+
text: this.addressDiscardText,
|
|
119
|
+
confirmButton: { text: i18next.t('button.discard', { defaultValue: 'discard' }), destructive: true },
|
|
120
|
+
cancelButton: { text: i18next.t('button.cancel', { defaultValue: 'cancel' }) }
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
async canDeactivate(signal) {
|
|
124
|
+
const decision = this.deactivation;
|
|
125
|
+
return typeof decision === 'boolean' ? decision : OxPrompt.open({ ...decision, signal });
|
|
126
|
+
}
|
|
127
|
+
get addressDiscardText() {
|
|
128
|
+
return i18next.t('text.unsaved-may-be-lost', { defaultValue: 'anything not saved is lost.' });
|
|
129
|
+
}
|
|
130
|
+
get addressDirty() {
|
|
131
|
+
this.flushAddressEdits();
|
|
132
|
+
const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist'));
|
|
133
|
+
return grids.some(grid => grid.dirtyRecords?.length);
|
|
134
|
+
}
|
|
135
|
+
flushAddressEdits() {
|
|
136
|
+
const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist'));
|
|
137
|
+
grids.forEach(grid => grid.flushEdits?.());
|
|
138
|
+
}
|
|
139
|
+
/** Runs only once approval has actually committed, never while a question is pending or canceled. */
|
|
140
|
+
discardAddressEdits() {
|
|
141
|
+
const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist'));
|
|
142
|
+
grids.filter(grid => grid.dirtyRecords?.length).forEach(grid => grid.reset());
|
|
39
143
|
}
|
|
40
144
|
/**
|
|
41
145
|
* Determines whether the page should update. This method is called whenever there are
|
|
@@ -182,4 +286,15 @@ __decorate([
|
|
|
182
286
|
__decorate([
|
|
183
287
|
property({ type: String, attribute: 'context-path' })
|
|
184
288
|
], PageView.prototype, "contextPath", void 0);
|
|
289
|
+
/** Presentation adapter used only by cancelable native traversal on engines without precommit. */
|
|
290
|
+
export function approveNativeDeparture(page) {
|
|
291
|
+
if (!page)
|
|
292
|
+
return true;
|
|
293
|
+
const decision = page.deactivation;
|
|
294
|
+
if (typeof decision === 'boolean')
|
|
295
|
+
return decision;
|
|
296
|
+
if (page.addressEditsKept)
|
|
297
|
+
return 'preserve';
|
|
298
|
+
return window.confirm(String(decision.text || ''));
|
|
299
|
+
}
|
|
185
300
|
//# sourceMappingURL=page-view.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-view.js","sourceRoot":"","sources":["../../../../src/app/pages/page-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, PropertyValues } from 'lit'\nimport { property } from 'lit/decorators.js'\nimport isEqual from 'lodash-es/isEqual.js'\n\nimport { UPDATE_CONTEXT } from '../../actions/const.js'\nimport { store } from '../../store.js'\n\nexport type PageLifecycle = {\n active: boolean\n params: object\n resourceId?: string\n page?: string\n}\n\nfunction diff(after: any, before: any): any {\n var changed = false\n var changes: { [key: string]: any } = {}\n\n Object.getOwnPropertyNames(after).forEach(function (key) {\n let before_val = before[key]\n let after_val = after[key]\n\n if (!isEqual(before_val, after_val)) {\n changes[key] = after_val\n changed = true\n }\n })\n\n return changed && changes\n}\n\n/**\n * PageView is a base class for creating page elements with lifecycle management.\n * Subclasses can extend PageView to define custom behavior and handle page lifecycle events.\n */\nexport class PageView extends LitElement {\n /**\n * Determines whether the page can be deactivated. Subclasses can override this method\n * to implement custom deactivation logic.\n * @returns A Promise that resolves to true if the page can be deactivated, or false otherwise.\n */\n async canDeactivate(): Promise<boolean> {\n return true\n }\n\n /**\n * Determines whether the page should update. This method is called whenever there are\n * changes to the page's properties.\n * @param changes - A map of changed property values.\n * @returns True if the page should update, or false otherwise.\n */\n shouldUpdate(changes: PropertyValues<this>) {\n var active = String(this.active) == 'true'\n var { active: oldActive = false } = this._oldLifecycleInfo$ || {}\n\n /*\n * page lifecycle\n * case 1. page가 새로 activate 되었다.\n * case 2. page가 active 상태에서 lifecycle 정보가 바뀌었다.\n **/\n if (active) {\n this.pageUpdate({\n active\n })\n } else if (oldActive) {\n this.pageUpdate({\n active\n })\n }\n\n return active\n }\n\n /**\n * Indicates whether the page is currently active.\n */\n @property({ type: Boolean }) active: boolean = false\n\n /**\n * Stores information about the page's lifecycle.\n */\n @property({ type: Object }) lifecycle!: PageLifecycle\n\n /**\n * The context path for the page.\n */\n @property({ type: String, attribute: 'context-path' }) contextPath?: string\n\n _oldLifecycleInfo$: any\n\n /* lifecycle */\n\n /**\n * Handles page updates and lifecycle events. Subclasses can override this method\n * to implement custom logic for initializing, updating, and disposing of the page.\n * @param changes - A map of changed properties.\n * @param force - If true, forces an update of the page.\n */\n async pageUpdate(changes: any = {}, force: boolean = false) {\n var before = this._oldLifecycleInfo$ || {}\n\n var after = {\n ...before,\n ...this.lifecycle,\n contextPath: this.contextPath,\n ...changes\n }\n\n if (!('initialized' in changes) && after.active && !before.initialized) {\n after.initialized = true\n }\n\n if (force) {\n after.updated = Date.now()\n }\n\n var changed = diff(after, before)\n if (!changed) {\n return\n }\n\n this._oldLifecycleInfo$ = after\n\n /* page의 이미 초기화된 상태에서 contextPath가 바뀐다면, 무조건 page가 리셋되어야 한다. */\n if (before.initialized && changed.contextPath) {\n await this.pageReset()\n return\n }\n\n if (changed.initialized) {\n await this.pageInitialized(after)\n }\n\n if ('initialized' in changed) {\n if (changed.initialized) {\n /*\n * 방금 초기화된 경우라면, 엘리먼트들이 만들어지지 않았을 가능성이 있으므로,\n * 다음 animationFrame에서 pageUpdated 콜백을 호출한다.\n */\n requestAnimationFrame(async () => {\n await this.pageUpdated(changed, after, before)\n /* active page인 경우에는, page Context 갱신도 필요할 것이다. */\n after.active && this.updateContext()\n })\n } else {\n await this.pageDisposed(after)\n }\n } else {\n await this.pageUpdated(changed, after, before)\n /* active page인 경우에는, page Context 갱신도 필요할 것이다. */\n after.active && this.updateContext()\n }\n }\n\n /**\n * Resets the page. Subclasses can override this method to perform custom reset logic.\n */\n async pageReset() {\n var { initialized } = this._oldLifecycleInfo$ || {}\n\n if (initialized) {\n await this.pageDispose()\n await this.pageUpdate({}, true)\n }\n }\n\n /**\n * Disposes of the page. Subclasses can override this method to perform custom disposal logic.\n */\n async pageDispose() {\n await this.pageUpdate({\n initialized: false\n })\n }\n\n /**\n * Initializes the page. Subclasses can override this method to perform custom initialization logic.\n * @param pageInfo - Information about the page's state.\n */\n pageInitialized(pageInfo: any) {}\n\n /**\n * Handles page updates and changes in properties.\n * Subclasses can override this method to implement custom update logic.\n * @param changes - A map of changed properties.\n * @param after - The current state of the page.\n * @param before - The previous state of the page.\n */\n pageUpdated(changes: any, after: any, before: any) {}\n\n /**\n * Handles the disposal of the page. Subclasses can override this method\n * to implement custom disposal logic.\n * @param pageInfo - Information about the page's state.\n */\n pageDisposed(pageInfo: any) {}\n\n /* context */\n updateContext(override?: any) {\n store.dispatch({\n type: UPDATE_CONTEXT,\n context: override ? { ...this.context, ...override } : this.context\n })\n }\n\n /**\n * Updates the context of the page. Subclasses can override the `context` getter\n * to provide specific context information for the page. The context will be updated\n * using the `updateContext` method inherited from PageView.\n * @param override - An optional object with context properties to override.\n */\n get context() {\n return {}\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"page-view.js","sourceRoot":"","sources":["../../../../src/app/pages/page-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, PropertyValues, type ReactiveControllerHost } from 'lit'\nimport { property } from 'lit/decorators.js'\nimport isEqual from 'lodash-es/isEqual.js'\nimport { i18next } from '@operato/i18n'\nimport { OxPrompt } from '@operato/popup/ox-prompt.js'\n\nimport { UPDATE_CONTEXT } from '../../actions/const.js'\nimport { store } from '../../store.js'\nimport { getPathInfo } from '@operato/utils'\nimport { UnsavedDraftController } from '../../drafts/unsaved-draft-controller.js'\n\ntype ListDraftSource = HTMLElement &\n ReactiveControllerHost & {\n draftSnapshot?: { value: unknown; base: string | number | null }\n draftRevision: string | number | null\n dirtyRecords?: unknown[]\n restoreUnsavedDraft(value: unknown, base: string | number | null): void\n flushEdits(): void\n }\n\nexport type PageLifecycle = {\n active: boolean\n params: object\n resourceId?: string\n page?: string\n}\n\nfunction diff(after: any, before: any): any {\n var changed = false\n var changes: { [key: string]: any } = {}\n\n Object.getOwnPropertyNames(after).forEach(function (key) {\n let before_val = before[key]\n let after_val = after[key]\n\n if (!isEqual(before_val, after_val)) {\n changes[key] = after_val\n changed = true\n }\n })\n\n return changed && changes\n}\n\n/**\n * PageView is a base class for creating page elements with lifecycle management.\n * Subclasses can extend PageView to define custom behavior and handle page lifecycle events.\n */\nexport class PageView extends LitElement {\n private listDrafts = new Map<ListDraftSource, { query: string; controller: UnsavedDraftController<unknown> }>()\n\n private listDraft = (event: Event) => {\n const { source, query, action, pathname } = (\n event as CustomEvent<{\n source: ListDraftSource\n query: string\n pathname: string\n action: 'edit' | 'loaded' | 'leave' | 'discard'\n }>\n ).detail\n let binding = this.listDrafts.get(source)\n if (binding && binding.query !== query) {\n binding.controller.dispose()\n this.listDrafts.delete(source)\n binding = undefined\n }\n if (!binding && action !== 'leave' && action !== 'discard') {\n const state = store.getState() as { auth?: { user?: { id?: string } } }\n const user = state.auth?.user?.id\n const target = JSON.stringify([\n source.id || Array.from(this.renderRoot.querySelectorAll('ox-grist')).indexOf(source),\n query\n ])\n const controller = new UnsavedDraftController(source, {\n address: () => {\n const current = store.getState() as { auth?: { user?: { id?: string } } }\n return user && current.auth?.user?.id === user\n ? { user, domain: getPathInfo(pathname).domain || '', screen: pathname, target }\n : undefined\n },\n snapshot: () => {\n source.flushEdits()\n return source.draftSnapshot\n },\n savedRevision: () => source.draftRevision,\n restore: (value, base) => source.restoreUnsavedDraft(value, base)\n })\n binding = { query, controller }\n this.listDrafts.set(source, binding)\n }\n if (!binding) return\n if (action === 'discard') void binding.controller.settled()\n if (action === 'edit') void binding.controller.flush()\n if (action === 'loaded' && this.active && pathname === location.pathname) void binding.controller.offer()\n if (action === 'leave') {\n if (source.draftSnapshot) void binding.controller.flush()\n binding.controller.dispose()\n this.listDrafts.delete(source)\n }\n }\n\n /** True only for the current edit's completed IndexedDB write; an unwritten edit still needs protection. */\n get addressEditsKept(): boolean {\n this.flushAddressEdits()\n const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist')) as ListDraftSource[]\n const dirty = [...new Set([...grids, ...this.listDrafts.keys()])].filter(source => source.dirtyRecords?.length)\n return dirty.length > 0 && dirty.every(source => this.listDrafts.get(source)?.controller.keeps)\n }\n\n private queryChanged = () => {\n if (this.active) this.updateContext()\n }\n\n connectedCallback() {\n super.connectedCallback()\n this.addEventListener('query-state-change', this.queryChanged)\n this.addEventListener('list-draft', this.listDraft)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.removeEventListener('query-state-change', this.queryChanged)\n for (const [source, binding] of this.listDrafts) {\n if (source.draftSnapshot) void binding.controller.flush()\n binding.controller.dispose()\n }\n this.listDrafts.clear()\n this.removeEventListener('list-draft', this.listDraft)\n }\n /** One page-owned decision, shared by the app dialog and the native traversal adapter. */\n get deactivation(): boolean | Parameters<typeof OxPrompt.open>[0] {\n if (!this.addressDirty) return true\n return {\n type: 'warning',\n title: i18next.t('title.unsaved-draft', { defaultValue: 'there is an unsaved edit' }),\n text: this.addressDiscardText,\n confirmButton: { text: i18next.t('button.discard', { defaultValue: 'discard' }), destructive: true },\n cancelButton: { text: i18next.t('button.cancel', { defaultValue: 'cancel' }) }\n }\n }\n\n async canDeactivate(signal?: AbortSignal): Promise<boolean> {\n const decision = this.deactivation\n return typeof decision === 'boolean' ? decision : OxPrompt.open({ ...decision, signal })\n }\n\n protected get addressDiscardText(): string {\n return i18next.t('text.unsaved-may-be-lost', { defaultValue: 'anything not saved is lost.' })\n }\n\n get addressDirty(): boolean {\n this.flushAddressEdits()\n const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist')) as (HTMLElement & {\n dirtyRecords?: unknown[]\n })[]\n return grids.some(grid => grid.dirtyRecords?.length)\n }\n\n protected flushAddressEdits(): void {\n const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist')) as (HTMLElement & {\n flushEdits?: () => void\n })[]\n grids.forEach(grid => grid.flushEdits?.())\n }\n\n /** Runs only once approval has actually committed, never while a question is pending or canceled. */\n discardAddressEdits(): void {\n const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist')) as (HTMLElement & {\n dirtyRecords?: unknown[]\n reset(): void\n })[]\n grids.filter(grid => grid.dirtyRecords?.length).forEach(grid => grid.reset())\n }\n\n /**\n * Determines whether the page should update. This method is called whenever there are\n * changes to the page's properties.\n * @param changes - A map of changed property values.\n * @returns True if the page should update, or false otherwise.\n */\n shouldUpdate(changes: PropertyValues<this>) {\n var active = String(this.active) == 'true'\n var { active: oldActive = false } = this._oldLifecycleInfo$ || {}\n\n /*\n * page lifecycle\n * case 1. page가 새로 activate 되었다.\n * case 2. page가 active 상태에서 lifecycle 정보가 바뀌었다.\n **/\n if (active) {\n this.pageUpdate({\n active\n })\n } else if (oldActive) {\n this.pageUpdate({\n active\n })\n }\n\n return active\n }\n\n /**\n * Indicates whether the page is currently active.\n */\n @property({ type: Boolean }) active: boolean = false\n\n /**\n * Stores information about the page's lifecycle.\n */\n @property({ type: Object }) lifecycle!: PageLifecycle\n\n /**\n * The context path for the page.\n */\n @property({ type: String, attribute: 'context-path' }) contextPath?: string\n\n _oldLifecycleInfo$: any\n\n /* lifecycle */\n\n /**\n * Handles page updates and lifecycle events. Subclasses can override this method\n * to implement custom logic for initializing, updating, and disposing of the page.\n * @param changes - A map of changed properties.\n * @param force - If true, forces an update of the page.\n */\n async pageUpdate(changes: any = {}, force: boolean = false) {\n var before = this._oldLifecycleInfo$ || {}\n\n var after = {\n ...before,\n ...this.lifecycle,\n contextPath: this.contextPath,\n ...changes\n }\n\n if (!('initialized' in changes) && after.active && !before.initialized) {\n after.initialized = true\n }\n\n if (force) {\n after.updated = Date.now()\n }\n\n var changed = diff(after, before)\n if (!changed) {\n return\n }\n\n this._oldLifecycleInfo$ = after\n\n /* page의 이미 초기화된 상태에서 contextPath가 바뀐다면, 무조건 page가 리셋되어야 한다. */\n if (before.initialized && changed.contextPath) {\n await this.pageReset()\n return\n }\n\n if (changed.initialized) {\n await this.pageInitialized(after)\n }\n\n if ('initialized' in changed) {\n if (changed.initialized) {\n /*\n * 방금 초기화된 경우라면, 엘리먼트들이 만들어지지 않았을 가능성이 있으므로,\n * 다음 animationFrame에서 pageUpdated 콜백을 호출한다.\n */\n requestAnimationFrame(async () => {\n await this.pageUpdated(changed, after, before)\n /* active page인 경우에는, page Context 갱신도 필요할 것이다. */\n after.active && this.updateContext()\n })\n } else {\n await this.pageDisposed(after)\n }\n } else {\n await this.pageUpdated(changed, after, before)\n /* active page인 경우에는, page Context 갱신도 필요할 것이다. */\n after.active && this.updateContext()\n }\n }\n\n /**\n * Resets the page. Subclasses can override this method to perform custom reset logic.\n */\n async pageReset() {\n var { initialized } = this._oldLifecycleInfo$ || {}\n\n if (initialized) {\n await this.pageDispose()\n await this.pageUpdate({}, true)\n }\n }\n\n /**\n * Disposes of the page. Subclasses can override this method to perform custom disposal logic.\n */\n async pageDispose() {\n await this.pageUpdate({\n initialized: false\n })\n }\n\n /**\n * Initializes the page. Subclasses can override this method to perform custom initialization logic.\n * @param pageInfo - Information about the page's state.\n */\n pageInitialized(pageInfo: any) {}\n\n /**\n * Handles page updates and changes in properties.\n * Subclasses can override this method to implement custom update logic.\n * @param changes - A map of changed properties.\n * @param after - The current state of the page.\n * @param before - The previous state of the page.\n */\n pageUpdated(changes: any, after: any, before: any) {}\n\n /**\n * Handles the disposal of the page. Subclasses can override this method\n * to implement custom disposal logic.\n * @param pageInfo - Information about the page's state.\n */\n pageDisposed(pageInfo: any) {}\n\n /* context */\n updateContext(override?: any) {\n store.dispatch({\n type: UPDATE_CONTEXT,\n context: override ? { ...this.context, ...override } : this.context\n })\n }\n\n /**\n * Updates the context of the page. Subclasses can override the `context` getter\n * to provide specific context information for the page. The context will be updated\n * using the `updateContext` method inherited from PageView.\n * @param override - An optional object with context properties to override.\n */\n get context() {\n return {}\n }\n}\n\n/** Presentation adapter used only by cancelable native traversal on engines without precommit. */\nexport function approveNativeDeparture(page?: PageView): boolean | 'preserve' {\n if (!page) return true\n const decision = page.deactivation\n if (typeof decision === 'boolean') return decision\n if (page.addressEditsKept) return 'preserve'\n return window.confirm(String(decision.text || ''))\n}\n"]}
|