豫言 / 豫言操作系统网页导航 @ 0.1.0

前往或替换当前网址、重载页面,并在同源内压入或替换历史记录。

源码浏览已生成;不能解析的文件以纯文本展示,不表示通过类型检查。

规范.汉语.md

# 网页导航接口规范 0.1.0

本包让浏览器里的豫言应用改变当前页面的地址与历史记录:离开当前页去别处、替换当前地址、重载,以及在**不离开本页**的前提下压入或替换历史记录(用地址栏的查询参数记录“打开了哪个项目、哪个版本”这类状态)。回退与前进产生的 `popstate`、`hashchange` 事件不在本包,用[网页事件接口](../网页事件/规范.汉语.md)订阅“窗口”取得(类型 `历史`)。读取当前完整网址用网页文树包的 `读取页面网址`,解析与改写网址用网址定位(`解析绝对网址部件`、`根据根址解析网址部件`)与网址查询两个包。应用依赖本包后,全部函数都必须实现。

## 地址规则

所有函数的“地址”参数都按**当前页面网址**解析(可以是绝对网址,也可以是 `/路径`、`?查询`、`#锚` 等相对引用),并满足:

- 长度至多 8192 个 UTF-16 码元,不得为空,不得含 ASCII 控制字符(0 至 31、127)和反斜杠;
- 解析后的协议只能是 `http:` 或 `https:`(`javascript:`、`data:`、`blob:`、`file:` 等一律拒绝)。

违规抛豫言事故(中文消息,可捕获)。

## 函数

### `前往网址 : 字符串 → 有`

等价于 `location.assign(地址)`:在历史里留下一条并前往新地址(可以是另一个来源)。页面随即卸载,本次调用之后的应用代码**不保证执行**;需要在离开前做的事(保存草稿等)应在调用之前完成。

### `替换当前网址 : 字符串 → 有`

等价于 `location.replace(地址)`:用新地址替换当前历史记录,后退不会回到旧地址(登录跳转常用)。页面随即卸载。

### `重载页面 : 有 → 有`

等价于 `location.reload()`。页面随即卸载。

### `压入历史 : 字符串 → 有`、`替换历史 : 字符串 → 有`

等价于 `history.pushState(null, '', 地址)` 与 `history.replaceState(null, '', 地址)`:只改地址栏与历史,**不重新载入、不触发 `popstate`**,状态对象恒为 null。地址解析后必须与当前页面**同源**,否则抛事故(浏览器本身也会拒绝)。典型用法:选中一个项目时 `压入历史("/cloud/?project=…")`,筛选变化时 `替换历史(…)`。

### `移动历史 : 整数 → 有`

等价于 `history.go(n)`:负数后退、正数前进;0 无效(重载用 `重载页面`),绝对值至多 50。移动异步完成,浏览器随后触发 `popstate`(同一文档内)或直接卸载页面(离开本文档时)。

## 与其他包的配合

- 读取当前地址:网页文树包 `读取页面网址`、`读取页面查询参数`。
- 拼装带查询的地址:网址查询包(`编码查询串`、`设置网址查询参数`)与网址包(`编码网址成分`)。
- 回退与前进:网页事件包 `订阅界面事件("窗口", "popstate", "{}")`,事件类型 `历史`,详情 `{"网址":当前地址,"状态":null}`。应用收到后自行决定重新读取地址并刷新界面,或调用 `重载页面`。

## 限额与失败

| 项 | 限额 |
| --- | --- |
| 地址长度 | 至多 8192 个 UTF-16 码元 |
| `移动历史` | 1 至 50 或 −50 至 −1 |

违规调用(地址不合规、非同源的压入或替换、步数越界)抛事故;浏览器因页面正在卸载或历史操作过于频繁而拒绝时同样抛事故。宿主已关闭时抛事故。

## 一致性样例

1. 当前页 `https://例.站/cloud/?service=code`:`压入历史("/cloud/?project=甲")` 后 `读取页面网址` 为 `https://例.站/cloud/?project=甲`,`popstate` 不触发;`移动历史(-1)` 后回到原地址,并收到一个类型 `历史`、名称 `popstate` 的事件。
2. `压入历史("https://别处.站/")`:抛事故(非同源)。
3. `前往网址("javascript:alert(1)")`、`前往网址("data:text/html,x")`:抛事故。
4. `前往网址("?panel=终端")` 解析为当前路径加新查询后前往。
5. `替换历史("#锚")` 后地址带 `#锚`,历史条数不变。

