haori 0.16.0 → 0.17.0

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/README.ja.md CHANGED
@@ -101,6 +101,7 @@ Haori.mount(document.body, {items: [{name: 'りんご'}, {name: 'みかん'}]});
101
101
  - `data-fetch` — サーバーからデータを取得してバインド
102
102
  - `data-import` — 外部 HTML を読み込んで挿入
103
103
  - `data-url-param` — URL のクエリパラメータをバインディングに取り込む
104
+ - `data-unauthorized-redirect` / `data-forbidden-redirect` — `<body>`/`<html>` に宣言する認証ガード。Haori の fetch 応答が 401/403 のとき指定 URL(式可)へ遷移します。全 fetch 経路(`data-fetch`・イベント fetch・`data-import`)に適用。ステータス別オプトイン(旧 `data-login` 相当)。
104
105
 
105
106
  追加のバインディング補助:
106
107
 
@@ -111,6 +112,7 @@ Haori.mount(document.body, {items: [{name: 'りんご'}, {name: 'みかん'}]});
111
112
 
112
113
  - `data-click-*`・`data-change-*`・`data-input-*`・`data-load-*`・`data-intersect-*` は、それぞれクリック・フォーム変更・逐次入力・要素ロード・ビューポート交差を契機に処理(fetch、bind、copy、ダイアログ操作など)を宣言します。`data-load-*` は `data-if` 要素が非表示→表示へ遷移した(`haori:show`)タイミングでも発火するため、ネイティブの `load` が発生しない `<button>` などでも利用できます。
113
114
  - `data-input-*` — テキスト入力1文字ごと(`input` イベント)に手続きを起動します。逐次発火するため `data-input-*` を**明示した要素のみ**が対象(オプトイン)で、`change` 同様に先祖フォームを自動検出して双方向バインディングへ反映します。検索欄の逐次絞り込みなどに使えます(例: `<input name="q" data-input-form>`)。
115
+ - `data-on="イベント名"` + `data-on-*` — `window` / `document` へ dispatch された**任意のカスタムイベント**を契機に手続きを起動します(アクション語彙は `data-{event}-*` と共通)。ネイティブ橋の準備完了通知など、組み込みイベント以外での初期化を宣言的に書けます(例: `<body data-on="kanadeAPIReady" data-on-fetch="/api/init.json" data-on-bind="#app">`)。イベント名は属性値で保持(属性名の小文字化対策)、`window` キャプチャ1本で二重発火なく購読、後挿入要素も追従。組み込みイベント名(click/change/input/load)は警告し購読しません。Haori 購読開始前に発火したイベントは受け取れない点に注意。
114
116
  - `data-click-copy-source` — `data-click-copy` のコピー元要素を明示指定します(既定は `data-click-form` のフォーム、無ければイベント発火元の binding)。
115
117
  - `data-click-no-disabled` / `data-click-defer` — 他ライブラリとの併用補助です。`no-disabled` はクリック手続き実行中に `disabled` 属性を付与せず実行します(Bootstrap collapse など disabled 要素を無視するライブラリ・CSS が動作し続けます。多重実行は内部マーカーで防止)。`defer` はクリック手続きを次フレーム(`requestAnimationFrame`/`setTimeout(0)`)で実行し、他ライブラリの同期 click ハンドラを先に完了させます。遅延後は `preventDefault()` できないため、`<a href>` や `type="submit"` への `defer` 併用は避けてください。
116
118
  - `data-{event}-prevent`(例: `data-click-prevent`)— そのイベントでブラウザのネイティブなデフォルト動作(`type="submit"` ボタンのフォーム送信、`<a href>` の遷移など)を抑止します。`preventDefault()` はクリックの同期区間で呼ぶため `data-click-defer` と併用しても確実に抑止でき、`stopPropagation()` は呼ばないので他ライブラリのイベント伝播には影響しません。これにより `type="submit"` のまま `data-click-fetch` 等を付けても、ページ再読込なしに動作します。
@@ -122,7 +124,9 @@ Haori.mount(document.body, {items: [{name: 'りんご'}, {name: 'みかん'}]});
122
124
  - `haori:bindcomplete` — `data-*-bind` / `data-*-bind-arg` によるバインドと、対象要素配下の再評価が完了した後に対象要素で発火します(`detail.bindArg`)。
123
125
  - `haori:show` / `haori:hide` — `data-if` 要素の表示・非表示時に発火します。
124
126
 
