@operato/shell 10.29.39 → 10.29.43

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.
@@ -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) => Promise<boolean>;
14
+ export declare const navigate: (location: string, replace?: boolean, source?: Element) => 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
  *
@@ -15,8 +15,8 @@ import { store } from '../store.js';
15
15
  * @param location - The path of the page to navigate to.
16
16
  * @param replace - Optional. If true, replaces the current page in the browser's history.
17
17
  */
18
- export const navigate = (location, replace) => {
19
- return writeAddress(new URL(location, document.baseURI), { replace });
18
+ export const navigate = (location, replace, source) => {
19
+ return writeAddress(new URL(location, document.baseURI), { replace, source, intent: 'navigation' });
20
20
  };
21
21
  /**
22
22
  * Navigate to a page with optional query parameters, and dispatch a Redux action to load the page.
@@ -1 +1 @@
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"]}
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../src/actions/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAE3E,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,QAAgB,EAAE,OAAiB,EAAE,MAAgB,EAAE,EAAE;IAChF,OAAO,YAAY,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAA;AACrG,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAC9B,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAA0E,EAAE,EAAE,CAC/G,CAAC,QAAa,EAAE,EAAE;IAChB,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;IAE5C,MAAM,GAAG,GAAG,uBAAuB,CAAA;IACnC,MAAM,UAAU,GAAG,kBAAkB,CAAC,QAAS,CAAC,CAAA;IAChD,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;IAC/C,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAA;IACvC,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;IAEzB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,iBAAiB,EAAE,CAAC,MAAM,CAAC;YAClC,GAAG,iBAAiB,EAAE,CAAC,KAAK;YAC5B,GAAG,EAAE,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC;SACrD,CAAC,CAAA;IACJ,CAAC;IAED,2EAA2E;IAC3E,kBAAkB;IAClB,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,CAAA;AACtC,CAAC,CAAA;AAEH;;;;;GAKG;AACH,MAAM,YAAY,GAAG,KAAK,EAAE,IAAS,EAAE,EAAE;IACvC;;;OAGG;IACH,IAAI,KAAK,GAAQ,KAAK,CAAC,QAAQ,EAAE,CAAA;IAEjC,uDAAuD;IACvD,IAAI,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAA;IAC/B,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,IAAI,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;YACvB,IAAI,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;YAC9D,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,KAAK,CAAA;YACd,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC,CAAA;AAED;;;;;;GAMG;AACH,IAAI,YAAY,GAAG,CAAC,CAAA;AACpB,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAU,EAAE,MAA8B,EAAE,EAAE,CAAC,KAAK,EAAE,QAAa,EAAE,EAAE;IAC5G,MAAM,QAAQ,GAAG,EAAE,YAAY,CAAA;IAC/B,IAAI,OAAO,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAA;IACtC,IAAI,QAAQ,KAAK,YAAY;QAAE,OAAM;IAErC,IAAI,IAAI,KAAK,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,QAAQ,CACN,mBAAmB,CAAC;YAClB,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO;YAC3C,MAAM;SACP,CAAC,CACH,CAAA;QACD,OAAM;IACR,CAAC;IAED,QAAQ,CAAC;QACP,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,OAAO;QACb,UAAU,EAAE,EAAE;QACd,MAAM;KACP,CAAC,CAAA;AACJ,CAAC,CAAA","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, source?: Element) => {\n return writeAddress(new URL(location, document.baseURI), { replace, source, intent: 'navigation' })\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"]}
@@ -11,7 +11,7 @@ import { store } from '../store.js';
11
11
  import { RouteController } from '../controllers/route-controller.js';
12
12
  import { AppController } from '../controllers/app-controller.js';
13
13
  import { AppStyle } from './app-style.js';
14
- import { approveNativeDeparture } from './pages/page-view.js';
14
+ import { staysOn } from './pages/page-view.js';
15
15
  var MODULES_STATE;
16
16
  (function (MODULES_STATE) {
17
17
  MODULES_STATE[MODULES_STATE["NOT_INITIALIZED"] = 0] = "NOT_INITIALIZED";
@@ -115,11 +115,13 @@ let ThingsApp = class ThingsApp extends LitElement {
115
115
  this.stopAddressGuard?.();
116
116
  this.stopAddressRouter?.();
117
117
  let previousEntry;
118
+ const discards = (change) => !!this.activePage && this.activePage.discards(change, staysOn(this.activePage, change.after.url, change.before.url));
118
119
  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()
120
+ approve: change => (discards(change) ? this.activePage.canDeactivate(change.signal) : true),
121
+ discards,
122
+ /* Edits a draft holds survive a traversal: they are offered back on return. */
123
+ kept: () => !!this.activePage?.addressEditsKept,
124
+ committed: change => discards(change) && this.activePage.discardAddressEdits(change)
123
125
  });