## 边界

本包不规定:历史状态对象(恒为 null)、`window.open`(新窗口与弹窗)、`beforeunload` 询问、Navigation API、单页路由库、下载与链接点击(用 `a[href]` 加界面事件)。

规范.文言.md

# 网页导航之约 0.1.0

此包令浏览器中豫言之客改当前页之址与历史:离此而往他处、易当前之址、重载,及**不离本页**而压入或替换历史(以地址栏之查询参数记“开某项目、某版本”之类态)。回退与前进所生之 popstate、hashchange,不在此包,以[网页事件之约](../网页事件/规范.文言.md)订“窗口”得之(类曰历史)。读当前网址全文,用网页文树包之读取页面网址;解与改网址,用网址定位、网址查询二包。客依此包,诸术皆当具。

## 址之律

诸术之“址”参数,皆依**当前页之网址**而解(可为绝对网址,亦可为 `/路径`、`?查询`、`#锚` 等相对之引),且当合:

- 长至多八千一百九十二 UTF-16 码元,不得为空,不得含 ASCII 控制字符(零至三十一、一百二十七)与反斜杠;
- 解后之协议惟 http: 或 https:(javascript:、data:、blob:、file: 等一概拒之)。

违约则发豫言事故(中文辞,可捕)。

## 诸术

### 前往网址:字符串,返有

等于 location.assign(址):于历史留一条而往新址(可他来源)。页随即卸,此调之后客之代码**不保证行**;欲于离前所为(存稿之类)当先于调用完成。

### 替换当前网址:字符串,返有

等于 location.replace(址):以新址易当前历史项,退不复至旧址(登录跳转常用)。页随即卸。

### 重载页面:有,返有

等于 location.reload()。页随即卸。

### 压入历史:字符串,返有;替换历史:字符串,返有

等于 history.pushState(null, '', 址) 与 history.replaceState(null, '', 址):惟改地址栏与历史,**不重载、不触发 popstate**,状态物恒为 null。址解后须与当前页**同源**,否则发事故(浏览器亦拒之)。常法:择一项目则压入历史(“/cloud/?project=…”),筛选变则替换历史。

### 移动历史:整数,返有

等于 history.go(n):负则后退,正则前进;零无效(重载用重载页面),绝对值至多五十。移动异步而成,浏览器随后触发 popstate(同文档内)或径卸其页(离本文档时)。

## 与他包之配

- 读当前址:网页文树包之读取页面网址、读取页面查询参数。
- 拼带查询之址:网址查询包与网址包。
- 回退与前进:网页事件包订阅界面事件(“窗口”,“popstate”,“{}”),事类曰历史,详情 `{"网址":当前址,"状态":null}`。客既收,自决重读址而更界面,或重载页面。

## 限额与败

| 项 | 限 |
| --- | --- |
| 址长 | 至多八千一百九十二 UTF-16 码元 |
| 移动历史 | 一至五十,或负五十至负一 |

违约之调用(址不合、压入或替换非同源、步数越界)发事故;浏览器因页正卸或历史操作过繁而拒之,亦发事故。宿主已闭则发事故。

## 一致性之例

1. 当前页 `https://例.站/cloud/?service=code`:压入历史(“/cloud/?project=甲”)后读取页面网址为 `https://例.站/cloud/?project=甲`,popstate 不发;移动历史(负一)后归原址,并收一类曰历史、名曰 popstate 之事。
2. 压入历史(“https://别处.站/”):发事故(非同源)。
3. 前往网址(“javascript:alert(1)”)、前往网址(“data:text/html,x”):发事故。
4. 前往网址(“?panel=终端”)解为当前路径加新查询而往。
5. 替换历史(“#锚”)后址带 #锚,历史条数不变。

## 界

此包不定:历史状态物(恒 null)、window.open(新窗与弹窗)、beforeunload 之问、Navigation API、单页路由库、下载与链接之点击(用 a[href] 与界面事件)。