125
- 式中では予約名前空間 `haori` の組み込みヘルパーを利用できます。`haori.date(value, format?)` は ISO 文字列・エポックミリ秒・`Date` を整形し(既定 `yyyy/MM/dd HH:mm`、ローカル時刻)、`haori.number(value, decimals?)` は桁区切り付きで数値を整形、`haori.range(start, end?, step?)` は整数配列を生成し(終端排他)、`haori.pages(totalPages, current, {window?, boundary?})` は省略記号付きの番号ページ列を生成します(`current` は 0 始まり。各要素は `{page, label, active, ellipsis}` を持ち `label` は `page + 1`)。月別 UI 向けに、`haori.monthAdd(value, delta)` は `YYYY-MM` 形式の年月へ月数を加算し(`Date` を介さない整数演算でタイムゾーン非依存。不正な入力は空文字)、`haori.monthRange(count, base?)` は基準月から降順に `count + 1` 個の `{targetMonth, label}` を返します(`base` 省略時は現在月)。ページ件数表示向けに、`haori.pageSummary(page, visibleCount?)` は Spring の `Page` 相当(`number`・`size`・`totalElements`/`totalCount`)から `{start, end, total, empty}` を計算します。`haori.findBy(array, key, value)` は配列から `item[key]` が `value` に一致する最初の要素(文字列化比較)を返し、無ければ `null` を返します。これにより番号ページネーション(`data-each="haori.pages(totalPages, number, {window: 2})"`)や値の整形(`{{ haori.date(lastUpdatedAt, 'yyyy/MM/dd HH:mm') }}`)を宣言的に書けます。同じ関数は `Haori.date` / `Haori.number` / `Haori.range` / `Haori.pages` / `Haori.monthAdd` / `Haori.monthRange` / `Haori.pageSummary` / `Haori.findBy` としても公開されています。`haori` は予約名のため、同名の `data-bind` キーを与えても式中では組み込みが優先されます。
127
+ 式中では予約名前空間 `haori` の組み込みヘルパーを利用できます。`haori.date(value, format?)` は ISO 文字列・エポックミリ秒・`Date` を整形し(既定 `yyyy/MM/dd HH:mm`、ローカル時刻)、`haori.number(value, decimals?)` は桁区切り付きで数値を整形、`haori.range(start, end?, step?)` は整数配列を生成し(終端排他)、`haori.pages(totalPages, current, {window?, boundary?})` は省略記号付きの番号ページ列を生成します(`current` は 0 始まり。各要素は `{page, label, active, ellipsis}` を持ち `label` は `page + 1`)。月別 UI 向けに、`haori.monthAdd(value, delta)` は `YYYY-MM` 形式の年月へ月数を加算し(`Date` を介さない整数演算でタイムゾーン非依存。不正な入力は空文字)、`haori.monthRange(count, base?)` は基準月から降順に `count + 1` 個の `{targetMonth, label}` を返します(`base` 省略時は現在月)。ページ件数表示向けに、`haori.pageSummary(page, visibleCount?)` は Spring の `Page` 相当(`number`・`size`・`totalElements`/`totalCount`)から `{start, end, total, empty}` を計算します。`haori.findBy(array, key, value)` は配列から `item[key]` が `value` に一致する最初の要素(文字列化比較)を返し、無ければ `null` を返します。`haori.sum(array, key?)` は配列の数値合計を返します(`key` 省略時は要素自体、指定時は `item[key]`、数値化できない値は無視、非配列は `0`)。これにより番号ページネーション(`data-each="haori.pages(totalPages, number, {window: 2})"`)・値の整形(`{{ haori.date(lastUpdatedAt, 'yyyy/MM/dd HH:mm') }}`)・集計行(`{{ haori.number(haori.sum(rows, 'total')) }}`)を宣言的に書けます。同じ関数は `Haori.date` / `Haori.number` / `Haori.range` / `Haori.pages` / `Haori.monthAdd` / `Haori.monthRange` / `Haori.pageSummary` / `Haori.findBy` / `Haori.sum` としても公開されています。`haori` は予約名のため、同名の `data-bind` キーを与えても式中では組み込みが優先されます。
128
+
129
+ JS からバインドデータを読むには `Haori.Core.getBindingData(element, {resolved?})` を使います。既定では要素自身の生バインドデータ(無ければ `null`)、`resolved: true` で継承を解決済みのスコープを返します(`setBindingData` の対となる読み取り API)。
126
130
 
