saby-customizer 0.0.0-pre.28 → 0.0.0-pre.32

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.
@@ -0,0 +1,17 @@
1
+ import { toolbar } from 'saby-customizer/lib.js'
2
+ import { octicons } from 'saby-customizer/octicons.js'
3
+ import { GitBranchCardData } from 'saby-customizer/features/git-branch.js'
4
+
5
+
6
+ toolbar.addButton({
7
+ position: 'top',
8
+ title: 'Скопировать ссылку на карточку',
9
+ iconSVG: octicons.link.toSVG({ width: 18 }),
10
+ onclick: card => {
11
+ const gitCard = new GitBranchCardData(card.data)
12
+
13
+ gitCard.restoreFromHistory()
14
+ .then(() => gitCard.copyLink())
15
+ .catch(console.error)
16
+ }
17
+ })
@@ -4,7 +4,7 @@ import { octicons } from 'saby-customizer/octicons.js'
4
4
 
5
5
 
6
6
  /** Класс для управления данными карточки задачи */
7
- class GitBranchCardData {
7
+ export class GitBranchCardData {
8
8
 
9
9
  /**
10
10
  * @typedef GitCardData
@@ -55,9 +55,7 @@ class GitBranchCardData {
55
55
  * @param {string} value Версия
56
56
  */
57
57
  set version(value) {
58
- if (this.raw.milestones && this.raw.milestones.includes(value)) {
59
- this.raw.version = value
60
- }
58
+ this.raw.version = value || this.raw.version
61
59
  }
62
60
 
63
61
  /** @returns {string} Часть имени ветки, зависящая от регламента задачи */
@@ -182,6 +180,17 @@ class GitBranchCardData {
182
180
  }
183
181
  }
184
182
 
183
+ /**
184
+ * Удаление карточки задачи из истории
185
+ *
186
+ * @param {number} primaryKey Ид записи в истории
187
+ */
188
+ async removeFromHistory(primaryKey) {
189
+ const gitBranchHistory = db.table('gitBranchHistory')
190
+
191
+ await gitBranchHistory.delete(primaryKey)
192
+ }
193
+
185
194
  }
186
195
 
187
196
  /** Карточка со сведениями о задаче для копирования ветки */
@@ -208,6 +217,10 @@ class GitBranchCard extends oom.extends(HTMLElement) {
208
217
  whiteSpace: 'nowrap',
209
218
  textOverflow: 'ellipsis'
210
219
  },
