1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16export class PageNation {
17  element: unknown;
18  pageInfo: unknown;
19  first: unknown;
20  prev: unknown;
21  next: unknown;
22  last: unknown;
23  inputBox: unknown;
24  btn: unknown;
25  list: unknown;
26  origin: HTMLElement | undefined;
27  static BtnBackColor = '#6C9BFA';
28  static BtnColor = '#fff';
29  constructor(selector: unknown, options = {}) {
30    // @ts-ignore
31    selector!.innerHTML = '';
32    //最大容器
33    this.element = selector;
34    // 默认值
35    this.pageInfo = {
36      current: 1,
37      total: 100,
38      pageSize: 15,
39    };
40    //等待创建的元素
41    this.first = null;
42    this.prev = null;
43    this.next = null;
44    this.last = null;
45    // 输入框
46    this.inputBox = null;
47    // 跳转按钮
48    this.btn = null;
49    // 中间的按钮组
50    this.list = null;
51    this.setPageOptions(options);
52    this.setItemStyles();
53    this.createPageElement();
54    this.bindPageHtml();
55    this.bindPageEvent();
56  }
57
58  setPageOptions(options: unknown): void {
59    // 当前页
60    // @ts-ignore
61    this.pageInfo.current = options.current || 1;
62    // 一页显示多少条
63    // @ts-ignore
64    this.pageInfo.pageSize = options.pageSize || 15; // @ts-ignore
65    if (options.totalpage) {
66      //用户传递了多少页
67      // @ts-ignore
68      this.pageInfo.totalpage = options.totalpage;
69    } else {
70      //没有传递多少页
71      // @ts-ignore
72      if (options.total) {
73        // 如果传递了总条数
74        // @ts-ignore
75        this.pageInfo.totalpage = Math.ceil(options.total / this.pageInfo.pageSize);
76      } else {
77        // 如果没有传递总条数
78        // @ts-ignore
79        this.pageInfo.totalpage = 9;
80      }
81    } // @ts-ignore
82    this.pageInfo.first = options.first || '<<';
83    // @ts-ignore
84    this.pageInfo.change = options.change || function (): void {};
85  }
86
87  setElementStyles(ele: unknown, styles: unknown): void {
88    // @ts-ignore
89    for (let key in styles) {
90      // @ts-ignore
91      ele.style[key] = styles[key];
92    }
93  }
94
95  setItemStyles(): void {
96    this.setElementStyles(this.element, {
97      margin: '18px auto',
98      display: 'flex',
99      alignItems: 'center',
100      justifyContent: 'center',
101    });
102  }
103
104  createElement(jumpDiv: HTMLElement): void {
105    // Create input field
106    this.inputBox = document.createElement('input'); // @ts-ignore
107    this.inputBox.value = this.pageInfo.current;
108    this.setElementStyles(this.inputBox, {
109      width: '35px',
110      height: '30px',
111      textAlign: 'center',
112      outline: 'none',
113      padding: '0',
114      border: '0',
115      'border-radius': '5px',
116    }); // @ts-ignore
117    jumpDiv.appendChild(this.inputBox);
118    let span = document.createElement('span');
119    span.style.width = '1px';
120    span.style.height = '24px';
121    span.style.alignSelf = 'center';
122    span.style.backgroundColor = '#999999';
123    jumpDiv.appendChild(span);
124    // Create button
125    this.btn = document.createElement('button'); // @ts-ignore
126    this.btn.innerText = ''; // @ts-ignore
127    this.btn.name = 'goto';
128    this.setElementStyles(this.btn, {
129      height: '32px',
130      width: '30px',
131      cursor: 'pointer',
132      backgroundColor: '#FFF',
133      border: '0',
134      'border-radius': '5px',
135    }); // @ts-ignore
136    this.btn.style.background = 'url("img/arrowright.png") no-repeat 98% center var(--dark-background3,#FFFFFF)'; // @ts-ignore
137    this.btn.style.backgroundPosition = 'center'; // @ts-ignore
138    jumpDiv.appendChild(this.btn); // @ts-ignore
139    this.element.appendChild(jumpDiv);
140  }
141
142  // 创建元素 首页 上一页 按钮组  下一页 尾页 输入框 按钮
143  createPageElement(): void {
144    //首页
145    this.origin = document.createElement('p');
146    this.setElementStyles(this.origin, {
147      'border-radius': '4px',
148      padding: '5px',
149      border: '1px solid rgba(0,0,0,0.6)',
150      cursor: 'pointer',
151      margin: '0 5px',
152    });
153    this.first = this.origin.cloneNode(true); // @ts-ignore
154    this.first.innerText = this.pageInfo.first; // @ts-ignore
155    this.first.name = 'first'; // @ts-ignore
156    this.element.appendChild(this.first);
157    this.prev = this.origin.cloneNode(true); // @ts-ignore
158    this.prev.innerText = '<'; // @ts-ignore
159    this.prev.name = 'prev'; // @ts-ignore
160    this.prev.style.padding = '5px 10px'; // @ts-ignore
161    this.element.appendChild(this.prev);
162    // 创建ul
163    this.list = document.createElement('ul');
164    this.setElementStyles(this.list, {
165      display: 'flex',
166      padding: '0',
167    }); // @ts-ignore
168    this.element.appendChild(this.list);
169    this.next = this.origin.cloneNode(true); // @ts-ignore
170    this.next.innerText = '>'; // @ts-ignore
171    this.next.name = 'next'; // @ts-ignore
172    this.next.style.padding = '5px 10px'; // @ts-ignore
173    this.next.style.margin = '0px 5px'; // @ts-ignore
174    this.element.appendChild(this.next);
175    this.last = this.origin.cloneNode(true); // @ts-ignore
176    this.last.innerText = '>>'; // @ts-ignore
177    this.last.name = 'last'; // @ts-ignore
178    this.last.style.padding = '5px'; // @ts-ignore
179    this.last.style.margin = '0px 5px'; // @ts-ignore
180    this.element.appendChild(this.last);
181    let jumpDiv = document.createElement('div');
182    jumpDiv.style.display = 'flex';
183    jumpDiv.style.border = '1px solid rgba(0,0,0,0.6)';
184    jumpDiv.style.borderRadius = '4px';
185    jumpDiv.style.width = '70px';
186    jumpDiv.style.height = '32px';
187    jumpDiv.style.marginLeft = '10px';
188
189    this.createElement(jumpDiv);
190  }
191
192  // 判断首页 上一页 下一页 尾页 是否可以点击
193  bindPageHtml(): void {
194    // @ts-ignore
195    const { current, totalpage } = this.pageInfo;
196    const disable = { color: '#999999', cursor: 'not-allowed' };
197    const enable = {
198      color: '#000',
199      cursor: 'pointer',
200    };
201    // 判断当前页是否是第一页  如果是第一页  那么首页和上一页就不能点击
202    if (current <= 1) {
203      this.setElementStyles(this.first, disable);
204      this.setElementStyles(this.prev, disable);
205    } else {
206      this.setElementStyles(this.first, enable);
207      this.setElementStyles(this.prev, enable);
208    }
209    // 判断当前页是否是最后一页  如果是最后一页  那么下一页和尾页就不能点击
210    if (current >= totalpage) {
211      this.setElementStyles(this.next, disable);
212      this.setElementStyles(this.last, disable);
213    } else {
214      this.setElementStyles(this.next, enable);
215      this.setElementStyles(this.last, enable);
216    } // @ts-ignore
217    this.inputBox.value = current;
218    //渲染的时候判断ul列表的显示情况
219    this.bindPageList(); // @ts-ignore
220    this.pageInfo.change(this.pageInfo.current);
221  }
222
223  bindPageList(): void {
224    // @ts-ignore
225    this.list.innerHTML = ''; // clear ul its contents
226    // @ts-ignore
227    const { pageSize, current, totalpage } = this.pageInfo; //Clean the ul before each load
228    const origin = document.createElement('li');
229    origin.dataset.name = 'item';
230    this.setElementStyles(origin, {
231      listStyle: 'none',
232      'border-radius': '4px',
233      border: '1px solid rgba(0,0,0,0.6)',
234      padding: '5px 10px',
235      margin: '0 5px',
236      cursor: 'pointer',
237    });
238    if (totalpage <= 9) {
239      for (let i = 0; i < totalpage; i++) {
240        this.buildLi(origin, i, current);
241      }
242      return;
243    }
244    // Five on the left... Two on the right
245    if (this.bindLeftList(current, totalpage, origin)) {
246      return;
247    }
248    // The current page is larger than 5 pages and smaller than the last 5 pages
249    for (let index = 0; index < 2; index++) {
250      this.buildLi(origin, index, current);
251    }
252    let span = document.createElement('span');
253    span.innerText = '...'; // @ts-ignore
254    this.list.appendChild(span);
255    for (let i = current - 3; i < current + 2; i++) {
256      this.buildLi(origin, i, current);
257    }
258    span = document.createElement('span');
259    span.innerText = '...'; // @ts-ignore
260    this.list.appendChild(span);
261    for (let i = totalpage - 2; i < totalpage; i++) {
262      this.buildLi(origin, i, current);
263    }
264  }
265
266  private buildLi(origin: HTMLElement, i: number, current: number): void {
267    const li = origin.cloneNode(true);
268    // @ts-ignore
269    li.innerText = i + 1;
270    if (i + 1 === current) {
271      this.setElementStyles(li, {
272        backgroundColor: PageNation.BtnBackColor,
273        color: PageNation.BtnColor,
274      });
275    } // @ts-ignore
276    this.list.appendChild(li);
277  }
278
279  bindLeftList(current: number, totalpage: number, origin: HTMLElement): boolean {
280    let span;
281    if (current < 5) {
282      // 左边5个 中间 ... 右边2个
283      for (let index = 0; index < 5; index++) {
284        this.buildLi(origin, index, current);
285      }
286      span = document.createElement('span');
287      span.innerText = '...'; // @ts-ignore
288      this.list.appendChild(span);
289      for (let index = totalpage - 2; index < totalpage; index++) {
290        this.buildLi(origin, index, current);
291      }
292      return true;
293    }
294    if (current === 5) {
295      // 左边5个 中间 ... 右边2个
296      for (let i = 0; i < 7; i++) {
297        this.buildLi(origin, i, current);
298      }
299      span = document.createElement('span');
300      span.innerText = '...'; // @ts-ignore
301      this.list.appendChild(span);
302
303      for (let index = totalpage - 2; index < totalpage; index++) {
304        this.buildLi(origin, index, current);
305      }
306      return true;
307    }
308    // 当前页面 大于倒数第5页
309    if (current > totalpage - 4) {
310      // 左边5个 中间 ... 右边2个
311      for (let index = 0; index < 2; index++) {
312        this.buildLi(origin, index, current);
313      }
314      span = document.createElement('span');
315      span.innerText = '...'; // @ts-ignore
316      this.list.appendChild(span);
317      for (let i = totalpage - 5; i < totalpage; i++) {
318        this.buildLi(origin, i, current);
319      }
320      return true;
321    }
322    if (current === totalpage - 4) {
323      // 左边5个 中间 ... 右边2个
324      this.nodeAppendChild(origin, current, span, totalpage);
325      return true;
326    }
327    return false;
328  }
329
330  nodeAppendChild(origin: HTMLElement, current: number, span: unknown, totalpage: number): void {
331    for (let i = 0; i < 2; i++) {
332      this.buildLi(origin, i, current);
333    }
334    span = document.createElement('span'); // @ts-ignore
335    span.innerText = '...'; // @ts-ignore
336    this.list.appendChild(span);
337    for (let i = totalpage - 7; i < totalpage; i++) {
338      this.buildLi(origin, i, current);
339    }
340  }
341
342  bindPageEvent(): void {
343    // @ts-ignore
344    this.element.addEventListener(
345      'click',
346      (event: {
347        target: {
348          name: string;
349          dataset: { name: string };
350          innerText: number;
351        };
352      }) => {
353        this.targetName(event);
354        if (event.target.name === 'goto') {
355          // 拿到你文本的内容
356          // @ts-ignore
357          let page = this.inputBox.value - 0;
358          if (isNaN(page)) {
359            page = 1;
360          }
361          if (page <= 1) {
362            page = 1;
363          } // @ts-ignore
364          if (page >= this.pageInfo.totalpage) {
365            // @ts-ignore
366            page = this.pageInfo.totalpage;
367          } // @ts-ignore
368          this.pageInfo.current = page;
369          this.bindPageHtml();
370        }
371        if (event.target.dataset.name === 'item') {
372          // @ts-ignore
373          this.pageInfo.current = event.target.innerText - 0;
374          this.bindPageHtml();
375        }
376      }
377    );
378  }
379
380  targetName(event: {
381    target: {
382      name: string;
383      dataset: { name: string };
384      innerText: number;
385    };
386  }): void {
387    if (event.target.name === 'first') {
388      // @ts-ignore
389      if (this.pageInfo.current === 1) {
390        return;
391      } // @ts-ignore
392      this.pageInfo.current = 1;
393      this.bindPageHtml();
394    }
395    if (event.target.name === 'prev') {
396      // @ts-ignore
397      if (this.pageInfo.current === 1) {
398        return;
399      } // @ts-ignore
400      this.pageInfo.current--;
401      this.bindPageHtml();
402    }
403    if (event.target.name === 'next') {
404      // @ts-ignore
405      if (this.pageInfo.current === this.pageInfo.totalpage) {
406        return;
407      } // @ts-ignore
408      this.pageInfo.current++;
409      this.bindPageHtml();
410    }
411    if (event.target.name === 'last') {
412      // @ts-ignore
413      if (this.pageInfo.current === this.pageInfo.totalpage) {
414        return;
415      } // @ts-ignore
416      this.pageInfo.current = this.pageInfo.totalpage;
417      this.bindPageHtml();
418    }
419  }
420}
421