124
126
  this.stopAddressRouter = installRouter(async (location, e) => {
125
127
  var { pathname } = location;
@@ -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'\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
+ {"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, type AddressChange } 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, staysOn } 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 const discards = (change: AddressChange) =>\n !!this.activePage && this.activePage.discards(change, staysOn(this.activePage, change.after.url, change.before.url))\n this.stopAddressGuard = addressController().guard({\n approve: change => (discards(change) ? this.activePage!.canDeactivate(change.signal) : true),\n discards,\n /* Edits a draft holds survive a traversal: they are offered back on return. */\n kept: () => !!this.activePage?.addressEditsKept,\n committed: change => discards(change) && this.activePage!.discardAddressEdits(change)\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"]}
@@ -11,6 +11,11 @@ export type PageLifecycle = {
11
11
  * Subclasses can extend PageView to define custom behavior and handle page lifecycle events.
12
12
  */
13
13
  export declare class PageView extends LitElement {
14
+ /**
15
+ * Closing this page instance (an MDI tab) destroys it, so its unsaved edits are asked about first: the bar
16
+ * removes the tab only on yes. A page switch only caches the instance and asks nothing.
17
+ */
18
+ confirmClose(): Promise<boolean>;
14
19
  private listDrafts;
15
20
  private listDraft;
16
21
  /** True only for the current edit's completed IndexedDB write; an unwritten edit still needs protection. */
@@ -18,14 +23,34 @@ export declare class PageView extends LitElement {
18
23
  private queryChanged;
19
24
  connectedCallback(): void;
20
25
  disconnectedCallback(): void;
21
- /** One page-owned decision, shared by the app dialog and the native traversal adapter. */
26
+ /**
27
+ * Whether `change` would discard unsaved edits, so the shell asks first (address-state-ownership §6.4,
28
+ * 2026-10-19). `stays`: this page instance stays on screen. Grid edits stay in the cached page when another
29
+ * page is shown; they are lost when this page gets new route arguments (every grid reloads) or a new list
30
+ * query (the url-bound grids reload). A page's own unsaved state (`addressDirty`) is asked about whenever the
31
+ * page is left or changed, as `canDeactivate` was before 2026-10-17.
32
+ */
33
+ discards(change: {
34
+ route: boolean;
35
+ query: boolean;
36
+ }, stays: boolean): boolean;
37
+ /** Whether the page's grids hold unsaved edits - only those bound to the address when `urlBound`. */
38
+ protected listDirty(urlBound: boolean): boolean;
39
+ private listGrids;
40
+ /** The question asked when `discards` says so: asked before an app request, or at a traversal's arrival. */
22
41
  get deactivation(): boolean | Parameters<typeof OxPrompt.open>[0];
23
42
  canDeactivate(signal?: AbortSignal): Promise<boolean>;
24
43
  protected get addressDiscardText(): string;
44
+ /** The page's own unsaved state, apart from its grids (a modeller's model). */
25
45
  get addressDirty(): boolean;
26
46
  protected flushAddressEdits(): void;
27
- /** Runs only once approval has actually committed, never while a question is pending or canceled. */
28
- discardAddressEdits(): void;
47
+ /**
48
+ * Runs only once a change `discards` approved has committed, never while a question is pending or canceled.
49
+ * A list query change resets only the url-bound grids: the others keep their edits.
50
+ */
51
+ discardAddressEdits(change?: {
52
+ route: boolean;
53
+ }): void;
29
54
  /**
30
55
  * Determines whether the page should update. This method is called whenever there are
31
56
  * changes to the page's properties.
@@ -89,5 +114,5 @@ export declare class PageView extends LitElement {
89
114
  */
90
115
  get context(): {};
91
116
  }
92
- /** Presentation adapter used only by cancelable native traversal on engines without precommit. */
93
- export declare function approveNativeDeparture(page?: PageView): boolean | 'preserve';
117
+ /** Whether the page shown at `before` stays on screen at `after`: the same path, or a path naming the same page. */
118
+ export declare function staysOn(page: PageView, after: URL, before: URL): boolean;
@@ -85,6 +85,18 @@ export class PageView extends LitElement {
85
85
  */
86
86
  this.active = false;
87
87
  }
88
+ /**
89
+ * Closing this page instance (an MDI tab) destroys it, so its unsaved edits are asked about first: the bar
90
+ * removes the tab only on yes. A page switch only caches the instance and asks nothing.
91
+ */
92
+ async confirmClose() {
93
+ if (!this.addressDirty && !this.listDirty(false))
94
+ return true;
95
+ if (!(await this.canDeactivate()))
96
+ return false;
97
+ this.discardAddressEdits();
98
+ return true;
99
+ }
88
100
  /** True only for the current edit's completed IndexedDB write; an unwritten edit still needs protection. */
89
101
  get addressEditsKept() {
90
102
  this.flushAddressEdits();
@@ -108,9 +120,32 @@ export class PageView extends LitElement {
108
120
  this.listDrafts.clear();
109
121
  this.removeEventListener('list-draft', this.listDraft);
110
122
  }
111
- /** One page-owned decision, shared by the app dialog and the native traversal adapter. */
123
+ /**
124
+ * Whether `change` would discard unsaved edits, so the shell asks first (address-state-ownership §6.4,
125
+ * 2026-10-19). `stays`: this page instance stays on screen. Grid edits stay in the cached page when another
126
+ * page is shown; they are lost when this page gets new route arguments (every grid reloads) or a new list
127
+ * query (the url-bound grids reload). A page's own unsaved state (`addressDirty`) is asked about whenever the
128
+ * page is left or changed, as `canDeactivate` was before 2026-10-17.
129
+ */
130
+ discards(change, stays) {
131
+ if (!change.route && !change.query)
132
+ return false;
133
+ if (this.addressDirty)
134
+ return true;
135
+ return stays && this.listDirty(!change.route);
136
+ }
137
+ /** Whether the page's grids hold unsaved edits - only those bound to the address when `urlBound`. */
138
+ listDirty(urlBound) {
139
+ return this.listGrids(urlBound).some(grid => grid.dirtyRecords?.length);
140
+ }
141
+ listGrids(urlBound) {
142
+ this.flushAddressEdits();
143
+ const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist'));
144
+ return urlBound ? grids.filter(grid => grid.urlParamsSensitive) : grids;
145
+ }
146
+ /** The question asked when `discards` says so: asked before an app request, or at a traversal's arrival. */
112
147
  get deactivation() {
113
- if (!this.addressDirty)
148
+ if (!this.addressDirty && !this.listDirty(false))
114
149
  return true;
115
150
  return {
116
151
  type: 'warning',
@@ -127,19 +162,22 @@ export class PageView extends LitElement {
127
162
  get addressDiscardText() {
128
163
  return i18next.t('text.unsaved-may-be-lost', { defaultValue: 'anything not saved is lost.' });
129
164
  }
165
+ /** The page's own unsaved state, apart from its grids (a modeller's model). */
130
166
  get addressDirty() {
131
- this.flushAddressEdits();
132
- const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist'));
133
- return grids.some(grid => grid.dirtyRecords?.length);
167
+ return false;
134
168
  }
135
169
  flushAddressEdits() {
136
170
  const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist'));
137
171
  grids.forEach(grid => grid.flushEdits?.());
138
172
  }
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());
173
+ /**
174
+ * Runs only once a change `discards` approved has committed, never while a question is pending or canceled.
175
+ * A list query change resets only the url-bound grids: the others keep their edits.
176
+ */
177
+ discardAddressEdits(change) {
178
+ this.listGrids(!!change && !change.route)
179
+ .filter(grid => grid.dirtyRecords?.length)
180
+ .forEach(grid => grid.reset());
143
181
  }
144
182
  /**
145
183
  * Determines whether the page should update. This method is called whenever there are
@@ -286,15 +324,11 @@ __decorate([
286
324
  __decorate([
287
325
  property({ type: String, attribute: 'context-path' })
288
326
  ], 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)
327
+ /** Whether the page shown at `before` stays on screen at `after`: the same path, or a path naming the same page. */
328
+ export function staysOn(page, after, before) {
329
+ if (after.origin === before.origin && after.pathname === before.pathname)
292
330
  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 || ''));
331
+ const name = decodeURIComponent(getPathInfo(after.pathname).path || '').match(/^\/([^\/]+)/)?.[1] || '';
332
+ return !!name && page.getAttribute('data-page') === name;
299
333
  }
300
334
  //# 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, 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"]}
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 /**\n * Closing this page instance (an MDI tab) destroys it, so its unsaved edits are asked about first: the bar\n * removes the tab only on yes. A page switch only caches the instance and asks nothing.\n */\n async confirmClose(): Promise<boolean> {\n if (!this.addressDirty && !this.listDirty(false)) return true\n if (!(await this.canDeactivate())) return false\n this.discardAddressEdits()\n return true\n }\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 /**\n * Whether `change` would discard unsaved edits, so the shell asks first (address-state-ownership §6.4,\n * 2026-10-19). `stays`: this page instance stays on screen. Grid edits stay in the cached page when another\n * page is shown; they are lost when this page gets new route arguments (every grid reloads) or a new list\n * query (the url-bound grids reload). A page's own unsaved state (`addressDirty`) is asked about whenever the\n * page is left or changed, as `canDeactivate` was before 2026-10-17.\n */\n discards(change: { route: boolean; query: boolean }, stays: boolean): boolean {\n if (!change.route && !change.query) return false\n if (this.addressDirty) return true\n return stays && this.listDirty(!change.route)\n }\n\n /** Whether the page's grids hold unsaved edits - only those bound to the address when `urlBound`. */\n protected listDirty(urlBound: boolean): boolean {\n return this.listGrids(urlBound).some(grid => grid.dirtyRecords?.length)\n }\n\n private listGrids(urlBound: boolean) {\n this.flushAddressEdits()\n const grids = Array.from(this.renderRoot.querySelectorAll('ox-grist')) as (HTMLElement & {\n dirtyRecords?: unknown[]\n urlParamsSensitive?: boolean\n reset(): void\n })[]\n return urlBound ? grids.filter(grid => grid.urlParamsSensitive) : grids\n }\n\n /** The question asked when `discards` says so: asked before an app request, or at a traversal's arrival. */\n get deactivation(): boolean | Parameters<typeof OxPrompt.open>[0] {\n if (!this.addressDirty && !this.listDirty(false)) 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 /** The page's own unsaved state, apart from its grids (a modeller's model). */\n get addressDirty(): boolean {\n return false\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 /**\n * Runs only once a change `discards` approved has committed, never while a question is pending or canceled.\n * A list query change resets only the url-bound grids: the others keep their edits.\n */\n discardAddressEdits(change?: { route: boolean }): void {\n this.listGrids(!!change && !change.route)\n .filter(grid => grid.dirtyRecords?.length)\n .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/** Whether the page shown at `before` stays on screen at `after`: the same path, or a path naming the same page. */\nexport function staysOn(page: PageView, after: URL, before: URL): boolean {\n if (after.origin === before.origin && after.pathname === before.pathname) return true\n const name = decodeURIComponent(getPathInfo(after.pathname).path || '').match(/^\\/([^\\/]+)/)?.[1] || ''\n return !!name && page.getAttribute('data-page') === name\n}\n"]}
@@ -17,9 +17,9 @@ export const installRouter = (locationUpdatedCallback) => {
17
17
  if (url.origin !== location.origin)
18
18
  return;
19
19
  event.preventDefault();
20
- const overlay = path.find(node => node.tagName === 'OX-FLOATING-OVERLAY');
20
+ // The anchor is the request's source: inside a popup, that popup is its origin.
21
21
  if (url.href !== location.href)
22
- void writeAddress(url, { fromOverlay: overlay?.name });
22
+ void writeAddress(url, { source: anchor, intent: 'navigation' });
23
23
  };
24
24
  document.body.addEventListener('click', click);
25
25
  const stop = addressController().subscribe(entry => locationUpdatedCallback(entry.url, new Event('address-change')));
@@ -1 +1 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAE3E,uFAAuF;AACvF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,uBAAqE,EAAE,EAAE;IACrG,MAAM,KAAK,GAAG,CAAC,KAAiB,EAAE,EAAE;QAClC,IACE,KAAK,CAAC,gBAAgB;YACtB,KAAK,CAAC,MAAM,KAAK,CAAC;YAClB,KAAK,CAAC,OAAO;YACb,KAAK,CAAC,OAAO;YACb,KAAK,CAAC,QAAQ;YACd,KAAK,CAAC,MAAM;YAEZ,OAAM;QACR,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,EAAE,CAAA;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAA6B,EAAE,CAAC,IAAI,YAAY,iBAAiB,CAAC,CAAA;QAChG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK,UAAU;YAAE,OAAM;QACpG,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;QAClD,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;YAAE,OAAM;QAC1C,KAAK,CAAC,cAAc,EAAE,CAAA;QACtB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAE,IAAoB,CAAC,OAAO,KAAK,qBAAqB,CAC3C,CAAA;QAC9C,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI;YAAE,KAAK,YAAY,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IACxF,CAAC,CAAA;IACD,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC9C,MAAM,IAAI,GAAG,iBAAiB,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAA;IACpH,OAAO,GAAG,EAAE;QACV,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QACjD,IAAI,EAAE,CAAA;IACR,CAAC,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { addressController, writeAddress } from '@operato/utils/address.js'\n\n/** Link requests and committed entry notifications share the same address contract. */\nexport const installRouter = (locationUpdatedCallback: (location: URL, event: Event | null) => void) => {\n const click = (event: MouseEvent) => {\n if (\n event.defaultPrevented ||\n event.button !== 0 ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey ||\n event.altKey\n )\n return\n const path = event.composedPath()\n const anchor = path.find((node): node is HTMLAnchorElement => node instanceof HTMLAnchorElement)\n if (!anchor || anchor.target || anchor.hasAttribute('download') || anchor.rel === 'external') return\n const url = new URL(anchor.href, document.baseURI)\n if (url.origin !== location.origin) return\n event.preventDefault()\n const overlay = path.find(node => (node as HTMLElement).tagName === 'OX-FLOATING-OVERLAY') as\n (HTMLElement & { name: string }) | undefined\n if (url.href !== location.href) void writeAddress(url, { fromOverlay: overlay?.name })\n }\n document.body.addEventListener('click', click)\n const stop = addressController().subscribe(entry => locationUpdatedCallback(entry.url, new Event('address-change')))\n return () => {\n document.body.removeEventListener('click', click)\n stop()\n }\n}\n"]}
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAE3E,uFAAuF;AACvF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,uBAAqE,EAAE,EAAE;IACrG,MAAM,KAAK,GAAG,CAAC,KAAiB,EAAE,EAAE;QAClC,IACE,KAAK,CAAC,gBAAgB;YACtB,KAAK,CAAC,MAAM,KAAK,CAAC;YAClB,KAAK,CAAC,OAAO;YACb,KAAK,CAAC,OAAO;YACb,KAAK,CAAC,QAAQ;YACd,KAAK,CAAC,MAAM;YAEZ,OAAM;QACR,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,EAAE,CAAA;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAA6B,EAAE,CAAC,IAAI,YAAY,iBAAiB,CAAC,CAAA;QAChG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK,UAAU;YAAE,OAAM;QACpG,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;QAClD,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;YAAE,OAAM;QAC1C,KAAK,CAAC,cAAc,EAAE,CAAA;QACtB,gFAAgF;QAChF,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI;YAAE,KAAK,YAAY,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAA;IAClG,CAAC,CAAA;IACD,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC9C,MAAM,IAAI,GAAG,iBAAiB,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAA;IACpH,OAAO,GAAG,EAAE;QACV,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QACjD,IAAI,EAAE,CAAA;IACR,CAAC,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { addressController, writeAddress } from '@operato/utils/address.js'\n\n/** Link requests and committed entry notifications share the same address contract. */\nexport const installRouter = (locationUpdatedCallback: (location: URL, event: Event | null) => void) => {\n const click = (event: MouseEvent) => {\n if (\n event.defaultPrevented ||\n event.button !== 0 ||\n event.metaKey ||\n event.ctrlKey ||\n event.shiftKey ||\n event.altKey\n )\n return\n const path = event.composedPath()\n const anchor = path.find((node): node is HTMLAnchorElement => node instanceof HTMLAnchorElement)\n if (!anchor || anchor.target || anchor.hasAttribute('download') || anchor.rel === 'external') return\n const url = new URL(anchor.href, document.baseURI)\n if (url.origin !== location.origin) return\n event.preventDefault()\n // The anchor is the request's source: inside a popup, that popup is its origin.\n if (url.href !== location.href) void writeAddress(url, { source: anchor, intent: 'navigation' })\n }\n document.body.addEventListener('click', click)\n const stop = addressController().subscribe(entry => locationUpdatedCallback(entry.url, new Event('address-change')))\n return () => {\n document.body.removeEventListener('click', click)\n stop()\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,87 @@
1
+ import { expect, fixture } from '@open-wc/testing';
2
+ import { html } from 'lit';
3
+ import { PageView, staysOn } from '../src/app/pages/page-view.js';
4
+ /**
5
+ * What leaving with unsaved edits asks (address-state-ownership §6.4, ruling 2026-10-19): only a change that would
6
+ * discard them. Grid edits stay in the cached page when another page is shown, as they did before 2026-10-17; a
7
+ * page's own unsaved state (a modeller's model) is asked about whenever it is left, as it was then.
8
+ */
9
+ class ListPage extends PageView {
10
+ render() {
11
+ return html `<ox-grist id="bound"></ox-grist><ox-grist id="detail"></ox-grist>`;
12
+ }
13
+ }
14
+ customElements.define('leaving-list-page', ListPage);
15
+ class ModellerPage extends PageView {
16
+ constructor() {
17
+ super(...arguments);
18
+ this.unsaved = false;
19
+ }
20
+ get addressDirty() {
21
+ return this.unsaved;
22
+ }
23
+ }
24
+ customElements.define('leaving-modeller-page', ModellerPage);
25
+ const query = { route: false, query: true };
26
+ const route = { route: true, query: false };
27
+ const listPage = async (bound, detail) => {
28
+ const page = await fixture(html `<leaving-list-page active></leaving-list-page>`);
29
+ Object.assign(page.renderRoot.querySelector('#bound'), { urlParamsSensitive: true, dirtyRecords: new Array(bound) });
30
+ Object.assign(page.renderRoot.querySelector('#detail'), { dirtyRecords: new Array(detail) });
31
+ return page;
32
+ };
33
+ describe('leaving with unsaved edits', () => {
34
+ it('showing another page asks nothing: the grid edits stay in the cached page', async () => {
35
+ const page = await listPage(1, 1);
36
+ expect(page.discards(route, false)).to.equal(false);
37
+ });
38
+ it('a new query for the url-bound grid that holds edits asks', async () => {
39
+ const page = await listPage(1, 0);
40
+ expect(page.discards(query, true)).to.equal(true);
41
+ });
42
+ it('a new query asks nothing when only a grid not bound to the address holds edits', async () => {
43
+ const page = await listPage(0, 1);
44
+ expect(page.discards(query, true)).to.equal(false);
45
+ });
46
+ it('new route arguments for the page on screen ask about every grid', async () => {
47
+ const page = await listPage(0, 1);
48
+ expect(page.discards(route, true)).to.equal(true);
49
+ });
50
+ it("a page's own unsaved state is asked about when the page is left", async () => {
51
+ const page = await fixture(html `<leaving-modeller-page></leaving-modeller-page>`);
52
+ page.unsaved = true;
53
+ expect(page.discards(route, false)).to.equal(true);
54
+ });
55
+ it('closing the instance asks first when it holds unsaved edits, and answers with the user', async () => {
56
+ class Asking extends ListPage {
57
+ constructor() {
58
+ super(...arguments);
59
+ this.answer = false;
60
+ this.asked = 0;
61
+ }
62
+ async canDeactivate() {
63
+ this.asked++;
64
+ return this.answer;
65
+ }
66
+ }
67
+ customElements.define('leaving-asking-page', Asking);
68
+ const page = await fixture(html `<leaving-asking-page active></leaving-asking-page>`);
69
+ Object.assign(page.renderRoot.querySelector('#detail'), { dirtyRecords: [{}], reset() { } });
70
+ expect(await page.confirmClose()).to.equal(false);
71
+ page.answer = true;
72
+ expect(await page.confirmClose()).to.equal(true);
73
+ expect(page.asked).to.equal(2);
74
+ });
75
+ it('closing a clean instance asks nothing', async () => {
76
+ const page = await listPage(0, 0);
77
+ expect(await page.confirmClose()).to.equal(true);
78
+ });
79
+ it('a change stays on the page when the path is the same, or names the same page', async () => {
80
+ const page = await fixture(html `<leaving-list-page data-page="ledger"></leaving-list-page>`);
81
+ const at = (path) => new URL(path, location.origin);
82
+ expect(staysOn(page, at('/ledger?filters=x'), at('/ledger'))).to.equal(true);
83
+ expect(staysOn(page, at('/ledger/2'), at('/ledger/1'))).to.equal(true);
84
+ expect(staysOn(page, at('/employees'), at('/ledger'))).to.equal(false);
85
+ });
86
+ });
87
+ //# sourceMappingURL=leaving-edits.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leaving-edits.test.js","sourceRoot":"","sources":["../../test/leaving-edits.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture } from '@open-wc/testing'\nimport { html } from 'lit'\n\nimport { PageView, staysOn } from '../src/app/pages/page-view.js'\n\n/**\n * What leaving with unsaved edits asks (address-state-ownership §6.4, ruling 2026-10-19): only a change that would\n * discard them. Grid edits stay in the cached page when another page is shown, as they did before 2026-10-17; a\n * page's own unsaved state (a modeller's model) is asked about whenever it is left, as it was then.\n */\n\nclass ListPage extends PageView {\n render() {\n return html`<ox-grist id=\"bound\"></ox-grist><ox-grist id=\"detail\"></ox-grist>`\n }\n}\ncustomElements.define('leaving-list-page', ListPage)\n\nclass ModellerPage extends PageView {\n unsaved = false\n get addressDirty() {\n return this.unsaved\n }\n}\ncustomElements.define('leaving-modeller-page', ModellerPage)\n\nconst query = { route: false, query: true }\nconst route = { route: true, query: false }\n\nconst listPage = async (bound: number, detail: number) => {\n const page = await fixture<ListPage>(html`<leaving-list-page active></leaving-list-page>`)\n Object.assign(page.renderRoot.querySelector('#bound')!, { urlParamsSensitive: true, dirtyRecords: new Array(bound) })\n Object.assign(page.renderRoot.querySelector('#detail')!, { dirtyRecords: new Array(detail) })\n return page\n}\n\ndescribe('leaving with unsaved edits', () => {\n it('showing another page asks nothing: the grid edits stay in the cached page', async () => {\n const page = await listPage(1, 1)\n expect(page.discards(route, false)).to.equal(false)\n })\n\n it('a new query for the url-bound grid that holds edits asks', async () => {\n const page = await listPage(1, 0)\n expect(page.discards(query, true)).to.equal(true)\n })\n\n it('a new query asks nothing when only a grid not bound to the address holds edits', async () => {\n const page = await listPage(0, 1)\n expect(page.discards(query, true)).to.equal(false)\n })\n\n it('new route arguments for the page on screen ask about every grid', async () => {\n const page = await listPage(0, 1)\n expect(page.discards(route, true)).to.equal(true)\n })\n\n it(\"a page's own unsaved state is asked about when the page is left\", async () => {\n const page = await fixture<ModellerPage>(html`<leaving-modeller-page></leaving-modeller-page>`)\n page.unsaved = true\n expect(page.discards(route, false)).to.equal(true)\n })\n\n it('closing the instance asks first when it holds unsaved edits, and answers with the user', async () => {\n class Asking extends ListPage {\n answer = false\n asked = 0\n async canDeactivate() {\n this.asked++\n return this.answer\n }\n }\n customElements.define('leaving-asking-page', Asking)\n const page = await fixture<Asking>(html`<leaving-asking-page active></leaving-asking-page>`)\n Object.assign(page.renderRoot.querySelector('#detail')!, { dirtyRecords: [{}], reset() {} })\n expect(await page.confirmClose()).to.equal(false)\n page.answer = true\n expect(await page.confirmClose()).to.equal(true)\n expect(page.asked).to.equal(2)\n })\n\n it('closing a clean instance asks nothing', async () => {\n const page = await listPage(0, 0)\n expect(await page.confirmClose()).to.equal(true)\n })\n\n it('a change stays on the page when the path is the same, or names the same page', async () => {\n const page = await fixture<ListPage>(html`<leaving-list-page data-page=\"ledger\"></leaving-list-page>`)\n const at = (path: string) => new URL(path, location.origin)\n expect(staysOn(page, at('/ledger?filters=x'), at('/ledger'))).to.equal(true)\n expect(staysOn(page, at('/ledger/2'), at('/ledger/1'))).to.equal(true)\n expect(staysOn(page, at('/employees'), at('/ledger'))).to.equal(false)\n })\n})\n"]}