127
131
  テンプレート式では、プロパティアクセス、動的インデックスを含むブラケットアクセス、optional chaining、三項演算子、配列 `map` / `filter` のアロー関数、spread を伴う呼び出しなどの安全な構文を利用できます。一方で、グローバルオブジェクト、`eval` や `arguments`、`constructor`、`__proto__`、`prototype`、`Reflect`、`Object` などの脱出経路は使用できません。`Object` がブロックされるため、`Object.assign` の代わりにスプレッド構文 `{...a, ...b}` を使ってください。ブロックされた識別子を式で参照すると、コンソールに `blocked identifier(s): …` という警告が出力されます。
128
132
 
package/README.md CHANGED
@@ -101,6 +101,7 @@ Haori.mount(document.body, {items: [{name: 'apple'}, {name: 'orange'}]});
101
101
  - `data-fetch` — fetch data from a server and bind the result
102
102
  - `data-import` — load external HTML and insert it
103
103
  - `data-url-param` — import URL query parameters into bindings
104
+ - `data-unauthorized-redirect` / `data-forbidden-redirect` — auth guard declared on `<body>`/`<html>`. When a Haori fetch responds 401/403, navigate to the given URL (expressions allowed). Applies to all fetch paths (`data-fetch`, event fetches, `data-import`); per-status opt-in (the `data-login` equivalent).
104
105
 
105
106
  Additional binding helpers:
106
107
 
@@ -111,6 +112,7 @@ Event-driven actions:
111
112
 
112
113
  - `data-click-*`, `data-change-*`, `data-input-*`, `data-load-*`, `data-intersect-*` declare actions (fetch, bind, copy, dialog control, etc.) triggered by click, form change, incremental input, element load, and viewport intersection respectively. `data-load-*` also fires when a `data-if` element transitions from hidden to shown (the `haori:show` timing), so it works on elements like `<button>` that never receive a native `load` event.
113
114
  - `data-input-*` — run a procedure on each keystroke (the `input` event) for text inputs. Because `input` fires incrementally, only elements that explicitly declare a `data-input-*` attribute are handled (opt-in); like `change`, it auto-detects the ancestor form and reflects the value into two-way bindings. Useful for incremental search filtering (e.g. `<input name="q" data-input-form>`).
115
+ - `data-on="eventName"` + `data-on-*` — run a procedure when an arbitrary **custom event** dispatched on `window` / `document` fires (the action vocabulary is shared with `data-{event}-*`). Lets you declaratively initialize on events other than the built-ins, e.g. a native-bridge ready signal (`<body data-on="kanadeAPIReady" data-on-fetch="/api/init.json" data-on-bind="#app">`). The event name is held in the attribute value (attribute names are lowercased), a single `window` capture subscription receives both `window`- and `document`-dispatched events without double-firing, and elements inserted later are picked up too. Built-in names (click/change/input/load) are warned and not subscribed. Note: events dispatched before Haori subscribes are not received (no replay).
114
116
  - `data-click-copy-source` — explicitly set the copy source element for `data-click-copy` (defaults to the form given by `data-click-form`, otherwise the event element's binding).
115
117
  - `data-click-no-disabled` / `data-click-defer` — coexistence helpers for other libraries. `no-disabled` runs the click procedure without adding the `disabled` attribute (so libraries/CSS that ignore disabled elements, e.g. Bootstrap collapse, keep working; double execution is still prevented internally). `defer` runs the click procedure on the next frame (`requestAnimationFrame`/`setTimeout(0)`) so other libraries' synchronous click handlers complete first. Avoid `defer` on `<a href>` / `type="submit"` because the deferred procedure cannot `preventDefault()` the default action.
116
118
  - `data-{event}-prevent` (e.g. `data-click-prevent`) — suppress the browser's native default action for the event (form submission for a `type="submit"` button, navigation for `<a href>`). `preventDefault()` is called synchronously during the click, so it works even together with `data-click-defer`, and `stopPropagation()` is never called (other libraries' event propagation is unaffected). This lets you keep `type="submit"` and still attach `data-click-fetch` etc. without the page reloading.
@@ -122,7 +124,9 @@ Lifecycle events:
122
124
  - `haori:bindcomplete` — fired on the target element after a `data-*-bind` / `data-*-bind-arg` bind and the subsequent re-evaluation of its subtree complete (`detail.bindArg`).
123
125
  - `haori:show` / `haori:hide` — fired when a `data-if` element becomes shown or hidden.
124
126
 
