hexo-theme-solitude 1.2.1 → 1.2.3

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.
@@ -1,140 +1,164 @@
1
- window.addEventListener('load', () => {
1
+ window.addEventListener("load", () => {
2
+ const $searchMask = document.getElementById("search-mask");
3
+ const $searchDialog = document.querySelector("#algolia-search .search-dialog");
4
+
2
5
  const openSearch = () => {
3
- document.body.style.cssText = 'width: 100%;overflow: hidden'
4
- document.querySelector('#algolia-search .search-dialog').style.display = 'block'
5
- document.querySelector('#algolia-search .ais-SearchBox-input').focus()
6
- utils.fadeIn(document.getElementById('search-mask'), 0.5)
7
- // shortcut: ESC
8
- document.addEventListener('keydown', function f(event) {
9
- if (event.code === 'Escape') {
10
- closeSearch()
11
- document.removeEventListener('keydown', f)
6
+ utils.animateIn($searchMask, "to_show 0.5s");
7
+ $searchDialog.style.display = "block";
8
+ setTimeout(() => {
9
+ document.querySelector("#algolia-search .ais-SearchBox-input").focus();
10
+ }, 100);
11
+ document.addEventListener("keydown", function f(event) {
12
+ if (event.code === "Escape") {
13
+ closeSearch();
14
+ document.removeEventListener("keydown", f);
12
15
  }
13
- })
14
- }
16
+ });
17
+ fixSafariHeight();
18
+ window.addEventListener("resize", fixSafariHeight);
19
+ };
15
20
 
16
21
  const closeSearch = () => {
17
- document.body.style.cssText = "width: '';overflow: ''"
18
- const $searchDialog = document.querySelector('#algolia-search .search-dialog')
19
- $searchDialog.style.animation = 'search_close .5s'
20
- setTimeout(() => {
21
- $searchDialog.style.cssText = "display: none; animation: ''"
22
- }, 500)
23
- utils.fadeOut(document.getElementById('search-mask'), 0.5)
24
- }
22
+ utils.animateOut($searchDialog, "search_close .5s");
23
+ utils.animateOut($searchMask, "to_hide 0.5s");
24
+ window.removeEventListener("resize", fixSafariHeight);
25
+ };
25
26
 
26
- const searchClickFn = () => {
27
- document.querySelector('#search-button > .search').addEventListener('click', openSearch)
28
- document.getElementById('search-mask').addEventListener('click', closeSearch)
29
- document.querySelector('#algolia-search .search-close-button').addEventListener('click', closeSearch)
30
- document.getElementById('menu-search').addEventListener('click', function () {
31
- rm.hideRightMenu();
32
- openSearch();
33
- let t = document.querySelector('.ais-search-box--input');
34
- let evt = new Event('input', {bubbles: true, cancelable: true});
35
- t.value = selectTextNow;
36
- t.dispatchEvent(evt);
37
- });
38
- }
27
+ const fixSafariHeight = () => {
28
+ if (window.innerWidth < 768) {
29
+ $searchDialog.style.setProperty("--search-height", window.innerHeight + "px");
30
+ }
31
+ };
39
32
 
40
- searchClickFn()
33
+ const searchClickFn = () => {
34
+ utils.addEventListenerPjax(document.querySelector("#search-button > .search"), "click", openSearch);
35
+ };
41
36
 
42
- window.addEventListener('pjax:complete', function () {
43
- getComputedStyle(document.querySelector('#algolia-search .search-dialog')).display === 'block' && closeSearch()
44
- searchClickFn()
45
- })
37
+ const searchFnOnce = () => {
38
+ $searchMask.addEventListener("click", closeSearch);
39
+ document.querySelector("#algolia-search .search-close-button").addEventListener("click", closeSearch);
40
+ };
46
41
 
47
- const algolia = GLOBAL_CONFIG.algolia
48
- const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName
42
+ const algolia = GLOBAL_CONFIG.algolia;
43
+ const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName;
49
44
  if (!isAlgoliaValid) {
50
- return console.error('Algolia setting is invalid!')
45
+ return console.error("Algolia setting is invalid!");
51
46
  }
52
47
 
53
- const searchClient = algoliasearch(
54
- algolia.appId,
55
- algolia.apiKey
56
- );
57
-
58
48
  const search = instantsearch({
59
49
  indexName: algolia.indexName,
60
- searchClient,
61
- searchParameters: {
62
- hitsPerPage: algolia.hits.per_page || 10
63
- }
64
- })
65
-
66
- search.addWidget(
67
- instantsearch.widgets.searchBox({
68
- container: '#algolia-search-input',
69
- showReset: false,
70
- placeholder: GLOBAL_CONFIG.lang.search.placeholder,
71
- showSubmit: false,
72
- showLoadingIndicator: true,
73
- templates: {
74
- loadingIndicator: '<i class="scoicon sco-loading-line search-icon"></i>'
75
- },
76
- onStateChange({uiState, setUiState}) {
77
- const searchInput = document.querySelector('#algolia-search-input input')
78
- if (searchInput.value) {
79
- setUiState(uiState);
80
- }
50
+ searchClient: algoliasearch(algolia.appId, algolia.apiKey),
51
+ searchFunction(helper) {
52
+ if (helper.state.query) {
53
+ let innerLoading = '<i class="scoicon sco-loading-line sco-spin"></i>';
54
+ document.getElementById("algolia-hits").innerHTML = innerLoading;
55
+ helper.search();
81
56
  }
82
- })
83
- )
84
- search.addWidget(
85
- instantsearch.widgets.hits({
86
- container: '#algolia-hits',
87
- templates: {
88
- item(hit) {
89
- const link = hit.permalink ? hit.permalink : (GLOBAL_CONFIG.root + hit.path)
90
- return (
91
- `<a href="${link}" class="algolia-hit-item-link">${hit._highlightResult.title.value}</a>`
92
- )
93
- },
94
- empty(data) {
95
- return (
96
- '<div id="algolia-hits-empty">' +
97
- GLOBAL_CONFIG.lang.search.empty.replace(/\$\{query}/, data.query) +
98
- '</div>'
99
- )
57
+ },
58
+ });
59
+
60
+ const configure = instantsearch.widgets.configure({
61
+ hitsPerPage: algolia.hits.per_page ?? 5,
62
+ });
63
+
64
+ const searchBox = instantsearch.widgets.searchBox({
65
+ container: "#algolia-search-input",
66
+ showReset: false,
67
+ showSubmit: false,
68
+ placeholder: GLOBAL_CONFIG.lang.search.placeholder,
69
+ showLoadingIndicator: true,
70
+ searchOnEnterKeyPressOnly: true,
71
+ searchAsYouType: false,
72
+ });
73
+
74
+ const hits = instantsearch.widgets.hits({
75
+ container: "#algolia-hits",
76
+ templates: {
77
+ item(data) {
78
+ const link = data.permalink ? data.permalink : GLOBAL_CONFIG.root + data.path;
79
+ const result = data._highlightResult;
80
+ const loadingLogo = document.querySelector("#algolia-hits .sco-spin");
81
+ if (loadingLogo) {
82
+ loadingLogo.style.display = "none";
100
83
  }
84
+ setTimeout(() => {
85
+ document.querySelector("#algolia-search .ais-SearchBox-input").focus();
86
+ }, 200);
87
+ return `
88
+ <a href="${link}" class="algolia-hit-item-link">
89
+ <span class="algolia-hits-item-title">${result.title.value || "no-title"}</span>
90
+ </a>`;
101
91
  },
102
- cssClasses: {
103
- item: 'algolia-hit-item'
104
- }
105
- })
106
- )
107
-
108
- search.addWidget(
109
- instantsearch.widgets.stats({
110
- container: '#algolia-stats',
111
- templates: {
112
- text(data) {
113
- const stats = GLOBAL_CONFIG.lang.search.hit.replace(/\$\{hits}/, data.nbHits).replace(/\$\{time}/, data.processingTimeMS);
114
- return `${stats}`;
92
+ empty: function (data) {
93
+ const loadingLogo = document.querySelector("#algolia-hits .sco-spin");
94
+ if (loadingLogo) {
95
+ loadingLogo.style.display = "none";
115
96
  }
116
- }
117
- })
118
- )
119
-
120
- search.addWidget(
121
- instantsearch.widgets.pagination({
122
- container: '#algolia-pagination',
123
- scrollTo: false,
124
- showFirst: false,
125
- showPrevious: false,
126
- showNext: false,
127
- showLast: false,
128
- cssClasses: {
129
- list: 'pagination',
130
- pageItem: 'pagination-item',
131
- link: 'page-number',
97
+ setTimeout(() => {
98
+ document.querySelector("#algolia-search .ais-SearchBox-input").focus();
99
+ }, 200);
100
+ return (
101
+ '<div id="algolia-hits-empty">' +
102
+ GLOBAL_CONFIG.lang.search.empty.replace(/\$\{query}/, data.query) +
103
+ "</div>"
104
+ );
105
+ },
106
+ },
107
+ cssClasses: {
108
+ item: "algolia-hit-item",
109
+ },
110
+ });
111
+
112
+ const pagination = instantsearch.widgets.pagination({
113
+ container: "#algolia-pagination",
114
+ totalPages: algolia.hits.per_page ?? 5,
115
+ scrollTo: false,
116
+ showFirstLast: false,
117
+ templates: {
118
+ first: '<i class="scoicon sco-show-left-line"></i>',
119
+ last: '<i class="scoicon sco-show-right-line"></i>',
120
+ previous: '<i class="scoicon sco-arrow-left-bold"></i>',
121
+ next: '<i class="scoicon sco-arrow-right-bold"></i>',
122
+ },
123
+ cssClasses: {
124
+ root: "pagination",
125
+ item: "pagination-item",
126
+ link: "page-number",
127
+ active: "current",
128
+ disabled: "disabled-item",
129
+ },
130
+ });
131
+
132
+ const stats = instantsearch.widgets.stats({
133
+ container: "#algolia-tips > #algolia-stats",
134
+ templates: {
135
+ text: function (data) {
136
+ const stats = GLOBAL_CONFIG.lang.search.hit
137
+ .replace(/\$\{hits}/, data.nbHits)
138
+ .replace(/\$\{time}/, data.processingTimeMS);
139
+ return `<hr>${stats}`;
132
140
  },
133
- })
134
- )
135
- search.start()
136
-
137
- window.pjax && search.on('render', () => {
138
- window.pjax.refresh(document.getElementById('algolia-hits'))
139
- })
140
- })
141
+ },
142
+ });
143
+
144
+ const powerBy = instantsearch.widgets.poweredBy({
145
+ container: "#algolia-tips > #algolia-poweredBy",
146
+ });
147
+
148
+ search.addWidgets([configure, searchBox,stats, hits,powerBy, pagination]); // add the widgets to the instantsearch instance
149
+
150
+ search.start();
151
+
152
+ searchClickFn();
153
+ searchFnOnce();
154
+
155
+ window.addEventListener("pjax:complete", () => {
156
+ !utils.isHidden($searchMask) && closeSearch();
157
+ searchClickFn();
158
+ });
159
+
160
+ window.pjax &&
161
+ search.on("render", () => {
162
+ window.pjax.refresh(document.getElementById("algolia-hits"));
163
+ });
164
+ });
@@ -1,171 +1,146 @@
1
- const $searchMask = document.getElementById('search-mask'),
2
- $searchDialog = document.querySelector('#local-search .search-dialog'),
3
- $input = document.querySelector('#search-input'),
4
- $resultContent = document.getElementById('search-results'),
5
- $loadingStatus = document.getElementById('loading-status')
6
- let dataObj = null
7
-
8
- class search{
9
- static openSearch(){
10
- utils.fadeIn($searchMask, '0.5')
11
- utils.fadeIn($searchDialog, '0.5')
12
- setTimeout(() => { document.querySelector('#search-input').focus() }, 100)
13
- search.search()
14
- document.addEventListener('keydown', function f (event) {
15
- if (event.code === 'Escape') {
16
- closeSearch()
17
- document.removeEventListener('keydown', f)
18
- }
19
- })
20
- }
1
+ window.onload = () => {
2
+ let idx, store = [];
3
+ const $searchMask = document.getElementById("search-mask");
4
+ const $searchDialog = document.querySelector("#local-search .search-dialog");
5
+ const openSearch = () => {
6
+ utils.animateIn($searchMask, "to_show 0.5s");
7
+ $searchDialog.style.display = "block";
8
+ setTimeout(() => {
9
+ document.querySelector("#local-search .search-box-input").focus();
10
+ }, 100);
11
+ document.addEventListener("keydown", function f(event) {
12
+ if (event.code === "Escape") {
13
+ closeSearch();
14
+ document.removeEventListener("keydown", f);
15
+ }
16
+ });
17
+ fixSafariHeight();
18
+ window.addEventListener("resize", fixSafariHeight);
19
+ };
20
+ const fixSafariHeight = () => {
21
+ if (window.innerWidth < 768) {
22
+ $searchDialog.style.setProperty("--search-height", window.innerHeight + "px");
23
+ }
24
+ };
25
+ const closeSearch = () => {
26
+ utils.animateOut($searchDialog, "search_close .5s");
27
+ utils.animateOut($searchMask, "to_hide 0.5s");
28
+ window.removeEventListener("resize", fixSafariHeight);
29
+ };
30
+ utils.addEventListenerPjax(document.querySelector("#search-button > .search"), "click", openSearch);
31
+ utils.addEventListenerPjax(document.querySelector("#local-search .search-close-button"), "click", closeSearch);
32
+ function initLunr() {
33
+ fetch("/search.xml")
34
+ .then(response => response.text())
35
+ .then(data => {
36
+ let parser = new DOMParser();
37
+ let xmlDoc = parser.parseFromString(data, "text/xml");
38
+ let entries = xmlDoc.getElementsByTagName("entry");
39
+ for (let i = 0; i < entries.length; i++) {
40
+ let entry = entries[i];
41
+ let title = entry.getElementsByTagName("title")[0].textContent;
42
+ let link = entry.getElementsByTagName("url")[0].textContent;
43
+ let content = entry.getElementsByTagName("content")[0].textContent;
44
+ store.push({
45
+ 'title': title,
46
+ 'link': link,
47
+ 'content': content
48
+ });
49
+ }
21
50
 
22
- static closeSearch(){
23
- utils.fadeOut($searchDialog, '0.5')
24
- utils.fadeOut($searchMask, '0.5')
25
- }
51
+ idx = lunr(function () {
52
+ this.ref('link');
53
+ this.field('title', {boost: 10});
54
+ this.field('content');
26
55
 
27
- static async fetchData(path){
28
- let data = []
29
- const response = await fetch(path)
30
- const res = await new window.DOMParser().parseFromString(await response.text(), 'text/xml')
31
- data = [...res.querySelectorAll('entry')].map(item => {
32
- return {
33
- title: item.querySelector('title').textContent,
34
- content: item.querySelector('content') && item.querySelector('content').textContent,
35
- url: item.querySelector('url').textContent
36
- }
37
- })
38
- if (response.ok) {
39
- const $loadDataItem = document.getElementById('loading-database')
40
- $loadDataItem.nextElementSibling.style.display = 'block'
41
- $loadDataItem.remove()
56
+ store.forEach(function (doc) {
57
+ this.add(doc);
58
+ }, this);
59
+ });
60
+ })
61
+ .catch(err => console.error("Error loading search data:", err));
42
62
  }
43
- return data
44
- }
45
-
46
- static search(){
47
- if (!GLOBAL_CONFIG.localsearch.preload && dataObj === null) dataObj = this.fetchData(GLOBAL_CONFIG.localsearch.path)
48
- $input.addEventListener('input', function type() {
49
- const keywords = this.value.trim().toLowerCase().split(/[\s]+/)
50
- if (keywords[0] !== '') $loadingStatus.innerHTML = '<i class="scoicon sco-loading-line"></i><span>加载中</span>'
51
- else {
52
- $resultContent.innerHTML = ''
53
- return
54
- }
63
+ let query = ''
64
+ let currentPage = 0;
65
+ const resultsPerPage = 10;
66
+ let results = [];
55
67
 
56
- if (keywords.length <= 0) return
57
- let count = 0, str = '<div class="search-result-list">'
58
- // perform local searching
59
- dataObj.then(data => {
60
- data.forEach(data => {
61
- let isMatch = true
62
- let dataTitle = data.title ? data.title.trim().toLowerCase() : ''
63
- const dataContent = data.content ? data.content.trim().replace(/<[^>]+>/g, '').toLowerCase() : ''
64
- const dataUrl = data.url.startsWith('/') ? data.url : GLOBAL_CONFIG.root + data.url
65
- let indexTitle = -1
66
- let indexContent = -1
67
- let firstOccur = -1
68
- // only match articles with not empty titles and contents
69
- if (dataTitle !== '' || dataContent !== '') {
70
- keywords.forEach((keyword, i) => {
71
- indexTitle = dataTitle.indexOf(keyword)
72
- indexContent = dataContent.indexOf(keyword)
73
- if (indexTitle < 0 && indexContent < 0) {
74
- isMatch = false
75
- } else {
76
- if (indexContent < 0) {
77
- indexContent = 0
68
+ function initUI() {
69
+ const $results = document.getElementById("search-results");
70
+ const $search = document.getElementById("search-input");
71
+ $search.addEventListener('keydown', function (e) {
72
+ if (e.keyCode === 13) {
73
+ $results.innerHTML = '';
74
+ query = this.value;
75
+ results = search(query);
76
+ renderResults(results, currentPage);
77
+ renderPagination(results.length);
78
78
  }
79
- if (i === 0) {
80
- firstOccur = indexContent
81
- }
82
- }
83
- })
84
- } else {
85
- isMatch = false
86
- }
87
-
88
- // show search results
89
- if (isMatch) {
90
- if (firstOccur >= 0) {
91
- // cut out 130 characters
92
- let start = firstOccur - 30
93
- let end = firstOccur + 100
94
- let pre = ''
95
- let post = ''
96
-
97
- if (start < 0) {
98
- start = 0
99
- }
100
-
101
- if (start === 0) {
102
- end = 100
103
- } else {
104
- pre = '...'
105
- }
106
-
107
- if (end > dataContent.length) {
108
- end = dataContent.length
109
- } else {
110
- post = '...'
111
- }
112
-
113
- let matchContent = dataContent.substring(start, end)
114
- // highlight all keywords
115
- keywords.forEach(keyword => {
116
- const regex = new RegExp(`(?!<[^>]*?)(${keyword})(?![^<]*?>)`, 'gi')
117
- matchContent = matchContent.replaceAll(regex, '<span class="search-keyword">$1</span>')
118
- dataTitle = dataTitle.replaceAll(regex, '<span class="search-keyword">$1</span>')
119
- })
120
-
121
- str += '<div class="search__hit-item"><a href="' + dataUrl + '"><span class="search-result-title">' + dataTitle + '</span>'
122
- count += 1
123
- if (dataContent !== '') {
124
- str += '<div class="search-result">' + pre + matchContent + post + '</div>'
125
- }
126
79
  }
127
- str += '</a></div>'
128
- }
129
- })
130
- if (count === 0) {
131
- str += `<div id="search__hits-empty">${GLOBAL_CONFIG.lang.search.empty}</div>`
132
- }else{
133
- str += `<div class="search__hits-count">${GLOBAL_CONFIG.lang.search.hit.replace('${query}', '<span class="search-keyword">' + count + '</span>')}</div>`
80
+ )
81
+ ;
82
+ }
83
+ function search(query) {
84
+ return idx.search(query).map(result => {
85
+ return store.filter(page => {
86
+ return page.link === result.ref;
87
+ })[0];
88
+ });
89
+ }
90
+ function renderResults(results, page) {
91
+ const $search_results = document.getElementById("search-results");
92
+ $search_results.innerHTML = '';
93
+ const $tips = document.getElementById("search-tips")
94
+ $tips.innerHTML = '';
95
+ const start = page * resultsPerPage;
96
+ const end = start + resultsPerPage;
97
+ if (!results.length) {
98
+ const $empty = document.createElement("span");
99
+ $empty.className = "search-result-empty";
100
+ $empty.textContent = GLOBAL_CONFIG.lang.search.empty.replace(/\$\{query}/, query);
101
+ $search_results.appendChild($empty);
102
+ return;
134
103
  }
135
- str += '</div>'
136
- $resultContent.innerHTML = str
137
- if (keywords[0] !== '') $loadingStatus.innerHTML = ''
138
- })
139
- })
140
- }
141
- }
104
+ results.slice(start, end).forEach(function (result) {
105
+ const $result = document.createElement("li");
106
+ $result.className = "search-result-item";
107
+ const $link = document.createElement("a");
108
+ $link.className = "search-result-title";
109
+ $link.href = result.link;
110
+ $link.textContent = result.title;
111
+ $result.appendChild($link);
112
+ $search_results.appendChild($result);
113
+ });
114
+ const count = document.createElement("span");
115
+ count.className = "search-result-count";
116
+ count.innerHTML = `共 <b>${results.length}</b> 条结果`;
117
+ $tips.appendChild(count);
118
+ }
119
+ function renderPagination(totalResults) {
120
+ const totalPages = Math.ceil(totalResults / resultsPerPage);
121
+ const paginationContainer = document.getElementById("search-pagination");
122
+ paginationContainer.innerHTML = '';
123
+ const paginationList = document.createElement("ul");
124
+ paginationList.className = "pagination-list";
142
125
 
143
- const searchClickFn = () => {
144
- if (PAGE_CONFIG.page !== "404") document.querySelector('#search-button > .search').addEventListener('click', search.openSearch)
145
- GLOBAL_CONFIG.rightmenu.enable && document.getElementById('menu-search').addEventListener('click', function() {
146
- rm.hideRightMenu();
147
- search.openSearch();
148
- let t = document.getElementsByClassName('search-box-input')[0];
149
- let evt = new Event('input', {
150
- bubbles: true,
151
- cancelable: true
126
+ for (let i = 0; i < totalPages; i++) {
127
+ const button = document.createElement("li");
128
+ button.className = "pagination-item";
129
+ button.textContent = i + 1;
130
+ if (i === currentPage) {
131
+ button.classList.add('select');
132
+ }
133
+ button.addEventListener('click', function () {
134
+ currentPage = i;
135
+ renderResults(results, i);
136
+ });
137
+ paginationList.appendChild(button);
138
+ }
139
+ paginationContainer.appendChild(paginationList);
140
+ }
141
+ initLunr();
142
+ initUI();
143
+ window.addEventListener('DOMContentLoaded', (event) => {
144
+ initUI();
152
145
  });
153
- t.value = selectTextNow;
154
- t.dispatchEvent(evt);
155
- })
156
- }
157
-
158
- const searchClickFnOnce = () => {
159
- document.querySelector('#local-search .search-close-button').addEventListener('click', search.closeSearch)
160
- $searchMask.addEventListener('click', search.closeSearch)
161
- if (GLOBAL_CONFIG.localsearch.preload) dataObj = search.fetchData(GLOBAL_CONFIG.localsearch.path)
162
- }
163
-
164
- window.addEventListener('load', () => {
165
- searchClickFn()
166
- searchClickFnOnce()
167
- })
168
-
169
- window.addEventListener('pjax:complete', () => {
170
- searchClickFn()
171
- })
146
+ }
@@ -143,5 +143,34 @@ const utils = {
143
143
  })
144
144
  },
145
145
  isMobile: () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
146
- isHidden: e => 0 === e.offsetHeight && 0 === e.offsetWidth
146
+ isHidden: e => 0 === e.offsetHeight && 0 === e.offsetWidth,
147
+ addEventListenerPjax: function (element, eventType, callback, useCapture = false) {
148
+ element.addEventListener(eventType, callback, useCapture);
149
+ utils.addGlobalFn("pjax", function () {
150
+ element.removeEventListener(eventType, callback, useCapture);
151
+ });
152
+ },
153
+ addGlobalFn: (key, fn, name = false, parent = window) => {
154
+ const globalFn = parent.globalFn || {}
155
+ const keyObj = globalFn[key] || {}
156
+
157
+ if (name && keyObj[name]) return
158
+
159
+ name = name || Object.keys(keyObj).length
160
+ keyObj[name] = fn
161
+ globalFn[key] = keyObj
162
+ parent.globalFn = globalFn
163
+ },
164
+ animateIn: (ele, text) => {
165
+ ele.style.display = 'block'
166
+ ele.style.animation = text
167
+ },
168
+ animateOut: (ele, text) => {
169
+ ele.addEventListener('animationend', function f() {
170
+ ele.style.display = ''
171
+ ele.style.animation = ''
172
+ ele.removeEventListener('animationend', f)
173
+ })
174
+ ele.style.animation = text
175
+ }
147
176
  }