220
+ '.history-info': {
221
+ fontSize: '13px',
222
+ fontStyle: 'italic'
223
+ },
211
224
  '.link': {
212
225
  fontSize: '14px',
213
226
  color: 'var(--mdc-theme-primary, #6200ee)'
@@ -234,6 +247,7 @@ class GitBranchCard extends oom.extends(HTMLElement) {
234
247
  marginBottom: '-1px',
235
248
  cursor: 'pointer',
236
249
  color: 'var(--mdc-theme-primary, #6200ee)',
250
+ whiteSpace: 'nowrap',
237
251
  overflow: 'hidden',
238
252
  textOverflow: 'ellipsis'
239
253
  },
@@ -245,6 +259,9 @@ class GitBranchCard extends oom.extends(HTMLElement) {
245
259
  height: '48px',
246
260
  marginTop: '-1px'
247
261
  },
262
+ '.branch-sub-name-version': {
263
+ width: '132px'
264
+ },
248
265
  '.actions': {
249
266
  display: 'flex',
250
267
  marginLeft: '12px'
@@ -265,6 +282,10 @@ class GitBranchCard extends oom.extends(HTMLElement) {
265
282
  '.description-textarea': {
266
283
  width: '100%'
267
284
  },
285
+ '.icon_16': {
286
+ '--mdc-icon-size': '16px',
287
+ '--mdc-icon-button-size': '24px'
288
+ },
268
289
  '.icon_18': {
269
290
  '--mdc-icon-size': '18px',
270
291
  '--mdc-icon-button-size': '24px'
@@ -287,6 +308,7 @@ class GitBranchCard extends oom.extends(HTMLElement) {
287
308
  }
288
309
 
289
310
  data = new GitBranchCardData(this.options.data)
311
+ versionsList = this.data.milestones.concat(['Произвольная'])
290
312
 
291
313
  elements = {
292
314
  /** @type {HTMLSpanElement} */
@@ -320,13 +342,23 @@ class GitBranchCard extends oom.extends(HTMLElement) {
320
342
  oninput: () => this.oninputDescription()
321
343
  }).dom,
322
344
  /** @type {import('@material/mwc-menu').Menu} */// @ts-ignore
323
- versions: this.data.milestones.reduce((mwcMenu, item) => {
345
+ versions: this.versionsList.reduce((mwcMenu, item) => {
324
346
  return mwcMenu(oom.mwcListItem(item))
325
347
  }, oom.mwcMenu({ fixed: true, activatable: true })).dom,
348
+ /** @type {import('@material/mwc-textfield').TextField} */// @ts-ignore
349
+ branchVersionTextfield: oom.mwcTextfield({
350
+ class: 'branch-sub-name branch-sub-name-version hide',
351
+ value: this.data.version,
352
+ placeholder: 'YY.XXXX',
353
+ pattern: '^\\d\\d.\\d\\d\\d\\d$',
354
+ validationmessage: 'Пример: 99.9999',
355
+ oninput: () => this.oninputBranchVersion(),
356
+ onblur: () => this.onblurBranchVersion()
357
+ }).dom,
326
358
  /** @type {HTMLDivElement} */// @ts-ignore
327
359
  branchButton: oom.div({
328
360
  class: 'version-button',
329
- onclick: () => { this.elements.versions.open = true }
361
+ onclick: () => this.editBranchVersion()
330
362
  }, this.data.version).dom,
331
363
  /** @type {HTMLSpanElement} */
332
364
  branchNamePart: oom.span({
@@ -377,6 +409,7 @@ class GitBranchCard extends oom.extends(HTMLElement) {
377
409
  this.data.version = value
378
410
  if (this.data.version === value) {
379
411
  this.elements.branchButton.textContent = this.data.version
412
+ this.elements.branchVersionTextfield.value = this.data.version
380
413
  this.elements.cardTitle.textContent = this.data.branchTitle
381
414
  }
382
415
  }
@@ -422,13 +455,37 @@ class GitBranchCard extends oom.extends(HTMLElement) {
422
455
  template = () => {
423
456
  this.elements.versions.anchor = this.elements.branchButton
424
457
  this.elements.versions.addEventListener('selected', (/** @type {CustomEvent<import('@material/mwc-list/mwc-list-foundation').ActionDetail>} */event) => {
425
- this.version = this.data.milestones[event.detail.index]
458
+ this.selectedVersion(event.detail.index)
426
459
  })
427
460
 
428
461
  this.updateBranchNamePart().catch(console.error)
429
462
 
430
- return oom.div({ class: 'mdc-card' }, oom
431
- .div({ class: 'title' }, this.elements.cardTitle)
463
+ const cardElement = oom.div({ class: 'mdc-card' }, oom
464
+ .div({ class: 'title' }, this.elements.cardTitle))
465
+
466
+ if (this.options.pk) {
467
+ // Добавим элементы для карточки задачи из истории
468
+ const useDate = this.options.useDate.toLocaleString()
469
+
470
+ cardElement(oom.div(oom
471
+ .span({ class: 'history-info' }, `Скопировано: ${useDate}`)
472
+ .mwcIconButton({
473
+ title: 'Удалить из истории',
474
+ class: 'icon_16',
475
+ innerHTML: octicons.x.toSVG({ width: 16 }),
476
+ onclick: () => {
477
+ /** @type {GitBranchCardList} */// @ts-ignore
478
+ const cardList = this.parentElement.parentElement
479
+
480
+ this.remove()
481
+ this.data.removeFromHistory(this.options.pk)
482
+ .then(() => cardList.buildHistoryList())
483
+ .catch(console.error)
484
+ }
485
+ })))
486
+ }
487
+
488
+ return cardElement(oom
432
489
  .div(oom
433
490
  .a({ class: 'link' }, this.data.url, {
434
491
  target: '_blank',
@@ -441,6 +498,7 @@ class GitBranchCard extends oom.extends(HTMLElement) {
441
498
  .div({ class: 'branch' },
442
499
  this.elements.branchButton,
443
500
  this.elements.versions,
501
+ this.elements.branchVersionTextfield,
444
502
  this.elements.branchNamePart,
445
503
  this.elements.branchSubName,
446
504
  this.elements.branchSubNameTextfield)
@@ -469,6 +527,52 @@ class GitBranchCard extends oom.extends(HTMLElement) {
469
527
  this.description = this.elements.descriptionTextarea.value
470
528
  }
471
529
 
530
+ /**
531
+ * Обработчик выбора версии из меню
532
+ *
533
+ * @param {number} index Выбранная в меню позиция
534
+ */
535
+ selectedVersion(index) {
536
+ const version = this.versionsList[index]
537
+
538
+ if (version === 'Произвольная') {
539
+ this.elements.branchVersionTextfield.classList.toggle('hide')
540
+ this.elements.branchButton.classList.toggle('hide')
541
+ this.elements.branchVersionTextfield.focus()
542
+ this.elements.branchVersionTextfield.select()
543
+ } else {
544
+ this.version = version
545
+ }
546
+ }
547
+
548
+ /** Открывает форму редактирования версии ветки */
549
+ editBranchVersion() {
550
+ if (this.data.milestones.length === 0) {
551
+ this.elements.branchVersionTextfield.classList.toggle('hide')
552
+ this.elements.branchButton.classList.toggle('hide')
553
+ this.elements.branchVersionTextfield.focus()
554
+ this.elements.branchVersionTextfield.select()
555
+ } else {
556
+ this.elements.versions.open = true
557
+ }
558
+ }
559
+
560
+ /** Сохранение данных о версии ветки при вводе */
561
+ oninputBranchVersion() {
562
+ if (this.elements.branchVersionTextfield.checkValidity()) {
563
+ this.version = this.elements.branchVersionTextfield.value
564
+ }
565
+ }
566
+
567
+ /** Скрывает поле ввода версии ветки при потере фокуса */
568
+ onblurBranchVersion() {
569
+ if (this.elements.branchVersionTextfield.checkValidity()) {
570
+ this.elements.branchVersionTextfield.classList.toggle('hide')
571
+ this.elements.branchButton.classList.toggle('hide')
572
+ this.version = this.elements.branchVersionTextfield.value
573
+ }
574
+ }
575
+
472
576
  /** Открывает форму редактирования доп. имени ветки */
473
577
  editBranchSubName() {
474
578
  this.elements.branchSubName.classList.toggle('hide')
@@ -499,14 +603,22 @@ class GitBranchCard extends oom.extends(HTMLElement) {
499
603
 
500
604
  /** Копирование имени ветки */
501
605
  async copyBranchName() {
502
- if (this.elements.branchSubNameTextfield.checkValidity()) {
606
+ const valid = this.elements.branchSubNameTextfield.checkValidity() &&
607
+ this.elements.branchVersionTextfield.checkValidity()
608
+
609
+ if (valid) {
503
610
  await this.data.copyBranchName()
504
611
  }
505
612
  }
506
613
 
507
614
  /** Копирование описания для git commit */
508
615
  async copyDescription() {
509
- await this.data.copyDescription()
616
+ const valid = this.elements.branchSubNameTextfield.checkValidity() &&
617
+ this.elements.branchVersionTextfield.checkValidity()
618
+
619
+ if (valid) {
620
+ await this.data.copyDescription()
621
+ }
510
622
  }
511
623
 
512
624
  /** Восстановление из истории последнего сохраненного состояния карточки */
@@ -527,12 +639,31 @@ class GitBranchCardList extends oom.extends(HTMLElement) {
527
639
  static style = oom.style({
528
640
  'display': 'contents',
529
641
  '.empty': {
530
- padding: '100px',
642
+ padding: '50px',
531
643
  textAlign: 'center'
532
644
  },
533
645
  '.content': {
534
- overflow: 'auto',
535
- maxHeight: 'calc(var(--mdc-dialog-max-height) - 100px)'
646
+ flexGrow: '1',
647
+ overflowY: 'auto',
648
+ overflowX: 'hidden',
649
+ maxHeight: 'calc(var(--mdc-dialog-max-height) - 100px)',
650
+ background: 'var(--mdc-theme-background)'
651
+ },
652
+ '.hide': {
653
+ display: 'none'
654
+ },
655
+ '.nav-buttons': {
656
+ display: 'flex',
657
+ justifyContent: 'space-between',
658
+ alignItems: 'center',
659
+ padding: '4px 4px 0px',
660
+ height: '36px'
661
+ },
662
+ '.nav-buttons-space': {
663
+ width: '64px'
664
+ },
665
+ '.nav-buttons-page-label': {
666
+ userSelect: 'none'
536
667
  }
537
668
  })
538
669
 
@@ -542,24 +673,45 @@ class GitBranchCardList extends oom.extends(HTMLElement) {
542
673
  // .mwcTab({ label: 'Список задач' })
543
674
  .mwcTab({ label: 'История задач' }))
544
675
 
545
- list = oom.div({ class: 'content' })
676
+ openTaskList = oom.div({ class: 'content' }, oom.div({ class: 'empty' }, 'Загрузка ...'))
677
+ historyTaskList = oom.div({ class: 'content hide' })
678
+
679
+ // Параметры навигации по истории
680
+ historyListPage = 0
681
+ historyListLimit = 3
546
682
 
547
683
  template = async () => {
548
684
  // if (this.openTaskList.length === 0) {
549
685
  // this.tabs({ activeindex: '1' })
550
686
  // }
551
- oom(this, this.tabs, this.list)
552
- oom(this.list, oom.div({ class: 'empty' }, 'Загрузка ...'))
687
+ oom(this, this.tabs, this.openTaskList, this.historyTaskList)
688
+
689
+ this.tabs.dom.addEventListener('MDCTabBar:activated', (/** @type {CustomEvent<import('@material/mwc-list/mwc-list-foundation').ActionDetail>} */event) => {
690
+ switch (event.detail.index) {
691
+ case 0:
692
+ this.historyTaskList({ innerHTML: '' })
693
+ this.historyTaskList.dom.classList.add('hide')
694
+ this.openTaskList.dom.classList.remove('hide')
695
+ break
696
+ case 1:
697
+ this.historyTaskList({ innerHTML: '' }, oom.div({ class: 'empty' }, 'Загрузка ...'))
698
+ this.openTaskList.dom.classList.add('hide')
699
+ this.historyTaskList.dom.classList.remove('hide')
700
+ this.historyListPage = 0
701
+ this.historyListLimit = 3
702
+ this.buildHistoryList().catch(console.error)
703
+ break
704
+ }
705
+ })
553
706
 
554
- this.list({ innerHTML: '' }, await this.buildTaskList())
707
+ this.openTaskList({ innerHTML: '' }, await this.buildTaskList())
555
708
  }
556
709
 
557
710
  /** @returns {Promise<HTMLElement|DocumentFragment>} Вернет готовый список задач с учетом аинхронной загрузки данных */
558
711
  async buildTaskList() {
559
712
  let taskTist = null
560
713
  const openTaskList = (await getListOfOpenCards({
561
- names: ['Ошибка', 'Задача'],
562
- hasVersion: true
714
+ names: ['Ошибка', 'Задача']
563
715
  })).map(card => new GitBranchCard(card))
564
716
 
565
717
  await Promise.all(openTaskList.map(card => card.restoreFromHistory()))
@@ -573,6 +725,58 @@ class GitBranchCardList extends oom.extends(HTMLElement) {
573
725
  return taskTist.dom
574
726
  }
575
727
 
728
+ /** Строит компонент списка истории задач */
729
+ async buildHistoryList() {
730
+ const offset = this.historyListPage * this.historyListLimit
731
+ const navButtons = oom.div({ class: 'nav-buttons' })
732
+ const gitBranchHistory = db.table('gitBranchHistory')
733
+ const historyData = await gitBranchHistory
734
+ .orderBy('useDate')
735
+ .reverse()
736
+ .offset(offset)
737
+ .limit(this.historyListLimit + 1)
738
+ .toArray()
739
+
740
+ if (historyData.length > 0) {
741
+ const totalCount = await gitBranchHistory.count()
742
+ const currentSize = offset + Math.min(this.historyListLimit, historyData.length)
743
+
744
+ if (this.historyListPage > 0) {
745
+ navButtons(oom.mwcButton({
746
+ innerHTML: octicons['arrow-left'].toSVG({ width: 24 }),
747
+ onclick: () => {
748
+ --this.historyListPage
749
+ this.buildHistoryList().catch(console.error)
750
+ }
751
+ }))
752
+ } else {
753
+ navButtons(oom.span({ class: 'nav-buttons-space' }))
754
+ }
755
+ navButtons(oom.span(`${offset + 1} - ${currentSize} / ${totalCount}`, {
756
+ class: 'nav-buttons-page-label'
757
+ }))
758
+ if (historyData.length > this.historyListLimit) {
759
+ historyData.pop()
760
+ navButtons(oom.mwcButton({
761
+ innerHTML: octicons['arrow-right'].toSVG({ width: 24 }),
762
+ onclick: () => {
763
+ ++this.historyListPage
764
+ this.buildHistoryList().catch(console.error)
765
+ }
766
+ }))
767
+ } else {
768
+ navButtons(oom.span({ class: 'nav-buttons-space' }))
769
+ }
770
+
771
+ this.historyTaskList({ innerHTML: '' }, navButtons, ...historyData.map(card => new GitBranchCard(card)))
772
+ } else if (this.historyListPage > 0) {
773
+ --this.historyListPage
774
+ this.buildHistoryList().catch(console.error)
775
+ } else {
776
+ this.historyTaskList({ innerHTML: '' }, oom.div({ class: 'empty' }, 'Задач в истории не найдено'))
777
+ }
778
+ }
779
+
576
780
  }
577
781
 
578
782
 
@@ -593,25 +797,27 @@ toolbar.addButton({
593
797
 
594
798
  toolbar.addButton({
595
799
  position: 'top',
800
+ filter: { names: ['Ошибка', 'Задача'] },
596
801
  title: 'Скопировать имя ветки для Git',
597
- iconSVG: octicons['git-branch'].toSVG({ width: 24 }),
802
+ iconSVG: octicons['git-branch'].toSVG({ width: 18 }),
598
803
  onclick: card => {
599
804
  const gitCard = new GitBranchCardData(card.data)
600
805
 
601
806
  gitCard.restoreFromHistory()
602
- .then(() => gitCard.copyBranchName().catch(console.error))
807
+ .then(() => gitCard.copyBranchName())
603
808
  .catch(console.error)
604
809
  }
605
810
  })
606
811
  toolbar.addButton({
607
812
  position: 'top',
813
+ filter: { names: ['Ошибка', 'Задача'] },
608
814
  title: 'Скопировать описание для Git коммита',
609
- iconSVG: octicons['git-commit'].toSVG({ width: 24 }),
815
+ iconSVG: octicons['git-commit'].toSVG({ width: 18 }),
610
816
  onclick: card => {
611
817
  const gitCard = new GitBranchCardData(card.data)
612
818
 
613
819
  gitCard.restoreFromHistory()
614
- .then(() => gitCard.copyDescription().catch(console.error))
820
+ .then(() => gitCard.copyDescription())
615
821
  .catch(console.error)
616
822
  }
617
823
  })
@@ -47,7 +47,8 @@ export class PopupDialog extends oom.extends(HTMLElement, PopupDialogDefaults) {
47
47
  'mwc-dialog': {
48
48
  '--mdc-dialog-z-index': '10000',
49
49
  '--mdc-dialog-max-width': '700px',
50
- '--mdc-dialog-max-height': '600px'
50
+ '--mdc-dialog-min-width': '500px',
51
+ '--mdc-dialog-max-height': '700px'
51
52
  },
52
53
  'header': {
53
54
  margin: '-20px -24px 0px -24px',
@@ -61,25 +62,31 @@ export class PopupDialog extends oom.extends(HTMLElement, PopupDialogDefaults) {
61
62
  overflow: 'hidden'
62
63
  },
63
64
  'main': {
65
+ display: 'flex',
66
+ flexDirection: 'column',
64
67
  margin: '0px -24px -20px -24px',
65
68
  overflow: 'auto',
66
69
  maxHeight: 'calc(var(--mdc-dialog-max-height) - 52px)'
67
70
  }
68
71
  })
69
72
 
73
+ // Фиксированный минимальный размер диалога по содержимому
74
+ contentMinWidth = 0
75
+ contentMinHeight = 0
76
+
70
77
  key = this.options.key
71
78
  content = typeof this.options.Element === 'string' ? this.options.Element : new this.options.Element()
79
+ main = oom.main(this.content)
80
+ header = oom.header(oom
81
+ .span(this.options.title)
82
+ .mwcIconButton({ icon: 'close', onclick: () => this.close() }))
72
83
 
73
84
  template = async () => {
74
85
  // Открытый диалог может быть только один
75
86
  this.id = 'sc-popup-dialog'
76
87
  /** @type {import('@material/mwc-dialog').Dialog} */// @ts-ignore
77
88
  this.dialog = oom
78
- .mwcDialog({ hideActions: true }, oom
79
- .header(oom
80
- .span(this.options.title)
81
- .mwcIconButton({ icon: 'close', onclick: () => this.close() }))
82
- .main(this.content))
89
+ .mwcDialog({ hideActions: true }, this.header, this.main)
83
90
  .dom
84
91
 
85
92
  oom(this, this.dialog)
@@ -87,6 +94,10 @@ export class PopupDialog extends oom.extends(HTMLElement, PopupDialogDefaults) {
87
94
  this.dialog.addEventListener('closed', event => this.closed(event))
88
95
 
89
96
  await this.open()
97
+
98
+ this.fixMinimumSize()
99
+ this.observer = new MutationObserver(() => this.fixMinimumSize())
100
+ this.observer.observe(this, { childList: true, subtree: true })
90
101
  }
91
102
 
92
103
  /** Функция открытия диалога с асинхронной задержкой, что бы успело построиться дерево компонента */
@@ -115,6 +126,24 @@ export class PopupDialog extends oom.extends(HTMLElement, PopupDialogDefaults) {
115
126
  }
116
127
  }
117
128
 
129
+ /** Фиксирует минимальный размер диалога по содержимому, чтобы избежать дальнейших скачков размера окна */
130
+ fixMinimumSize() {
131
+ const width = Math.max(this.contentMinWidth, this.main.dom.clientWidth)
132
+ const height = Math.max(this.contentMinHeight, this.main.dom.clientHeight)
133
+
134
+ if (this.contentMinWidth !== width || this.contentMinHeight !== height) {
135
+ this.contentMinWidth = width
136
+ this.contentMinHeight = height
137
+
138
+ this.main({
139
+ style: {
140
+ minWidth: `${this.contentMinWidth}px`,
141
+ minHeight: `${this.contentMinHeight}px`
142
+ }
143
+ })
144
+ }
145
+ }
146
+
118
147
  }
119
148
 
120
149
  oom.define(PopupDialog)
@@ -120,7 +120,7 @@ export function getListOfOpenCards(filter = {}) {
120
120
  url: '',
121
121
  author: record.get('ЛицоСоздал.Название') || record.get('Сотрудник.Название'),
122
122
  milestones: [],
123
- version: 'dev',
123
+ version: `${(new Date().getFullYear() + '').slice(-2)}.0000`,
124
124
  description: ''
125
125
  }
126
126
 
@@ -23,10 +23,10 @@ class ToolbarContainer extends oom.extends(HTMLElement, optionsDefaults) {
23
23
  marginBottom: '6px'
24
24
  },
25
25
  'saby-customizer-toolbar.top': {
26
- marginRight: '8px'
26
+ marginLeft: '16px'
27
27
  },
28
28
  '.button': {
29
- padding: '4px',
29
+ padding: '2px',
30
30
  color: 'var(--secondary_icon-color)',
31
31
  fill: 'var(--secondary_icon-color)',
32
32
  cursor: 'pointer',
@@ -42,7 +42,10 @@ class ToolbarContainer extends oom.extends(HTMLElement, optionsDefaults) {
42
42
  'saby-customizer-toolbar.top .button': {
43
43
  height: '20px',
44
44
  width: '20px',
45
- marginRight: '4px'
45
+ marginRight: '8px'
46
+ },
47
+ 'saby-customizer-toolbar.top .button:last-child': {
48
+ marginRight: '0'
46
49
  },
47
50
  '.button:hover': {
48
51
  color: 'var(--link_hover_text-color)',
@@ -54,9 +57,15 @@ class ToolbarContainer extends oom.extends(HTMLElement, optionsDefaults) {
54
57
  }
55
58
  })
56
59
 
60
+ /**
61
+ * @typedef ButtonOptionsFilter
62
+ * @property {Array<string>} [names] Фильтр по названию документа
63
+ */
64
+
57
65
  /**
58
66
  * @typedef ButtonOptions
59
67
  * @property {string} [position='right'] Позиция панели в которой отображается кнопка
68
+ * @property {ButtonOptionsFilter} [filter] Фильтры отображения кнопок
60
69
  * @property {string} title Всплывающая подсказка на кнопке
61
70
  * @property {string} iconSVG Верстка иконки в формате SVG
62
71
  * @property {Function} onclick Обработчик клика на иконку
@@ -111,7 +120,7 @@ class ToolbarContainer extends oom.extends(HTMLElement, optionsDefaults) {
111
120
 
112
121
  if (popupContainer) {
113
122
  this.observer = new MutationObserver(() => this.addTaskPanelContainer())
114
- this.observer.observe(popupContainer, { childList: true })
123
+ this.observer.observe(popupContainer, { childList: true, subtree: true })
115
124
  }
116
125
  }
117
126
 
@@ -133,7 +142,13 @@ class ToolbarContainer extends oom.extends(HTMLElement, optionsDefaults) {
133
142
  }
134
143
  }
135
144
  if (topPanel) {
136
- const topSidebar = topPanel.querySelector('saby-customizer-toolbar')
145
+ /** @type {ToolbarContainer} */
146
+ let topSidebar = topPanel.querySelector('saby-customizer-toolbar')
147
+
148
+ if (topSidebar && topSidebar.options?.card.data.id !== card.data.id) {
149
+ topSidebar.remove()
150
+ topSidebar = null
151
+ }
137
152
 
138
153
  if (!topSidebar) {
139
154
  topPanel.prepend(new ToolbarContainer({ card, position: 'top' }))
@@ -172,7 +187,17 @@ class ToolbarContainer extends oom.extends(HTMLElement, optionsDefaults) {
172
187
  * @param {ButtonOptions} options Опции кнопки
173
188
  */
174
189
  addButton(options) {
175
- if (this.options.position === options.position) {
190
+ let match = true
191
+
192
+ match = match && this.options.position === options.position
193
+
194
+ if (match && this.options.card && options.filter) {
195
+ if (options.filter.names) {
196
+ match = match && options.filter.names.includes(this.options.card.data.name)
197
+ }
198
+ }
199
+
200
+ if (match) {
176
201
  const button = oom.div({
177
202
  class: 'button',
178
203
  title: options.title,
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "repository": "github:saby-customizer/saby-customizer.github.io",
11
11
  "license": "Unlicense",
12
- "version": "0.0.0-pre.28",
12
+ "version": "0.0.0-pre.32",
13
13
  "type": "module",
14
14
  "main": "./userscript.js",
15
15
  "exports": {
package/userscript.js CHANGED
@@ -16,7 +16,8 @@ import { oom } from '@notml/core'
16
16
  // Библиотеки компонентов плагина
17
17
  // TODO: Перевести на опциональную загрузку
18
18
  // await import('./lib/dashboard.js')
19
- await import('./features/git-branch.js')
19
+ await import('saby-customizer/features/doc-copy-link.js')
20
+ await import('saby-customizer/features/git-branch.js')
20
21
 
21
22
  // @font-face doesn't work with Shadow DOM https://github.com/mdn/interactive-examples/issues/887
22
23
  // https://wiki.csswg.org/spec/css-scoping