saby-customizer 0.0.0-pre.7 → 0.0.0
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/features/doc-copy-link.js +17 -0
- package/features/git-branch.js +770 -40
- package/lib/context.js +43 -0
- package/lib/database.js +4 -1
- package/lib/layout.js +75 -20
- package/lib/popup-dialog.js +69 -31
- package/{saby-lib → lib/saby-lib}/cloud-statistic.js +1 -0
- package/{saby-lib → lib/saby-lib}/edo.js +49 -7
- package/lib/saby-lib/rpc.js +19 -0
- package/lib/saby-lib/toolbar.js +272 -0
- package/lib.js +8 -0
- package/material.js +9161 -5144
- package/octicons.js +4673 -0
- package/package.json +25 -17
- package/{lib → third-party}/material.js +5 -0
- package/third-party/octicons.js +3 -0
- package/userscript.js +9 -4
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { oom } from '@notml/core'
|
|
2
|
+
import { getListOfOpenCards } from './edo.js'
|
|
3
|
+
|
|
4
|
+
const { MutationObserver } = window
|
|
5
|
+
/**
|
|
6
|
+
* @typedef ToolbarContainerOptions Опции по умолчанию для панели
|
|
7
|
+
* @property {boolean} global Признак глобальной панели
|
|
8
|
+
* @property {import('saby-customizer/lib.js').Card} [card] Ссылка на экземпляр карточки задачи
|
|
9
|
+
* @property {string} [position='right'] Положение панели на сайте right|top
|
|
10
|
+
*/
|
|
11
|
+
/** @type {ToolbarContainerOptions} */
|
|
12
|
+
const optionsDefaults = { global: false, card: null, position: 'right' }
|
|
13
|
+
|
|
14
|
+
/** Класс контейнера для расширения панели сайта дополнительными кнопками */
|
|
15
|
+
class ToolbarContainer extends oom.extends(HTMLElement, optionsDefaults) {
|
|
16
|
+
|
|
17
|
+
static tagName = 'saby-customizer-toolbar'
|
|
18
|
+
static style = oom.style({
|
|
19
|
+
'display': 'flex',
|
|
20
|
+
'alignItems': 'center',
|
|
21
|
+
'saby-customizer-toolbar.right': {
|
|
22
|
+
flexDirection: 'column',
|
|
23
|
+
marginBottom: '6px'
|
|
24
|
+
},
|
|
25
|
+
'saby-customizer-toolbar.top': {
|
|
26
|
+
marginLeft: '16px'
|
|
27
|
+
},
|
|
28
|
+
'.button': {
|
|
29
|
+
padding: '2px',
|
|
30
|
+
color: 'var(--secondary_icon-color)',
|
|
31
|
+
fill: 'var(--secondary_icon-color)',
|
|
32
|
+
cursor: 'pointer',
|
|
33
|
+
display: 'flex',
|
|
34
|
+
justifyContent: 'center',
|
|
35
|
+
alignItems: 'center'
|
|
36
|
+
},
|
|
37
|
+
'saby-customizer-toolbar.right .button': {
|
|
38
|
+
height: '32px',
|
|
39
|
+
width: '32px',
|
|
40
|
+
marginBottom: '4px'
|
|
41
|
+
},
|
|
42
|
+
'saby-customizer-toolbar.top .button': {
|
|
43
|
+
height: '20px',
|
|
44
|
+
width: '20px',
|
|
45
|
+
marginRight: '8px'
|
|
46
|
+
},
|
|
47
|
+
'saby-customizer-toolbar.top .button:last-child': {
|
|
48
|
+
marginRight: '0'
|
|
49
|
+
},
|
|
50
|
+
'.button:hover': {
|
|
51
|
+
color: 'var(--link_hover_text-color)',
|
|
52
|
+
fill: 'var(--link_hover_text-color)',
|
|
53
|
+
borderColor: ' var(--border-color_hover_button_toolButton)',
|
|
54
|
+
background: 'var(--background-color_hover_button_toolButton)',
|
|
55
|
+
borderRadius: 'var(--border-radius_button_toolButton)',
|
|
56
|
+
borderWidth: 'var(--border-thickness_button)'
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @typedef ButtonOptionsFilter
|
|
62
|
+
* @property {Array<string>} [names] Фильтр по названию документа
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @typedef ButtonOptions
|
|
67
|
+
* @property {string} [position='right'] Позиция панели в которой отображается кнопка
|
|
68
|
+
* @property {ButtonOptionsFilter} [filter] Фильтры отображения кнопок
|
|
69
|
+
* @property {string} title Всплывающая подсказка на кнопке
|
|
70
|
+
* @property {string} iconSVG Верстка иконки в формате SVG
|
|
71
|
+
* @property {Function} onclick Обработчик клика на иконку
|
|
72
|
+
*/
|
|
73
|
+
/** @type {ButtonOptions[]} */
|
|
74
|
+
static buttons = []
|
|
75
|
+
|
|
76
|
+
/** @type {Set<ToolbarContainer>} */
|
|
77
|
+
static containers = new Set()
|
|
78
|
+
|
|
79
|
+
/** @type {ToolbarContainer} */
|
|
80
|
+
static globalContainer = null
|
|
81
|
+
|
|
82
|
+
/** @type {MutationObserver} */
|
|
83
|
+
static observer = null
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Регистрирует новую общую кнопку в панели сайта
|
|
87
|
+
*
|
|
88
|
+
* @param {ButtonOptions} options Опции кнопки
|
|
89
|
+
*/
|
|
90
|
+
static addButton(options) {
|
|
91
|
+
options = Object.assign({ position: 'right' }, options)
|
|
92
|
+
this.buttons.push(options)
|
|
93
|
+
|
|
94
|
+
this.containers.forEach(container => container.addButton(options))
|
|
95
|
+
|
|
96
|
+
if (!ToolbarContainer.globalContainer) {
|
|
97
|
+
this.addGlobalContainer()
|
|
98
|
+
}
|
|
99
|
+
if (!this.observer) {
|
|
100
|
+
this.addTaskPanelContainer()
|
|
101
|
+
this.registerTaskPanelWatcher()
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Добавляет в вертску сайта глобальный контейнер в панели для добавления кнопок
|
|
107
|
+
*
|
|
108
|
+
* @param {{searchCount:number}} options Опции регистарции обработчиков
|
|
109
|
+
*/
|
|
110
|
+
static addGlobalContainer({ searchCount } = { searchCount: 0 }) {
|
|
111
|
+
if (!ToolbarContainer.globalContainer) {
|
|
112
|
+
const sabyPageRightPanel = document.querySelector('.sabyPage-MainLayout__rightPanel .sabyPage-MainLayout__wrapper') ||
|
|
113
|
+
document.querySelector('.sabyPage-MainLayout__mainContent .sabyPage-widgets__rightPanel__bottomButtons .sabyPage-widgets__wrapper')
|
|
114
|
+
|
|
115
|
+
if (sabyPageRightPanel) {
|
|
116
|
+
ToolbarContainer.globalContainer = new ToolbarContainer({ global: true })
|
|
117
|
+
sabyPageRightPanel.prepend(ToolbarContainer.globalContainer)
|
|
118
|
+
} else {
|
|
119
|
+
if (searchCount < 10) {
|
|
120
|
+
searchCount++
|
|
121
|
+
setTimeout(() => {
|
|
122
|
+
this.addGlobalContainer({ searchCount })
|
|
123
|
+
}, 1000)
|
|
124
|
+
} else {
|
|
125
|
+
console.warn('saby-customizer - addGlobalContainer: Не найден ни один общий контейнер для размещения доп. панелей с кнопками')
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Регистрирует обработчик для поиска открытых задач и добавления в них панели
|
|
133
|
+
*
|
|
134
|
+
* @param {{searchCount:number}} options Опции регистарции обработчиков
|
|
135
|
+
*/
|
|
136
|
+
static registerTaskPanelWatcher({ searchCount } = { searchCount: 0 }) {
|
|
137
|
+
const popupContainer = document.getElementById('popup')
|
|
138
|
+
const pageEntityContainer = document.querySelector('.onlinePage_Entity-wrapper.controls-Popup__dialog-target-container')
|
|
139
|
+
let timeout = null
|
|
140
|
+
|
|
141
|
+
if (!this.observer) {
|
|
142
|
+
this.observer = new MutationObserver(() => {
|
|
143
|
+
if (!timeout) {
|
|
144
|
+
timeout = setTimeout(() => {
|
|
145
|
+
this.addTaskPanelContainer()
|
|
146
|
+
timeout = null
|
|
147
|
+
}, 1000)
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (popupContainer) {
|
|
153
|
+
this.observer.observe(popupContainer, { childList: true, subtree: true })
|
|
154
|
+
}
|
|
155
|
+
if (pageEntityContainer) {
|
|
156
|
+
this.observer.observe(pageEntityContainer, { childList: true, subtree: true })
|
|
157
|
+
}
|
|
158
|
+
if (!popupContainer && !pageEntityContainer) {
|
|
159
|
+
if (searchCount < 10) {
|
|
160
|
+
searchCount++
|
|
161
|
+
setTimeout(() => {
|
|
162
|
+
this.registerTaskPanelWatcher({ searchCount })
|
|
163
|
+
}, 1000)
|
|
164
|
+
} else {
|
|
165
|
+
console.error('saby-customizer - registerTaskPanelWatcher: Не найден ни один общий контейнер для размещения доп. панелей с кнопками')
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** Добавления во все найденные открытые задачи правую панель */
|
|
171
|
+
static addTaskPanelContainer() {
|
|
172
|
+
const openTaskList = getListOfOpenCards({ duplicates: true })
|
|
173
|
+
|
|
174
|
+
openTaskList.forEach(card => {
|
|
175
|
+
const rightPanel = card.element.querySelector('.controls-StackTemplate__rightPanel .sabyPage-MainLayout__wrapper') ||
|
|
176
|
+
// Кнопки для всплывающий панелей в карточке открытой в отдельной вкладке
|
|
177
|
+
card.element.querySelector('.controls-StackTemplate__rightPanel .sabyPage-widgets__wrapper')
|
|
178
|
+
const topPanel = card.element.querySelector('.edo3-Dialog__head-firstLine-buttons')
|
|
179
|
+
|
|
180
|
+
if (rightPanel) {
|
|
181
|
+
const rightSidebar = rightPanel.querySelector('saby-customizer-toolbar')
|
|
182
|
+
|
|
183
|
+
if (!rightSidebar) {
|
|
184
|
+
rightPanel.prepend(new ToolbarContainer())
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (topPanel) {
|
|
188
|
+
/** @type {ToolbarContainer} */
|
|
189
|
+
let topSidebar = topPanel.querySelector('saby-customizer-toolbar')
|
|
190
|
+
|
|
191
|
+
if (topSidebar && topSidebar.options?.card.data.id !== card.data.id) {
|
|
192
|
+
topSidebar.remove()
|
|
193
|
+
topSidebar = null
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (!topSidebar) {
|
|
197
|
+
topPanel.prepend(new ToolbarContainer({ card, position: 'top' }))
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
template = () => {
|
|
204
|
+
// Атрибуты для игнорирования контейнера платформой wasaby
|
|
205
|
+
this.setAttribute('data-vdomignore', 'true')
|
|
206
|
+
this.setAttribute('contenteditable', 'true')
|
|
207
|
+
this.classList.add(this.options.position)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Будем запоминать все контейнеры для синхронизации кнопок */
|
|
211
|
+
connectedCallback() {
|
|
212
|
+
super.connectedCallback()
|
|
213
|
+
ToolbarContainer.containers.add(this)
|
|
214
|
+
ToolbarContainer.buttons.forEach(options => this.addButton(options))
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Очищаем удаленные из DOM контейнеры */
|
|
218
|
+
disconnectedCallback() {
|
|
219
|
+
if (this.options.global) {
|
|
220
|
+
ToolbarContainer.globalContainer = null
|
|
221
|
+
ToolbarContainer.addGlobalContainer()
|
|
222
|
+
}
|
|
223
|
+
ToolbarContainer.containers.delete(this)
|
|
224
|
+
this.innerHTML = ''
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Добавляет новую общую кнопку в текущий контейнер панели
|
|
229
|
+
*
|
|
230
|
+
* @param {ButtonOptions} options Опции кнопки
|
|
231
|
+
*/
|
|
232
|
+
addButton(options) {
|
|
233
|
+
let match = true
|
|
234
|
+
|
|
235
|
+
match = match && this.options.position === options.position
|
|
236
|
+
|
|
237
|
+
if (match && this.options.card && options.filter) {
|
|
238
|
+
if (options.filter.names) {
|
|
239
|
+
match = match && options.filter.names.includes(this.options.card.data.name)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (match) {
|
|
244
|
+
const button = oom.div({
|
|
245
|
+
class: 'button',
|
|
246
|
+
title: options.title,
|
|
247
|
+
onclick: () => {
|
|
248
|
+
const [card] = this.options.card
|
|
249
|
+
? getListOfOpenCards({ id: this.options.card.data.id })
|
|
250
|
+
: [null]
|
|
251
|
+
|
|
252
|
+
options.onclick(card)
|
|
253
|
+
}
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
if (options.iconSVG) {
|
|
257
|
+
button({ innerHTML: options.iconSVG })
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
oom(this, button)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
oom.define(ToolbarContainer)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
export const toolbar = {
|
|
271
|
+
addButton: (options) => ToolbarContainer.addButton(options)
|
|
272
|
+
}
|
package/lib.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './lib/context.js'
|
|
2
|
+
export * from './lib/database.js'
|
|
3
|
+
export * from './lib/hotkeys.js'
|
|
4
|
+
export * from './lib/layout.js'
|
|
5
|
+
export * from './lib/popup-dialog.js'
|
|
6
|
+
export * from './lib/saby-lib/edo.js'
|
|
7
|
+
export * from './lib/saby-lib/rpc.js'
|
|
8
|
+
export * from './lib/saby-lib/toolbar.js'
|