@daoyi/nmtl-ui 2.0.1-beta.14 → 2.0.1-beta.140
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.md +45 -45
- package/lib/components/Autocomplete-e40d7145.js +494 -0
- package/lib/components/Autocomplete.js +20 -1
- package/lib/components/Avatar.js +59 -1
- package/lib/components/BackTop.js +124 -1
- package/lib/components/BarChart.js +764 -1
- package/lib/components/Breadcrumbs.js +146 -1
- package/lib/components/Button-8cf35bc0.js +114 -0
- package/lib/components/Button.js +7 -1
- package/lib/components/Carousel.js +4654 -1
- package/lib/components/Checkbox.js +37 -1
- package/lib/components/CollapseContent.js +235 -1
- package/lib/components/ContactModal-af7fa280.js +12295 -0
- package/lib/components/ContactModal.js +24 -3
- package/lib/components/Drawer-b770014f.js +247 -0
- package/lib/components/Drawer.js +18 -1
- package/lib/components/Dropdown.js +134 -1
- package/lib/components/Empty-48685dd0.js +46 -0
- package/lib/components/Empty.js +5 -1
- package/lib/components/ExportButton.js +128 -1
- package/lib/components/ExtraTools-c46c1965.js +3676 -0
- package/lib/components/ExtraTools.js +11 -22
- package/lib/components/Filter.js +821 -12
- package/lib/components/Footer.js +317 -1
- package/lib/components/ForwardLink-2905563c.js +184 -0
- package/lib/components/ForwardLink.js +10 -0
- package/lib/components/Header.js +267 -1
- package/lib/components/Image.js +61 -1
- package/lib/components/Input.js +89 -1
- package/lib/components/InputMethod.js +33937 -10
- package/lib/components/KeywordSearch-4e621ded.js +156 -0
- package/lib/components/KeywordSearch.js +22 -1
- package/lib/components/KeywordTicker.js +224 -1
- package/lib/components/Keywords.js +383 -1
- package/lib/components/Loading.js +32 -1
- package/lib/components/MUITheme.js +2657 -1
- package/lib/components/Modal-aa77d4d8.js +171 -0
- package/lib/components/Modal.js +11 -1
- package/lib/components/MoreButton-0b5aaef3.js +148 -0
- package/lib/components/MoreButton.js +8 -1
- package/lib/components/Pagination.js +3702 -0
- package/lib/components/Radio.js +83 -1
- package/lib/components/SNA.js +1755 -22
- package/lib/components/SegmentedControl-804da0a6.js +113 -0
- package/lib/components/SegmentedControl.js +11 -0
- package/lib/components/Select-979f7e73.js +189 -0
- package/lib/components/Select.js +14 -1
- package/lib/components/Spin-07679812.js +79 -0
- package/lib/components/Spin.js +7 -1
- package/lib/components/Table.js +51 -1
- package/lib/components/Tooltip-bbbaa9c7.js +70 -0
- package/lib/components/Tooltip.js +7 -1
- package/lib/components/_commonjsHelpers-70de2c37.js +28 -0
- package/lib/components/_rollupPluginBabelHelpers-a52356f6.js +142 -0
- package/lib/components/createSvgIcon-370e163a.js +576 -0
- package/lib/components/dataExport-a9e3fae1.js +91 -0
- package/lib/components/debounce-127da66c.js +355 -0
- package/lib/components/defaultTheme-c5dd0f64.js +1661 -0
- package/lib/components/globalConfig.js +471 -0
- package/lib/components/hoist-non-react-statics.cjs-3f408ad2.js +105 -0
- package/lib/components/index-c33afcb5.js +61 -0
- package/lib/components/index-ff95f719.js +481 -0
- package/lib/components/isObjectLike-e111475d.js +190 -0
- package/lib/components/style-inject.es-1f59c1d0.js +28 -1
- package/lib/components/toConsumableArray-c268c112.js +19 -0
- package/lib/components/transform-849a452c.js +5475 -0
- package/lib/components/useTheme-98b6cf17.js +11 -0
- package/lib/components/withTheme-3486f38b.js +6 -0
- package/lib/configs/config.selector.js +151 -0
- package/lib/configs/index.d.ts +1 -0
- package/lib/configs/index.js +1 -0
- package/lib/index.d.ts +6 -1
- package/lib/index.js +6 -1
- package/lib/utils/_rollupPluginBabelHelpers-9802e640.js +121 -0
- package/lib/utils/arrayMerge.js +4953 -1
- package/lib/utils/chunkArray.js +15 -1
- package/lib/utils/convert2HtmlEntities.js +57 -1
- package/lib/utils/domToImage.js +802 -1
- package/lib/utils/downloadGephi.js +106 -1
- package/lib/utils/exportXlsx.js +221 -1
- package/lib/utils/historyAppendSearch.js +502 -1
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/index.js +2 -0
- package/lib/utils/isDevelopMode.js +5 -1
- package/lib/utils/newWindowHint-72ebfe3b.js +53 -0
- package/lib/utils/parseYMD.js +36 -1
- package/lib/utils/prepareTimelineData.js +70 -0
- package/lib/utils/removeDuplicateItem.js +11 -1
- package/lib/utils/sendEmail.js +39 -1
- package/lib/utils/snaDefine-6a2bcd94.js +5 -0
- package/lib/utils/snaDefine.js +1 -1
- package/lib/utils/snaPreProcess.js +84 -1
- package/lib/utils/syncTimelineA11y.js +293 -0
- package/package.json +141 -128
- package/lib/components/Empty-54b79907.js +0 -1
- package/lib/components/KeywordSearch-5a393f12.js +0 -1
- package/lib/components/Select-f2441b83.js +0 -1
- package/lib/components/_rollupPluginBabelHelpers-1b8c042f.js +0 -1
- package/lib/components/_rollupPluginBabelHelpers-ec4e2a53.js +0 -1
- package/lib/components/createSvgIcon-62b64929.js +0 -1
- package/lib/components/createSvgIcon-e24792d4.js +0 -1
- package/lib/components/createTheme-7fffa109.js +0 -1
- package/lib/components/dataExport-9fccd4f0.js +0 -1
- package/lib/components/debounce-c993109b.js +0 -1
- package/lib/components/hoist-non-react-statics.cjs-d6a9befd.js +0 -1
- package/lib/components/index-11391ca3.js +0 -7
- package/lib/components/index-b2745105.js +0 -7
- package/lib/components/isObjectLike-2f1983fe.js +0 -1
- package/lib/components/style-inject.es-c875d022.js +0 -1
- package/lib/components/transform-95ae0119.js +0 -1
- package/lib/utils/_commonjsHelpers-e2cda605.js +0 -1
- package/lib/utils/_rollupPluginBabelHelpers-928a52ce.js +0 -1
|
@@ -1 +1,11 @@
|
|
|
1
|
-
var
|
|
1
|
+
var removeDuplicateItem = function removeDuplicateItem(array) {
|
|
2
|
+
var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'value';
|
|
3
|
+
if (Array.isArray(array)) return array.filter(function (v, i, a) {
|
|
4
|
+
return a.findIndex(function (t) {
|
|
5
|
+
return t[key] === v[key];
|
|
6
|
+
}) === i;
|
|
7
|
+
});
|
|
8
|
+
return [];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export { removeDuplicateItem as default };
|
package/lib/utils/sendEmail.js
CHANGED
|
@@ -1 +1,39 @@
|
|
|
1
|
-
import
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
|
|
3
|
+
// const sendMail = {
|
|
4
|
+
// from: "orient.cc.noreply@gmail.com",
|
|
5
|
+
// to: email,
|
|
6
|
+
// subject: `ATC_${card_id}`+" card status has been changed (Orient-CC)",
|
|
7
|
+
// text: context,
|
|
8
|
+
// };
|
|
9
|
+
//
|
|
10
|
+
// apiUrl: "https://api.daoyidh.com/mail"
|
|
11
|
+
var sendEmail = function sendEmail(sendMail, apiUrl, onSuccess) {
|
|
12
|
+
var timeout = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 10000;
|
|
13
|
+
// timeout
|
|
14
|
+
axios.defaults.timeout = timeout;
|
|
15
|
+
try {
|
|
16
|
+
// axios api
|
|
17
|
+
return axios.post(apiUrl, {
|
|
18
|
+
sendMail: sendMail
|
|
19
|
+
}).then(function (res) {
|
|
20
|
+
return onSuccess({
|
|
21
|
+
state: res && res.status === 200
|
|
22
|
+
});
|
|
23
|
+
}).catch(function (err) {
|
|
24
|
+
console.error('api:axios:catch:error: ', err.message);
|
|
25
|
+
return {
|
|
26
|
+
state: false,
|
|
27
|
+
error: err.message
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
} catch (err) {
|
|
31
|
+
console.error('api:axios:try:catch:error: ', err.message);
|
|
32
|
+
return {
|
|
33
|
+
state: false,
|
|
34
|
+
error: err.message
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export { sendEmail as default };
|
package/lib/utils/snaDefine.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export { s as default } from './snaDefine-6a2bcd94.js';
|
|
@@ -1 +1,84 @@
|
|
|
1
|
-
import{_ as
|
|
1
|
+
import { _ as _toConsumableArray } from './_rollupPluginBabelHelpers-9802e640.js';
|
|
2
|
+
import { s as snaDefine } from './snaDefine-6a2bcd94.js';
|
|
3
|
+
|
|
4
|
+
var snaPreProcess = function snaPreProcess(_ref) {
|
|
5
|
+
var mainNodes = _ref.mainNodes,
|
|
6
|
+
snaData = _ref.snaData;
|
|
7
|
+
if (!mainNodes || !Array.isArray(mainNodes) || !snaData || !Array.isArray(snaData)) {
|
|
8
|
+
// eslint-disable-next-line no-console
|
|
9
|
+
console.log('ERROR: wrong input data.', mainNodes, snaData);
|
|
10
|
+
return {
|
|
11
|
+
nodes: [],
|
|
12
|
+
links: []
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 將所有source、target都建成node 並給予node的type好區分在圖上的圓圈大小與顏色
|
|
17
|
+
var nodes = [];
|
|
18
|
+
snaData.forEach(function (item) {
|
|
19
|
+
var sourceId = item.sourceId,
|
|
20
|
+
sourceType = item.sourceType,
|
|
21
|
+
source = item.source,
|
|
22
|
+
sourceHide = item.sourceHide,
|
|
23
|
+
targetId = item.targetId,
|
|
24
|
+
targetType = item.targetType,
|
|
25
|
+
target = item.target,
|
|
26
|
+
targetHide = item.targetHide;
|
|
27
|
+
|
|
28
|
+
// 避免出現無關聯的 node
|
|
29
|
+
var foundSrc = nodes.find(function (n) {
|
|
30
|
+
return n.id === item.sourceId;
|
|
31
|
+
});
|
|
32
|
+
if (!foundSrc) {
|
|
33
|
+
nodes.push({
|
|
34
|
+
name: source,
|
|
35
|
+
id: sourceId,
|
|
36
|
+
type: mainNodes.indexOf(sourceId) !== -1 ? snaDefine.mainNode : sourceType,
|
|
37
|
+
hasClick: mainNodes.indexOf(sourceId) === -1,
|
|
38
|
+
hide: sourceHide || '0'
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 避免出現無關聯的 node
|
|
43
|
+
var foundTar = nodes.find(function (n) {
|
|
44
|
+
return n.id === item.targetId;
|
|
45
|
+
});
|
|
46
|
+
if (!foundTar) {
|
|
47
|
+
nodes.push({
|
|
48
|
+
name: target,
|
|
49
|
+
id: targetId,
|
|
50
|
+
type: mainNodes.indexOf(targetId) !== -1 ? snaDefine.mainNode : targetType,
|
|
51
|
+
hasClick: mainNodes.indexOf(targetId) === -1,
|
|
52
|
+
hide: targetHide || '0'
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// 刪除重複的node
|
|
58
|
+
var uniqueNodes = _toConsumableArray(new Set(nodes.map(function (item) {
|
|
59
|
+
return JSON.stringify(item);
|
|
60
|
+
}))).map(function (item) {
|
|
61
|
+
return JSON.parse(item);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// 把有關係的node建立link
|
|
65
|
+
var links = [];
|
|
66
|
+
snaData.forEach(function (item) {
|
|
67
|
+
var sourceId = item.sourceId,
|
|
68
|
+
targetId = item.targetId;
|
|
69
|
+
links.push({
|
|
70
|
+
target: uniqueNodes.findIndex(function (uniqueNode) {
|
|
71
|
+
return targetId === uniqueNode.id;
|
|
72
|
+
}),
|
|
73
|
+
source: uniqueNodes.findIndex(function (uniqueNode) {
|
|
74
|
+
return sourceId === uniqueNode.id;
|
|
75
|
+
})
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
nodes: uniqueNodes,
|
|
80
|
+
links: links
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export { snaPreProcess as default };
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { b as _slicedToArray } from './_rollupPluginBabelHelpers-9802e640.js';
|
|
2
|
+
import { getIntl } from '../components/globalConfig';
|
|
3
|
+
|
|
4
|
+
/* 視覺隱藏的播報區(不依賴各站的 .visually-hidden) */
|
|
5
|
+
var VISUALLY_HIDDEN = 'position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;';
|
|
6
|
+
var MENU_BUTTON_LABELS = [['.tl-icon-zoom-in', 'chronology.zoomIn'], ['.tl-icon-zoom-out', 'chronology.zoomOut'], ['.tl-icon-goback', 'chronology.backToStart']];
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 建立後的鍵盤與報讀整理(數位部人工檢測退回 2026-10-07、人工測試回饋 2026-10-08;主站 nmtl-web timelineA11y.js 同步),回傳解除的函式:
|
|
10
|
+
* 1. 只有目前這張投影片可以被 Tab 走到:其餘投影片加 inert
|
|
11
|
+
* 2. 箭頭的 aria-label 拿掉標題連結上的「(另開新視窗)」(箭頭本身不會另開)
|
|
12
|
+
* 3. 焦點順序與畫面一致:上一張 → 投影片內容 → 下一張(套件 DOM 是 內容 → 下一張 → 上一張)
|
|
13
|
+
* 4. 換頁時以 aria-live 播報「第 x 張,共 y 張:年份 標題」(原本焦點留在箭頭上,報讀軟體聽不到換到哪一張)
|
|
14
|
+
* 5. 下方時間刻度的事件標記:原本只能滑鼠點選。改為 tablist/tab(只有目前事件可 Tab 到),
|
|
15
|
+
* 方向鍵/Home/End/PageUp/PageDown 換到對應事件
|
|
16
|
+
* 6. 放大、縮小、回到第一張:原本是沒有名稱的 span,補 role="button"、tabindex、名稱,Enter/空白鍵可操作
|
|
17
|
+
* 8. Google 雲端硬碟預覽器 iframe:tabindex="-1"+aria-hidden(見 prepareTimelineData 檔頭 GN1210200E)
|
|
18
|
+
* 7. 套件在 document 上監聽左右鍵換頁(每建一次就多綁一個、從不移除),焦點在頁籤、搜尋框等時間軸外的元件時
|
|
19
|
+
* 按左右鍵也會換投影片 → 只有焦點在這個時間軸的箭頭上才讓它生效
|
|
20
|
+
* @param {object} timeline new Timeline(...) 的實例
|
|
21
|
+
* @param {HTMLElement} root 時間軸容器
|
|
22
|
+
*
|
|
23
|
+
* 用法:
|
|
24
|
+
* const timeline = new Timeline('timeline-embed', prepareTimelineData(data), options);
|
|
25
|
+
* return syncTimelineA11y(timeline, document.getElementById('timeline-embed'));
|
|
26
|
+
*/
|
|
27
|
+
var syncTimelineA11y = function syncTimelineA11y(timeline, root) {
|
|
28
|
+
if (!timeline || !root) return function () {};
|
|
29
|
+
var t = function t(id, values) {
|
|
30
|
+
return getIntl().formatMessage({
|
|
31
|
+
id: id
|
|
32
|
+
}, values);
|
|
33
|
+
};
|
|
34
|
+
var hint = t('aria.newWindow');
|
|
35
|
+
var text = function text(el) {
|
|
36
|
+
return el ? el.textContent.split(hint).join('').replace(/\s+/g, ' ').trim() : '';
|
|
37
|
+
};
|
|
38
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
39
|
+
var currentIdOf = function currentIdOf() {
|
|
40
|
+
return timeline.current_id || timeline._storyslider && timeline._storyslider.current_id;
|
|
41
|
+
};
|
|
42
|
+
var slides = function slides() {
|
|
43
|
+
return Array.from(root.querySelectorAll('.tl-slide')).filter(function (s) {
|
|
44
|
+
return !s.classList.contains('tl-slide-titleslide');
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
var syncInert = function syncInert(currentId) {
|
|
48
|
+
root.querySelectorAll('.tl-slide').forEach(function (slide) {
|
|
49
|
+
if (slide.id === currentId) slide.removeAttribute('inert');else slide.setAttribute('inert', '');
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
var syncNavLabels = function syncNavLabels() {
|
|
53
|
+
root.querySelectorAll('.tl-slidenav-previous, .tl-slidenav-next').forEach(function (nav) {
|
|
54
|
+
var label = nav.getAttribute('aria-label');
|
|
55
|
+
if (label && label.indexOf(hint) !== -1) nav.setAttribute('aria-label', label.split(hint).join(''));
|
|
56
|
+
/* 箭頭的預覽區(aria-hidden)會複製相鄰投影片的標題,標題裡的站內連結(span role="link" tabindex="0")
|
|
57
|
+
跟著進來,變成「按鈕裡又一個可聚焦的連結」→ 移出 Tab 順序 */
|
|
58
|
+
var previewFocusables = nav.querySelectorAll('.tl-slidenav-content-container a, .tl-slidenav-content-container [tabindex]');
|
|
59
|
+
previewFocusables.forEach(function (el) {
|
|
60
|
+
return el.setAttribute('tabindex', '-1');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
/* 8. Google 雲端硬碟預覽器(iframe):會把 Tab 攔在內部循環(鍵盤陷阱)→ 不讓鍵盤進入、對報讀軟體隱藏,
|
|
65
|
+
改由圖說的「在 Google 雲端硬碟檢視原始檔案」連結提供;滑鼠仍可在頁內縮放、翻頁 */
|
|
66
|
+
var syncIframes = function syncIframes() {
|
|
67
|
+
root.querySelectorAll('.tl-slide iframe[src*="drive.google.com"]').forEach(function (frame) {
|
|
68
|
+
frame.setAttribute('tabindex', '-1');
|
|
69
|
+
frame.setAttribute('aria-hidden', 'true');
|
|
70
|
+
/* 套件會拿圖說(含「在 Google 雲端硬碟檢視原始檔案」連結文字)當 title,改成描述這個預覽器 */
|
|
71
|
+
var slide = frame.closest('.tl-slide');
|
|
72
|
+
var title = t('chronology.drivePreview', {
|
|
73
|
+
title: text(slide && slide.querySelector('.tl-headline:not(.tl-headline-date)'))
|
|
74
|
+
});
|
|
75
|
+
if (frame.getAttribute('title') !== title) frame.setAttribute('title', title);
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/* 3. 「上一張」移到投影片內容之前;兩個箭頭都是絕對定位,畫面不變 */
|
|
80
|
+
var orderNav = function orderNav() {
|
|
81
|
+
var prev = root.querySelector('.tl-slidenav-previous');
|
|
82
|
+
var mask = root.querySelector('.tl-slider-container-mask');
|
|
83
|
+
if (prev && mask && mask.parentNode === prev.parentNode && prev.nextElementSibling !== mask) {
|
|
84
|
+
mask.parentNode.insertBefore(prev, mask);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/* 4. 換頁播報:播報區放在時間軸容器外面(套件重建內容時會清掉容器內不認得的節點) */
|
|
89
|
+
var live = root.nextElementSibling && root.nextElementSibling.classList.contains('tl-a11y-live') ? root.nextElementSibling : null;
|
|
90
|
+
if (!live) {
|
|
91
|
+
live = document.createElement('div');
|
|
92
|
+
live.className = 'tl-a11y-live';
|
|
93
|
+
live.setAttribute('role', 'status');
|
|
94
|
+
live.setAttribute('aria-live', 'polite');
|
|
95
|
+
live.setAttribute('style', VISUALLY_HIDDEN);
|
|
96
|
+
root.parentNode.insertBefore(live, root.nextSibling);
|
|
97
|
+
}
|
|
98
|
+
/* 只在使用者剛操作過時間軸(按鍵、點擊)之後播報:套件初次載入也會觸發 change,不能一進頁面就念 */
|
|
99
|
+
var lastUserAction = 0;
|
|
100
|
+
var markUserAction = function markUserAction() {
|
|
101
|
+
lastUserAction = Date.now();
|
|
102
|
+
};
|
|
103
|
+
var announce = function announce(currentId) {
|
|
104
|
+
if (Date.now() - lastUserAction > 2000) return;
|
|
105
|
+
var list = slides();
|
|
106
|
+
var index = list.findIndex(function (s) {
|
|
107
|
+
return s.id === currentId;
|
|
108
|
+
});
|
|
109
|
+
if (index === -1) return;
|
|
110
|
+
var slide = list[index];
|
|
111
|
+
live.textContent = t('chronology.slideAnnounce', {
|
|
112
|
+
index: index + 1,
|
|
113
|
+
total: list.length,
|
|
114
|
+
date: text(slide.querySelector('.tl-headline-date')),
|
|
115
|
+
title: text(slide.querySelector('.tl-headline:not(.tl-headline-date)'))
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/* 5. 時間刻度標記:tablist/tab */
|
|
120
|
+
var markerContainer = function markerContainer() {
|
|
121
|
+
return root.querySelector('.tl-timenav-item-container');
|
|
122
|
+
};
|
|
123
|
+
var markers = function markers() {
|
|
124
|
+
return Array.from(root.querySelectorAll('.tl-timemarker'));
|
|
125
|
+
};
|
|
126
|
+
var slideIdOf = function slideIdOf(marker) {
|
|
127
|
+
return marker.id.replace(/-marker$/, '');
|
|
128
|
+
};
|
|
129
|
+
var syncMarkers = function syncMarkers(currentId) {
|
|
130
|
+
var container = markerContainer();
|
|
131
|
+
if (!container) return;
|
|
132
|
+
container.setAttribute('role', 'tablist');
|
|
133
|
+
container.setAttribute('aria-label', t('chronology.eventsLabel'));
|
|
134
|
+
markers().forEach(function (marker) {
|
|
135
|
+
var slide = document.getElementById(slideIdOf(marker));
|
|
136
|
+
var selected = slideIdOf(marker) === currentId;
|
|
137
|
+
marker.setAttribute('role', 'tab');
|
|
138
|
+
marker.setAttribute('aria-selected', String(selected));
|
|
139
|
+
marker.setAttribute('aria-controls', slideIdOf(marker));
|
|
140
|
+
marker.setAttribute('tabindex', selected ? '0' : '-1');
|
|
141
|
+
var label = [text(slide && slide.querySelector('.tl-headline-date')), text(marker.querySelector('.tl-headline'))].filter(Boolean).join(' ');
|
|
142
|
+
if (label) marker.setAttribute('aria-label', label);
|
|
143
|
+
/* 標記內的標題常是連結:標記已是 tab,裡面的連結不再各自佔一個 Tab 停點 */
|
|
144
|
+
marker.querySelectorAll('a, button, [tabindex]').forEach(function (el) {
|
|
145
|
+
return el.setAttribute('tabindex', '-1');
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
var focusMarkerAfterChange = false;
|
|
150
|
+
var onMarkerKeyDown = function onMarkerKeyDown(e) {
|
|
151
|
+
var marker = e.target.closest && e.target.closest('.tl-timemarker');
|
|
152
|
+
if (!marker) return;
|
|
153
|
+
var list = markers();
|
|
154
|
+
var index = list.indexOf(marker);
|
|
155
|
+
var last = list.length - 1;
|
|
156
|
+
var target = {
|
|
157
|
+
ArrowRight: Math.min(index + 1, last),
|
|
158
|
+
ArrowLeft: Math.max(index - 1, 0),
|
|
159
|
+
Home: 0,
|
|
160
|
+
End: last,
|
|
161
|
+
PageDown: Math.min(index + 10, last),
|
|
162
|
+
PageUp: Math.max(index - 10, 0)
|
|
163
|
+
}[e.key];
|
|
164
|
+
if (target === undefined) return;
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
if (target === index) return;
|
|
167
|
+
focusMarkerAfterChange = true;
|
|
168
|
+
timeline.goToId(slideIdOf(list[target]));
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/* 6. 放大/縮小/回到第一張 */
|
|
172
|
+
var syncMenuButtons = function syncMenuButtons() {
|
|
173
|
+
MENU_BUTTON_LABELS.forEach(function (_ref) {
|
|
174
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
175
|
+
iconSelector = _ref2[0],
|
|
176
|
+
id = _ref2[1];
|
|
177
|
+
var icon = root.querySelector(".tl-menubar-button ".concat(iconSelector));
|
|
178
|
+
var button = icon && icon.closest('.tl-menubar-button');
|
|
179
|
+
if (!button) return;
|
|
180
|
+
button.setAttribute('role', 'button');
|
|
181
|
+
button.tabIndex = 0;
|
|
182
|
+
button.setAttribute('aria-label', t(id));
|
|
183
|
+
button.setAttribute('aria-disabled', String(button.classList.contains('tl-menubar-button-inactive')));
|
|
184
|
+
icon.setAttribute('aria-hidden', 'true');
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
var onMenuKeyDown = function onMenuKeyDown(e) {
|
|
188
|
+
var button = e.target.closest && e.target.closest('.tl-menubar-button');
|
|
189
|
+
if (!button || e.key !== 'Enter' && e.key !== ' ') return;
|
|
190
|
+
e.preventDefault();
|
|
191
|
+
button.click();
|
|
192
|
+
setTimeout(syncMenuButtons, 0);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/* 7. 套件的全域左右鍵:焦點不在本時間軸的箭頭上就不換頁(時間刻度標記由 5. 自己處理) */
|
|
196
|
+
var blockKeyNav = false;
|
|
197
|
+
/* 套件每建一次時間軸就多綁一個 document 監聽器、從不移除;元件卸載或重建後,舊實例仍會被左右鍵觸發 →
|
|
198
|
+
解除時不還原 goToNext/goToPrev,而是讓舊實例永久停用 */
|
|
199
|
+
var disposed = false;
|
|
200
|
+
var onKeyCapture = function onKeyCapture(e) {
|
|
201
|
+
if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return;
|
|
202
|
+
var onArrow = root.contains(e.target) && e.target.closest('.tl-slidenav-previous, .tl-slidenav-next');
|
|
203
|
+
blockKeyNav = !onArrow;
|
|
204
|
+
};
|
|
205
|
+
var onKeyBubble = function onKeyBubble() {
|
|
206
|
+
blockKeyNav = false;
|
|
207
|
+
};
|
|
208
|
+
var originalNext = timeline.goToNext;
|
|
209
|
+
var originalPrev = timeline.goToPrev;
|
|
210
|
+
/* 套件的監聽器是匿名函式、拿不到也移除不了,只能在它呼叫的 goToNext/goToPrev 上把關 */
|
|
211
|
+
/* eslint-disable no-param-reassign */
|
|
212
|
+
timeline.goToNext = function () {
|
|
213
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
214
|
+
args[_key] = arguments[_key];
|
|
215
|
+
}
|
|
216
|
+
return blockKeyNav || disposed ? undefined : originalNext.apply(timeline, args);
|
|
217
|
+
};
|
|
218
|
+
timeline.goToPrev = function () {
|
|
219
|
+
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
220
|
+
args[_key2] = arguments[_key2];
|
|
221
|
+
}
|
|
222
|
+
return blockKeyNav || disposed ? undefined : originalPrev.apply(timeline, args);
|
|
223
|
+
};
|
|
224
|
+
/* eslint-enable no-param-reassign */
|
|
225
|
+
window.addEventListener('keydown', onKeyCapture, true);
|
|
226
|
+
window.addEventListener('keydown', onKeyBubble);
|
|
227
|
+
root.addEventListener('keydown', onMarkerKeyDown);
|
|
228
|
+
root.addEventListener('keydown', onMenuKeyDown);
|
|
229
|
+
var timer;
|
|
230
|
+
/* changed:只有真正換頁(change 事件)才播報,初次載入與重建不播 */
|
|
231
|
+
var apply = function apply(changed) {
|
|
232
|
+
orderNav();
|
|
233
|
+
syncIframes();
|
|
234
|
+
syncMenuButtons();
|
|
235
|
+
var currentId = currentIdOf();
|
|
236
|
+
/* 剛載入時 current_id 可能還是空的:先不動 inert,避免把畫面上的這張也設成 inert */
|
|
237
|
+
if (currentId) {
|
|
238
|
+
syncInert(currentId);
|
|
239
|
+
syncMarkers(currentId);
|
|
240
|
+
if (changed === true) announce(currentId);
|
|
241
|
+
if (focusMarkerAfterChange) {
|
|
242
|
+
focusMarkerAfterChange = false;
|
|
243
|
+
var marker = document.getElementById("".concat(currentId, "-marker"));
|
|
244
|
+
if (marker) marker.focus({
|
|
245
|
+
preventScroll: true
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
syncNavLabels();
|
|
250
|
+
/* 套件在同一輪事件裡才更新箭頭標題,下一輪再整理一次 */
|
|
251
|
+
clearTimeout(timer);
|
|
252
|
+
timer = setTimeout(syncNavLabels, 0);
|
|
253
|
+
};
|
|
254
|
+
/* 投影片是套件非同步建出來的:建好(loaded)與每次換頁(change)都重新套用 */
|
|
255
|
+
var onChange = function onChange() {
|
|
256
|
+
return apply(true);
|
|
257
|
+
};
|
|
258
|
+
timeline.on('loaded', apply);
|
|
259
|
+
timeline.on('change', onChange);
|
|
260
|
+
root.addEventListener('keydown', markUserAction, true);
|
|
261
|
+
root.addEventListener('click', markUserAction, true);
|
|
262
|
+
/* 套件是非同步分批建出投影片、時間刻度、工具列的(loaded 事件時工具列還沒建好):
|
|
263
|
+
結構有變動就再整理一次(不播報)。自己做的 setAttribute 不會觸發 childList */
|
|
264
|
+
var frame;
|
|
265
|
+
var observer = new MutationObserver(function () {
|
|
266
|
+
cancelAnimationFrame(frame);
|
|
267
|
+
frame = requestAnimationFrame(function () {
|
|
268
|
+
return apply(false);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
observer.observe(root, {
|
|
272
|
+
childList: true,
|
|
273
|
+
subtree: true
|
|
274
|
+
});
|
|
275
|
+
apply();
|
|
276
|
+
return function () {
|
|
277
|
+
clearTimeout(timer);
|
|
278
|
+
timeline.off('loaded', apply);
|
|
279
|
+
timeline.off('change', onChange);
|
|
280
|
+
observer.disconnect();
|
|
281
|
+
cancelAnimationFrame(frame);
|
|
282
|
+
root.removeEventListener('keydown', markUserAction, true);
|
|
283
|
+
root.removeEventListener('click', markUserAction, true);
|
|
284
|
+
disposed = true;
|
|
285
|
+
window.removeEventListener('keydown', onKeyCapture, true);
|
|
286
|
+
window.removeEventListener('keydown', onKeyBubble);
|
|
287
|
+
root.removeEventListener('keydown', onMarkerKeyDown);
|
|
288
|
+
root.removeEventListener('keydown', onMenuKeyDown);
|
|
289
|
+
if (live.parentNode) live.parentNode.removeChild(live);
|
|
290
|
+
};
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
export { syncTimelineA11y as default };
|