125
- Built-in helpers are available in expressions under the reserved namespace `haori`: `haori.date(value, format?)` formats an ISO string / epoch ms / `Date` (default `yyyy/MM/dd HH:mm`, local time), `haori.number(value, decimals?)` formats numbers with grouping, `haori.range(start, end?, step?)` builds an integer array (end-exclusive), and `haori.pages(totalPages, current, {window?, boundary?})` builds an ellipsis-aware page list (`current` is 0-based; each item exposes `{page, label, active, ellipsis}` with `label` = `page + 1`). For month-based UIs, `haori.monthAdd(value, delta)` adds months to a `YYYY-MM` string (timezone-safe integer math; invalid input returns `''`) and `haori.monthRange(count, base?)` builds a descending list of `count + 1` `{targetMonth, label}` items (`base` defaults to the current month). For pagination summaries, `haori.pageSummary(page, visibleCount?)` turns a Spring-style `Page` (`number`, `size`, `totalElements` / `totalCount`) into `{start, end, total, empty}`. `haori.findBy(array, key, value)` returns the first array element whose `item[key]` matches `value` (stringified comparison), or `null` when none match. These let you build number pagination (`data-each="haori.pages(totalPages, number, {window: 2})"`) and format values (`{{ haori.date(lastUpdatedAt, 'yyyy/MM/dd HH:mm') }}`) declaratively. The same functions are exposed as `Haori.date` / `Haori.number` / `Haori.range` / `Haori.pages` / `Haori.monthAdd` / `Haori.monthRange` / `Haori.pageSummary` / `Haori.findBy`. `haori` is reserved: a `data-bind` key of the same name does not shadow the built-ins inside expressions.
127
+ Built-in helpers are available in expressions under the reserved namespace `haori`: `haori.date(value, format?)` formats an ISO string / epoch ms / `Date` (default `yyyy/MM/dd HH:mm`, local time), `haori.number(value, decimals?)` formats numbers with grouping, `haori.range(start, end?, step?)` builds an integer array (end-exclusive), and `haori.pages(totalPages, current, {window?, boundary?})` builds an ellipsis-aware page list (`current` is 0-based; each item exposes `{page, label, active, ellipsis}` with `label` = `page + 1`). For month-based UIs, `haori.monthAdd(value, delta)` adds months to a `YYYY-MM` string (timezone-safe integer math; invalid input returns `''`) and `haori.monthRange(count, base?)` builds a descending list of `count + 1` `{targetMonth, label}` items (`base` defaults to the current month). For pagination summaries, `haori.pageSummary(page, visibleCount?)` turns a Spring-style `Page` (`number`, `size`, `totalElements` / `totalCount`) into `{start, end, total, empty}`. `haori.findBy(array, key, value)` returns the first array element whose `item[key]` matches `value` (stringified comparison), or `null` when none match. `haori.sum(array, key?)` returns the numeric total of an array (the elements themselves when `key` is omitted, or `item[key]`; non-numeric values are ignored; non-arrays yield `0`). These let you build number pagination (`data-each="haori.pages(totalPages, number, {window: 2})"`), format values (`{{ haori.date(lastUpdatedAt, 'yyyy/MM/dd HH:mm') }}`), and total rows (`{{ haori.number(haori.sum(rows, 'total')) }}`) declaratively. The same functions are exposed as `Haori.date` / `Haori.number` / `Haori.range` / `Haori.pages` / `Haori.monthAdd` / `Haori.monthRange` / `Haori.pageSummary` / `Haori.findBy` / `Haori.sum`. `haori` is reserved: a `data-bind` key of the same name does not shadow the built-ins inside expressions.
128
+
129
+ To read binding data from JS, use `Haori.Core.getBindingData(element, {resolved?})` — by default it returns the element's own raw binding data (or `null`), and with `resolved: true` it returns the scope with inheritance resolved (the read counterpart to `setBindingData`).
126
130
 
127
131
  Template expressions support safe JavaScript-like syntax such as property access, bracket access with dynamic indexes, optional chaining, ternary expressions, and method chains including array `map`/`filter` with arrow functions and spread calls. Access to global objects, `eval` or `arguments`, and prototype escape paths such as `constructor`, `__proto__`, `prototype`, `Reflect`, or `Object` is blocked. Because `Object` is blocked, use spread syntax `{...a, ...b}` instead of `Object.assign`; when a blocked identifier is referenced in an expression, a `blocked identifier(s): …` warning is logged to the console.
128
132