newhelper-js 2.1.7 → 2.1.8
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/newHelper.js +470 -283
- package/package.json +5 -2
package/newHelper.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Перед вами код newHelper.js версии 2.1.
|
|
3
|
-
*
|
|
2
|
+
* Перед вами код newHelper.js версии 2.1.8,
|
|
3
|
+
* Фронтенд библиотека сверхлегких и мощных утилит.
|
|
4
|
+
* Библиотека построена на базе фабрики
|
|
5
|
+
* Которая начинается с Intl.newHelper=function(namespace){...};
|
|
4
6
|
* Причина использоватся Intl.newHelper банально проста
|
|
5
7
|
* Если я в 2.1.0 засирал глобалскоуп одной полу гибкой переменной
|
|
6
8
|
* И парочкой addEventListener,
|
|
7
|
-
* То почему бы не начать отказываться от засирания глобал скоупа
|
|
9
|
+
* То почему бы не начать отказываться от засирания глобал скоупа
|
|
10
|
+
* при скачивании библиотеки как такового
|
|
8
11
|
* И да, для инициализации ньюхелпера реально нужно писать
|
|
9
|
-
*
|
|
10
|
-
* (Да, я рекомендую не бояться глобал скоупа, т.к. надеюсь
|
|
11
|
-
* что вы понимаете почему и зачем вы это читаете)
|
|
12
|
+
* Intl.newHelper(yourVar) чтобы newHelper появился в window.yourVar
|
|
12
13
|
*
|
|
13
14
|
* Стиль комментариев
|
|
14
15
|
* FIXME - странное поведение функции, которое желательно бы переделать
|
|
@@ -37,13 +38,14 @@
|
|
|
37
38
|
*
|
|
38
39
|
* Новые модули, готовятсяк релизу в 2.2
|
|
39
40
|
* их апи может быть чуть чуть нестабильно
|
|
40
|
-
*
|
|
41
|
-
* link (пропатченный, см. _.link.get => dynamic)
|
|
41
|
+
* link (пропатченный, см. window[_].link.get => dynamic)
|
|
42
42
|
* form
|
|
43
43
|
* pipe/pipeAsync
|
|
44
|
-
* drag (портирован из win)
|
|
45
|
-
*
|
|
46
|
-
*
|
|
44
|
+
* drag (портирован из win._initDrag)
|
|
45
|
+
* fade (портирован из win._animate)
|
|
46
|
+
* x10 (x window system - портирован и рефакторнут из кусков win)
|
|
47
|
+
* toast
|
|
48
|
+
|
|
47
49
|
*
|
|
48
50
|
* Модули, имена которых зарезервированы на 2.3++
|
|
49
51
|
* не используйте их неймспейсы для плагинов:
|
|
@@ -54,9 +56,9 @@
|
|
|
54
56
|
*
|
|
55
57
|
* Плагины, новый паттерн который я хочу узаконить в 2.2
|
|
56
58
|
* Это не _.use(), не _.plugins, не мутация прототипа
|
|
57
|
-
* Простое назначение _.myPlugin = pluginFabric();
|
|
59
|
+
* Простое назначение _.myPlugin = pluginFabric(_);
|
|
58
60
|
* (где _ это уже вызванная фабрика ядра)
|
|
59
|
-
* Как предполагается работать? также как и Intl.newHelper()
|
|
61
|
+
* Как предполагается работать? также как и Intl.newHelper(namespace)
|
|
60
62
|
* Фабрика плагина возвращает объект, метод, или класс, или что вам нужно
|
|
61
63
|
* Вам для подключения плагина просто нужно дать плагину неймспейс внутри ядра
|
|
62
64
|
* И вызвать фабрику, всё!
|
|
@@ -71,19 +73,22 @@
|
|
|
71
73
|
*
|
|
72
74
|
* А если вам нужны именно ньюхелпер таблицы
|
|
73
75
|
* Будьте добры проверить исходники 2.1.6 на npm
|
|
74
|
-
* Или пилите самодельные таблицы через innerHTML или _.html
|
|
76
|
+
* Или пилите самодельные таблицы через innerHTML или window[_].html
|
|
75
77
|
* Что вам удобнее то и берите
|
|
76
78
|
*
|
|
77
79
|
* Я (MIOBOMB) хочу релизнуть 2.2 уже после 2.1.8,
|
|
78
|
-
* ибо мне в идеале закончить тосты и Object Hub 0.
|
|
80
|
+
* ибо мне в идеале закончить тосты и Object Hub 0.98
|
|
79
81
|
*/
|
|
80
82
|
|
|
83
|
+
// deprecated!!
|
|
81
84
|
/** @import { NewHelper } from './newHelper.d.ts' */
|
|
82
|
-
Intl.newHelper=function() {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
Intl.newHelper=function(_='_') {
|
|
86
|
+
if (!window[_])
|
|
87
|
+
window[_] = {};
|
|
88
|
+
|
|
89
|
+
window[_].ver = '2.1.8';
|
|
85
90
|
|
|
86
|
-
link
|
|
91
|
+
window[_].link = {
|
|
87
92
|
/*
|
|
88
93
|
* МОДУЛЬ ССЫЛОК
|
|
89
94
|
* Author: MIOBOMB (2023-2026)
|
|
@@ -99,6 +104,10 @@ Intl.newHelper=function() {
|
|
|
99
104
|
* Но в теории на них можно повешать все модальные и прочие действия
|
|
100
105
|
*
|
|
101
106
|
* !!!: в функции get() работает весь роутинг, в т.ч. вложенный для страниц
|
|
107
|
+
* !!!: пожалуйста, относитесь к этому модулю не как к "компонентной модели"
|
|
108
|
+
* или что у вас там в реактивном вебе.
|
|
109
|
+
* А относитесь к нему как к серверному маршрутизатору,
|
|
110
|
+
* вы же ведь можете сделать красивые и адекватные маршруты.
|
|
102
111
|
*
|
|
103
112
|
* See also:
|
|
104
113
|
* - https://developer.mozilla.org/en-US/docs/Web/API/History_API
|
|
@@ -137,47 +146,47 @@ Intl.newHelper=function() {
|
|
|
137
146
|
* false = страница пишет свой адрес в ссылку
|
|
138
147
|
*/
|
|
139
148
|
// HMM: некоторые браузеры могут вызывать popstate и при реплейсе
|
|
140
|
-
if (!
|
|
149
|
+
if (!window[_].link._i) {
|
|
141
150
|
// здесь происходит перенос команд при popstate
|
|
142
|
-
// читайте _.link.get() если хотите узнать почему
|
|
143
|
-
let newUrl='?' + [
|
|
144
|
-
|
|
151
|
+
// читайте window[_].link.get() если хотите узнать почему
|
|
152
|
+
let newUrl='?' + [window[_].link.compile()[0],...window[_].link._cmd].join('&');
|
|
153
|
+
window[_].link._i=true;
|
|
145
154
|
history.replaceState(null,null,newUrl);
|
|
146
|
-
|
|
155
|
+
window[_].link.get();
|
|
147
156
|
} else
|
|
148
|
-
|
|
157
|
+
window[_].link._i=false;
|
|
149
158
|
},
|
|
150
159
|
_cmd: [],
|
|
151
160
|
popInit: false,
|
|
152
161
|
_init() {
|
|
153
|
-
if (!
|
|
154
|
-
window.addEventListener('popstate', ()=>
|
|
155
|
-
|
|
162
|
+
if (!window[_].link.popInit) {
|
|
163
|
+
window.addEventListener('popstate', ()=>window[_].link._pop());
|
|
164
|
+
window[_].link.popInit = true;
|
|
156
165
|
}
|
|
157
166
|
},
|
|
158
167
|
|
|
159
168
|
compile: (e=location.search)=>e.replace('?','').split('&'),
|
|
160
|
-
set(page, title =
|
|
169
|
+
set(page, title = window[_].link.defTitle) {
|
|
161
170
|
if (title) document.title = title;
|
|
162
|
-
if (!
|
|
163
|
-
let link =
|
|
171
|
+
if (!window[_].link._i) {
|
|
172
|
+
let link = window[_].link.compile();
|
|
164
173
|
link[0] = page;
|
|
165
174
|
history.pushState(null,null,'?'+link.join('&'));
|
|
166
175
|
}
|
|
167
|
-
|
|
176
|
+
window[_].link._i = false;
|
|
168
177
|
},
|
|
169
178
|
add(cmd) {
|
|
170
|
-
let link =
|
|
179
|
+
let link = window[_].link.compile();
|
|
171
180
|
if (!link.includes(cmd)) {
|
|
172
181
|
link.push(cmd);
|
|
173
|
-
|
|
182
|
+
window[_].link._cmd.push(cmd);
|
|
174
183
|
history.replaceState(null,null,'?'+link.join('&'));
|
|
175
184
|
}
|
|
176
185
|
},
|
|
177
186
|
remove(cmd) {
|
|
178
|
-
let link =
|
|
187
|
+
let link = window[_].link.compile();
|
|
179
188
|
if (link.includes(cmd)){
|
|
180
|
-
let c =
|
|
189
|
+
let c = window[_].link._cmd;
|
|
181
190
|
link.splice(link.indexOf(cmd),1);
|
|
182
191
|
c.splice(c.indexOf(cmd),1);
|
|
183
192
|
history.replaceState(null,null,'?'+link.join('&'));
|
|
@@ -185,7 +194,7 @@ Intl.newHelper=function() {
|
|
|
185
194
|
},
|
|
186
195
|
|
|
187
196
|
get() {
|
|
188
|
-
|
|
197
|
+
window[_].link._init();
|
|
189
198
|
/*
|
|
190
199
|
* Страницы бросают ошибку чтобы вызвать базовую страницу
|
|
191
200
|
* Команды тем временем так не делают
|
|
@@ -195,12 +204,12 @@ Intl.newHelper=function() {
|
|
|
195
204
|
* При popstate команды берутся из хранилища _cmd, вместо самой ссылки
|
|
196
205
|
* Сделано это для переноса команд при прыжках по истории
|
|
197
206
|
*/
|
|
198
|
-
let links =
|
|
207
|
+
let links = window[_].link.compile(),
|
|
199
208
|
[ firstKey, fisrtValue ] = links[0].split('='),
|
|
200
209
|
cmds = links.slice(1);
|
|
201
210
|
try {
|
|
202
211
|
let route = firstKey.split('/'),
|
|
203
|
-
dir =
|
|
212
|
+
dir = window[_].link.actions,
|
|
204
213
|
main = dir[firstKey];
|
|
205
214
|
if (!firstKey.includes('/')) {
|
|
206
215
|
main(fisrtValue);
|
|
@@ -268,22 +277,22 @@ Intl.newHelper=function() {
|
|
|
268
277
|
}
|
|
269
278
|
}
|
|
270
279
|
} catch (e) {
|
|
271
|
-
|
|
280
|
+
window[_].link.basePage();
|
|
272
281
|
throw e;
|
|
273
282
|
}
|
|
274
|
-
|
|
283
|
+
window[_].link._cmd = cmds;
|
|
275
284
|
cmds.forEach(cmdPre => {
|
|
276
285
|
let [ key, value ] = cmdPre.split('=');
|
|
277
|
-
let cmd =
|
|
286
|
+
let cmd = window[_].link.commands[key];
|
|
278
287
|
if (cmd)
|
|
279
288
|
cmd(value);
|
|
280
289
|
else
|
|
281
290
|
console.error(new Error(`command '${cmd}' doesn't exist!`))
|
|
282
291
|
});
|
|
283
292
|
},
|
|
284
|
-
}
|
|
293
|
+
};
|
|
285
294
|
|
|
286
|
-
lazy
|
|
295
|
+
window[_].lazy = {
|
|
287
296
|
/*
|
|
288
297
|
* МОДУЛЬ ЛЕНИ
|
|
289
298
|
* Author: MIOBOMB (2024-2026)
|
|
@@ -307,7 +316,7 @@ Intl.newHelper=function() {
|
|
|
307
316
|
load(url, ...args) {
|
|
308
317
|
/*
|
|
309
318
|
* ...args передаются в Promise.resolve(args)
|
|
310
|
-
* Это позволяет делать _.lazy.load('script.js', 'данные', 'для', 'колбека')
|
|
319
|
+
* Это позволяет делать window[_].lazy.load('script.js', 'данные', 'для', 'колбека')
|
|
311
320
|
* И потом в .then((a,b,c)=>...) получать эти аргументы
|
|
312
321
|
*
|
|
313
322
|
* Тройное состояние скрипта в lazy.loaded:
|
|
@@ -318,7 +327,7 @@ Intl.newHelper=function() {
|
|
|
318
327
|
* Это защита от двойной загрузки одного скрипта
|
|
319
328
|
*/
|
|
320
329
|
let key = url.split('?')[0], // отсекаем параметры, чтобы не дублировать
|
|
321
|
-
state =
|
|
330
|
+
state = window[_].lazy.loaded;
|
|
322
331
|
if (state[key] === true)
|
|
323
332
|
return Promise.resolve(args);
|
|
324
333
|
if (state[key] instanceof Promise)
|
|
@@ -351,22 +360,22 @@ Intl.newHelper=function() {
|
|
|
351
360
|
path = path[obj];
|
|
352
361
|
}
|
|
353
362
|
path[method] = (...a)=>
|
|
354
|
-
|
|
363
|
+
window[_].lazy._(script,fn).then(f=>f(...a));
|
|
355
364
|
}
|
|
356
365
|
},
|
|
357
366
|
async _(scr, fn) {
|
|
358
367
|
let get = path => path.split('.').reduce((obj, key) => obj?.[key], window),
|
|
359
368
|
wrapper = get(fn);
|
|
360
369
|
|
|
361
|
-
await
|
|
370
|
+
await window[_].lazy.load(scr); // await короче Promise.then
|
|
362
371
|
|
|
363
372
|
if (wrapper !== get(fn))
|
|
364
373
|
return get(fn);
|
|
365
374
|
throw new Error(`Function ${fn} not loaded from ${scr}`);
|
|
366
375
|
},
|
|
367
|
-
}
|
|
376
|
+
};
|
|
368
377
|
|
|
369
|
-
lang
|
|
378
|
+
window[_].lang = {
|
|
370
379
|
/*
|
|
371
380
|
* МОДУЛЬ ПЕРЕВОДОВ (l10n)
|
|
372
381
|
* Author: MIOBOMB (2024-2026)
|
|
@@ -409,21 +418,21 @@ Intl.newHelper=function() {
|
|
|
409
418
|
// или сохранить оригинальное api на объекте
|
|
410
419
|
main: {},
|
|
411
420
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
parse: (packet, vars = _.lang.vars)=>
|
|
421
|
+
load: name => fetch(window[_].lang.addr + name + '.json')
|
|
422
|
+
.then(r => r.text()),
|
|
423
|
+
parse: (packet, vars = window[_].lang.vars)=>
|
|
415
424
|
// HMM: переделать под общий синтаксис типа {var}
|
|
416
425
|
packet.replace(/\+([^+]+)\+/g, (match, key)=>{
|
|
417
426
|
let v = vars[key];
|
|
418
427
|
return v !== undefined ? v : match;
|
|
419
428
|
}),
|
|
420
429
|
async replace(name){
|
|
421
|
-
const packet = await
|
|
422
|
-
|
|
430
|
+
const packet = await window[_].lang.load(name);
|
|
431
|
+
window[_].lang.main = JSON.parse(window[_].lang.parse(packet)); // без замены языка нельзя начинать перевод
|
|
423
432
|
|
|
424
|
-
for (let el of document.querySelectorAll(`[${
|
|
433
|
+
for (let el of document.querySelectorAll(`[${window[_].lang.attr}]`)) {
|
|
425
434
|
let key = el.dataset.trans,
|
|
426
|
-
text =
|
|
435
|
+
text = window[_].lang.main[key] || key,
|
|
427
436
|
tag = el.tagName;
|
|
428
437
|
|
|
429
438
|
if (tag === 'IMG')
|
|
@@ -433,7 +442,7 @@ Intl.newHelper=function() {
|
|
|
433
442
|
else
|
|
434
443
|
el.innerHTML = text;
|
|
435
444
|
}
|
|
436
|
-
// возвращаем для последующей обработки пакета, например для сохранения в _.storage
|
|
445
|
+
// возвращаем для последующей обработки пакета, например для сохранения в window[_].storage
|
|
437
446
|
return packet;
|
|
438
447
|
},
|
|
439
448
|
|
|
@@ -441,33 +450,33 @@ Intl.newHelper=function() {
|
|
|
441
450
|
* Получатели строки из пакета автоматически формируют HTML
|
|
442
451
|
* Это позволяет заметно упростить работу с кодом
|
|
443
452
|
* Вместо отдельного указания data-trans и lang.from
|
|
444
|
-
* вы можете написать `<h1${_.lang.text('yourKey')}/h1>`
|
|
445
|
-
* А пришлось бы писать `<h1 data-trans="yourKey">${_.lang.from('yourKey')}</h1>`
|
|
453
|
+
* вы можете написать `<h1${window[_].lang.text('yourKey')}/h1>`
|
|
454
|
+
* А пришлось бы писать `<h1 data-trans="yourKey">${window[_].lang.from('yourKey')}</h1>`
|
|
446
455
|
* Согласитесь, и короче и удобнее ведь?
|
|
447
456
|
* Не повторяйте моих ошибок и примите это как победу в лотерее
|
|
448
457
|
*
|
|
449
458
|
* !!!: если ключа в пакете нету, будет выброшен warning
|
|
450
459
|
*/
|
|
451
460
|
attr: ` data-trans`,
|
|
452
|
-
from: i=>_.lang.main[i] || console.warn(`_.lang> ${i} is undefined`) || i,
|
|
461
|
+
from: i=>window[_].lang.main[i] || console.warn(`window[_].lang> ${i} is undefined`) || i,
|
|
453
462
|
|
|
454
|
-
text: i=>_.lang.attr+`="${i}">${_.lang.from(i)}<`,
|
|
455
|
-
submit: i=>_.lang.attr+`="${i}" value="${_.lang.from(i)}">`, // <input type=submit>
|
|
456
|
-
input: i=>_.lang.attr+`="${i}" placeholder="${_.lang.from(i)}">`,
|
|
457
|
-
textarea: i=>_.lang.attr+`="${i}" placeholder="${_.lang.from(i)}"><`,
|
|
458
|
-
img: i=>_.lang.attr+`="${i}" src="${_.lang.from(i)}"`,
|
|
463
|
+
text: i=>window[_].lang.attr+`="${i}">${window[_].lang.from(i)}<`,
|
|
464
|
+
submit: i=>window[_].lang.attr+`="${i}" value="${window[_].lang.from(i)}">`, // <input type=submit>
|
|
465
|
+
input: i=>window[_].lang.attr+`="${i}" placeholder="${window[_].lang.from(i)}">`,
|
|
466
|
+
textarea: i=>window[_].lang.attr+`="${i}" placeholder="${window[_].lang.from(i)}"><`,
|
|
467
|
+
img: i=>window[_].lang.attr+`="${i}" src="${window[_].lang.from(i)}"`,
|
|
459
468
|
winTitle(i) {
|
|
460
|
-
let text =
|
|
461
|
-
dataTrans = _.lang.attr
|
|
469
|
+
let text = window[_].lang.from(i),
|
|
470
|
+
dataTrans = window[_].lang.attr+`="${i}"`;
|
|
462
471
|
if (text == null || text == '') {
|
|
463
472
|
text = i;
|
|
464
473
|
dataTrans = '';
|
|
465
474
|
}
|
|
466
475
|
return `${dataTrans}>${text}<`;
|
|
467
476
|
},
|
|
468
|
-
}
|
|
477
|
+
};
|
|
469
478
|
|
|
470
|
-
http
|
|
479
|
+
window[_].http = {
|
|
471
480
|
/*
|
|
472
481
|
* HTTP-КЛИЕНТ
|
|
473
482
|
* Author: MIOBOMB (2024-2026)
|
|
@@ -494,7 +503,7 @@ Intl.newHelper=function() {
|
|
|
494
503
|
|
|
495
504
|
xhr.open(method, url);
|
|
496
505
|
|
|
497
|
-
let allHeaders = { ...
|
|
506
|
+
let allHeaders = { ...window[_].http.defaultHeaders, ...headers };
|
|
498
507
|
for (let header in allHeaders)
|
|
499
508
|
xhr.setRequestHeader(header, allHeaders[header]);
|
|
500
509
|
|
|
@@ -522,18 +531,18 @@ Intl.newHelper=function() {
|
|
|
522
531
|
});
|
|
523
532
|
},
|
|
524
533
|
get: (url, headers={})=>
|
|
525
|
-
_.http.req('GET', url, false, headers),
|
|
534
|
+
window[_].http.req('GET', url, false, headers),
|
|
526
535
|
post: (url, data = '', headers = {}, fileProgressElement = false)=>
|
|
527
|
-
_.http.req('POST', url, data, headers, fileProgressElement)
|
|
528
|
-
}
|
|
536
|
+
window[_].http.req('POST', url, data, headers, fileProgressElement)
|
|
537
|
+
};
|
|
529
538
|
|
|
530
|
-
html(strs, ...args) {
|
|
539
|
+
window[_].html = function(strs, ...args) {
|
|
531
540
|
/*
|
|
532
541
|
* Шаблонные строки в DOM
|
|
533
542
|
* Author: MIOBOMB (2026)
|
|
534
543
|
* Last patch: 2.1.4
|
|
535
544
|
*
|
|
536
|
-
* Позволяет писать _.html`<div>${content}</div>`
|
|
545
|
+
* Позволяет писать window[_].html`<div>${content}</div>`
|
|
537
546
|
* И получать настоящий DOM-элемент, а не строку
|
|
538
547
|
*
|
|
539
548
|
* Почему через template?
|
|
@@ -543,6 +552,7 @@ Intl.newHelper=function() {
|
|
|
543
552
|
* - Банально удобнее createElement для сложных древ
|
|
544
553
|
*
|
|
545
554
|
* HMM: проверить производительность этого генератора dom
|
|
555
|
+
* HMM: проверить факт о "защите от xss" из-за on* атрибутов
|
|
546
556
|
*
|
|
547
557
|
* See also:
|
|
548
558
|
* - https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement
|
|
@@ -578,9 +588,9 @@ Intl.newHelper=function() {
|
|
|
578
588
|
if (content.children.length === 1)
|
|
579
589
|
return content.firstChild;
|
|
580
590
|
return content;
|
|
581
|
-
}
|
|
591
|
+
};
|
|
582
592
|
|
|
583
|
-
pipe(data, ...fns) {
|
|
593
|
+
window[_].pipe = function(data, ...fns) {
|
|
584
594
|
/*
|
|
585
595
|
* КАСТОМНЫЙ PIPE ОПЕРАТОР
|
|
586
596
|
* Author: MIOBOMB (2026)
|
|
@@ -595,9 +605,9 @@ Intl.newHelper=function() {
|
|
|
595
605
|
for (const fn of fns)
|
|
596
606
|
data = fn(data);
|
|
597
607
|
return data;
|
|
598
|
-
}
|
|
608
|
+
};
|
|
599
609
|
|
|
600
|
-
async
|
|
610
|
+
window[_].pipeAsync = async function(data, ...fns) {
|
|
601
611
|
/*
|
|
602
612
|
* КАСТОМНЫЙ PIPE ОПЕРАТОР 2
|
|
603
613
|
* Author: MIOBOMB (2026)
|
|
@@ -615,9 +625,9 @@ Intl.newHelper=function() {
|
|
|
615
625
|
data = await fn(waiter);
|
|
616
626
|
}
|
|
617
627
|
return data;
|
|
618
|
-
}
|
|
628
|
+
};
|
|
619
629
|
|
|
620
|
-
form
|
|
630
|
+
window[_].form = { // TS DONE HMM no
|
|
621
631
|
/*
|
|
622
632
|
* АВТОСОХРАНЕНИЕ ФОРМ
|
|
623
633
|
* Author: MIOBOMB (2026)
|
|
@@ -672,9 +682,9 @@ Intl.newHelper=function() {
|
|
|
672
682
|
});
|
|
673
683
|
return data;
|
|
674
684
|
},
|
|
675
|
-
}
|
|
685
|
+
};
|
|
676
686
|
|
|
677
|
-
storage
|
|
687
|
+
window[_].storage = class {
|
|
678
688
|
/*
|
|
679
689
|
* ИЗОЛЯТОР ХРАНИЛИЩ
|
|
680
690
|
* Author: MIOBOMB (2024-2026)
|
|
@@ -690,21 +700,21 @@ Intl.newHelper=function() {
|
|
|
690
700
|
* - https://developer.mozilla.org/en-US/docs/Web/API/Storage
|
|
691
701
|
*/
|
|
692
702
|
constructor(storage, name) {
|
|
693
|
-
this.
|
|
703
|
+
this.s = storage;
|
|
694
704
|
this.n = name;
|
|
695
705
|
}
|
|
696
706
|
get = key=>
|
|
697
|
-
this.
|
|
707
|
+
this.s.getItem(this.n + key);
|
|
698
708
|
set = (key, value)=>
|
|
699
|
-
this.
|
|
709
|
+
this.s.setItem(this.n + key, value);
|
|
700
710
|
remove = key=>
|
|
701
|
-
this.
|
|
702
|
-
clear = ()=>Object.keys(this.
|
|
711
|
+
this.s.removeItem(this.n + key);
|
|
712
|
+
clear = ()=>Object.keys(this.s)
|
|
703
713
|
.filter(k => k.startsWith(this.n))
|
|
704
|
-
.forEach(k => this.
|
|
705
|
-
}
|
|
714
|
+
.forEach(k => this.s.removeItem(k));
|
|
715
|
+
};
|
|
706
716
|
|
|
707
|
-
err
|
|
717
|
+
window[_].err = {
|
|
708
718
|
/*
|
|
709
719
|
* МОДУЛЬ ОШИБОК
|
|
710
720
|
* Author: MIOBOMB (2024-2026)
|
|
@@ -721,33 +731,33 @@ Intl.newHelper=function() {
|
|
|
721
731
|
* - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
|
|
722
732
|
*/
|
|
723
733
|
init() {
|
|
724
|
-
window.addEventListener('error',_.err.handleGlobal);
|
|
725
|
-
window.addEventListener('unhandledrejection',_.err.handleRejection);
|
|
734
|
+
window.addEventListener('error',window[_].err.handleGlobal);
|
|
735
|
+
window.addEventListener('unhandledrejection',window[_].err.handleRejection);
|
|
726
736
|
},
|
|
727
737
|
print: (cnt,e)=>console.error(e),
|
|
728
738
|
|
|
729
739
|
errors: {},
|
|
730
740
|
_c: 0,
|
|
731
741
|
log(err) {
|
|
732
|
-
_.err.print(_.err._c,err);
|
|
733
|
-
_.err._c++;
|
|
734
|
-
_.err.errors[_.err._c]=err;
|
|
742
|
+
window[_].err.print(window[_].err._c,err);
|
|
743
|
+
window[_].err._c++;
|
|
744
|
+
window[_].err.errors[window[_].err._c]=err;
|
|
735
745
|
},
|
|
736
746
|
handleGlobal(message,source,line,column,error){
|
|
737
747
|
console.error(message,source+':'+line+':'+column,error)
|
|
738
|
-
_.err.log(message + `\n IN ${source} ON LINE ${line} IN COLUMN ${column}`);
|
|
748
|
+
window[_].err.log(message + `\n IN ${source} ON LINE ${line} IN COLUMN ${column}`);
|
|
739
749
|
},
|
|
740
750
|
handleRejection(e){
|
|
741
751
|
const err = e.reason || e;
|
|
742
752
|
console.error(err);
|
|
743
|
-
_.err.log(
|
|
753
|
+
window[_].err.log(
|
|
744
754
|
`PROMISE ERROR\n`+
|
|
745
755
|
`${e.stack || e}`
|
|
746
756
|
);
|
|
747
757
|
},
|
|
748
|
-
}
|
|
758
|
+
};
|
|
749
759
|
|
|
750
|
-
hotkeys
|
|
760
|
+
window[_].hotkeys = {
|
|
751
761
|
/*
|
|
752
762
|
* ГОРЯЧИЕ КЛАВИШЫ
|
|
753
763
|
* Author: MIOBOMB (2025-2026)
|
|
@@ -785,18 +795,18 @@ Intl.newHelper=function() {
|
|
|
785
795
|
_parse: combo => combo.split('+').map(k=>k.trim()),
|
|
786
796
|
_match(keys) {
|
|
787
797
|
// Нужно сверять все клавишы, это же КОМБИНАЦИЯ а не отдельные куски
|
|
788
|
-
for (let k of keys) if (!
|
|
798
|
+
for (let k of keys) if (!window[_].hotkeys._holds.has(k)) return false;
|
|
789
799
|
return true;
|
|
790
800
|
},
|
|
791
801
|
_init() {
|
|
792
|
-
if (
|
|
802
|
+
if (window[_].hotkeys._)
|
|
793
803
|
return;
|
|
794
804
|
document.addEventListener('keydown', e=>{
|
|
795
|
-
|
|
805
|
+
window[_].hotkeys._holds.add(e.code);// key зависит от раскладки (на Qwerty 'KeyZ' — это 'z', на Йцукен — 'я')
|
|
796
806
|
// code даёт физическое положение клавиши, что важно для игр и хоткеев, и в целом универсальнее
|
|
797
807
|
|
|
798
|
-
for (let hotkey of
|
|
799
|
-
if (!
|
|
808
|
+
for (let hotkey of window[_].hotkeys.keys.values()) {
|
|
809
|
+
if (!window[_].hotkeys._match(hotkey.keys))
|
|
800
810
|
continue;
|
|
801
811
|
if (hotkey.press && !hotkey.active) {
|
|
802
812
|
hotkey.active = true; // active защищает от множественных срабатываний
|
|
@@ -805,10 +815,10 @@ Intl.newHelper=function() {
|
|
|
805
815
|
}
|
|
806
816
|
});
|
|
807
817
|
document.addEventListener('keyup', e=>{
|
|
808
|
-
|
|
818
|
+
window[_].hotkeys._holds.delete(e.code);
|
|
809
819
|
|
|
810
|
-
for (let hotkey of
|
|
811
|
-
if (hotkey.active && !
|
|
820
|
+
for (let hotkey of window[_].hotkeys.keys.values()) {
|
|
821
|
+
if (hotkey.active && !window[_].hotkeys._match(hotkey.keys)) {
|
|
812
822
|
hotkey.active=false;
|
|
813
823
|
hotkey.release(e);
|
|
814
824
|
}
|
|
@@ -819,21 +829,21 @@ Intl.newHelper=function() {
|
|
|
819
829
|
* При переключении в другое окно автоматического keyup не будет
|
|
820
830
|
* Поэтому сбрасываем всё принудительно, мало ли
|
|
821
831
|
*/
|
|
822
|
-
for (let hotkey of
|
|
832
|
+
for (let hotkey of window[_].hotkeys.keys.values()) {
|
|
823
833
|
if (hotkey.active) {
|
|
824
834
|
hotkey.active = false;
|
|
825
835
|
hotkey.release();
|
|
826
836
|
}
|
|
827
837
|
}
|
|
828
|
-
|
|
838
|
+
window[_].hotkeys._holds.clear();
|
|
829
839
|
});
|
|
830
|
-
|
|
840
|
+
window[_].hotkeys._=true;
|
|
831
841
|
},
|
|
832
842
|
on(combo, press, release) {
|
|
833
|
-
|
|
834
|
-
let keys =
|
|
843
|
+
window[_].hotkeys._init();
|
|
844
|
+
let keys = window[_].hotkeys._parse(combo);
|
|
835
845
|
|
|
836
|
-
|
|
846
|
+
window[_].hotkeys.keys.set(combo, {
|
|
837
847
|
keys,
|
|
838
848
|
// press/releace по умолчанию пустышки для сокращения синаксиса
|
|
839
849
|
press: press || (()=>{}),
|
|
@@ -844,12 +854,12 @@ Intl.newHelper=function() {
|
|
|
844
854
|
return this;
|
|
845
855
|
},
|
|
846
856
|
off(combo) {
|
|
847
|
-
|
|
857
|
+
window[_].hotkeys.keys.delete(combo);
|
|
848
858
|
return this;
|
|
849
859
|
},
|
|
850
|
-
}
|
|
860
|
+
};
|
|
851
861
|
|
|
852
|
-
drag
|
|
862
|
+
window[_].drag = {
|
|
853
863
|
/* МОДУЛЬ ДРАГГЕРА
|
|
854
864
|
* Author: MIOBOMB (2023-2026)
|
|
855
865
|
* Last patch: 2.1.7
|
|
@@ -866,6 +876,10 @@ Intl.newHelper=function() {
|
|
|
866
876
|
* А последний взятый элемент сильно фризит
|
|
867
877
|
* Я что зря делал проброс nginx'а на 192.168.0.*?
|
|
868
878
|
* Непорядок
|
|
879
|
+
* HMM:
|
|
880
|
+
* оставить сломанный мультитач потому что
|
|
881
|
+
* мне лень его чинить + наврядли кто то
|
|
882
|
+
* всерьёз будет двигать много элементов за раз
|
|
869
883
|
*
|
|
870
884
|
* See also:
|
|
871
885
|
* - https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/clientX
|
|
@@ -884,11 +898,11 @@ Intl.newHelper=function() {
|
|
|
884
898
|
let start=e=>{
|
|
885
899
|
// Проверяем куда нажали, если бы мы не проверяли,
|
|
886
900
|
// То драггер не дал бы нам нажать на кнопки или изменить имя окна
|
|
887
|
-
if (
|
|
901
|
+
if (window[_].drag.prevent(e)) return;
|
|
888
902
|
|
|
889
903
|
e.preventDefault();
|
|
890
904
|
|
|
891
|
-
|
|
905
|
+
window[_].drag.active.set(e.pointerId,{
|
|
892
906
|
x:e.clientX,
|
|
893
907
|
y:e.clientY,
|
|
894
908
|
mover:mover,
|
|
@@ -897,11 +911,11 @@ Intl.newHelper=function() {
|
|
|
897
911
|
|
|
898
912
|
onStart?.(e);
|
|
899
913
|
};
|
|
900
|
-
if (!
|
|
901
|
-
document.addEventListener("pointermove", (e) =>
|
|
902
|
-
document.addEventListener("pointerup", (e) =>
|
|
903
|
-
document.addEventListener("pointercancel", (e) =>
|
|
904
|
-
|
|
914
|
+
if (!window[_].drag._i) {
|
|
915
|
+
document.addEventListener("pointermove", (e) => window[_].drag.move(e));
|
|
916
|
+
document.addEventListener("pointerup", (e) => window[_].drag.stop(e));
|
|
917
|
+
document.addEventListener("pointercancel", (e) => window[_].drag.stop(e));
|
|
918
|
+
window[_].drag._i = true;
|
|
905
919
|
}
|
|
906
920
|
dragger.onpointerdown=start;
|
|
907
921
|
// превентим touchmove событие чтобы не было проблем
|
|
@@ -909,7 +923,7 @@ Intl.newHelper=function() {
|
|
|
909
923
|
dragger.ontouchmove=e=>e.preventDefault();
|
|
910
924
|
},
|
|
911
925
|
move(e) {
|
|
912
|
-
let p=
|
|
926
|
+
let p=window[_].drag.active.get(e.pointerId);
|
|
913
927
|
if(!p) return;
|
|
914
928
|
e.preventDefault();
|
|
915
929
|
|
|
@@ -924,20 +938,206 @@ Intl.newHelper=function() {
|
|
|
924
938
|
mov.style.left=(mov.offsetLeft - dx)+"px";
|
|
925
939
|
},
|
|
926
940
|
stop(e) {
|
|
927
|
-
|
|
928
|
-
|
|
941
|
+
window[_].drag.active.get(e.pointerId)?.onStop?.(e);
|
|
942
|
+
window[_].drag.active.delete(e.pointerId);
|
|
943
|
+
},
|
|
944
|
+
};
|
|
945
|
+
|
|
946
|
+
window[_].fade = function(elem, anim, actAfter = ()=>{}) {
|
|
947
|
+
if (!anim)
|
|
948
|
+
return actAfter();
|
|
949
|
+
elem.classList.add(anim);
|
|
950
|
+
elem.addEventListener('animationend', ()=>{
|
|
951
|
+
elem.classList.remove(anim);
|
|
952
|
+
actAfter();
|
|
953
|
+
}, { once: true });
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
window[_].x10 = {
|
|
957
|
+
/*
|
|
958
|
+
* МОДУЛЬ ОКОН (РЕАЛЬНЫЙ)
|
|
959
|
+
* Author: MIOBOMB (2026)
|
|
960
|
+
* Last patch: 2.1.8
|
|
961
|
+
*
|
|
962
|
+
* Помните прошлый и уродливый win?
|
|
963
|
+
* Я теперь понял что насрал говна и решил подсмотреть
|
|
964
|
+
* архитектуру у гениев своего времени.
|
|
965
|
+
* По итогу я создал это чудо юдо чтобы поверх него строить "оконные менеджеры"!
|
|
966
|
+
* Прошлый модуль win все ещё останется рабочим и возможно
|
|
967
|
+
* будет встроенным wm как это сделано в реальных иксах с toms window manager.
|
|
968
|
+
* В отличии от реального x.org у меня будет реализована возможность
|
|
969
|
+
* исполнять несколько оконных менеджеров в одной сессии,
|
|
970
|
+
* нужно мне это чтобы модуль toast мог просто создавать для каждого
|
|
971
|
+
* инстанса тостов свой очень тонкий wm.
|
|
972
|
+
*
|
|
973
|
+
* СОСТОЯНИЯ ОКОН
|
|
974
|
+
* Это вообще отдельная тема, которую мне стоит осветить особенно от x10.
|
|
975
|
+
* Дело в том, что я вам дарую свободу обзывать и вешать в состояния окон
|
|
976
|
+
* всё что вам вздумается! Только пожалуйста, давайте не будем творить что попало
|
|
977
|
+
* и мы примим этот "контракт" о выдаче названий состояний окон:
|
|
978
|
+
*
|
|
979
|
+
* opened - окно открыто и видно
|
|
980
|
+
* hidened - окно скрыто
|
|
981
|
+
* opening - окно в анимации открытия
|
|
982
|
+
* hiding - окно в анимации сворачивания
|
|
983
|
+
* showing - окно в анимации разворачивания
|
|
984
|
+
* moving - окно в анимации движения
|
|
985
|
+
* closing - окно входит в анимацию закрытия и скоро умрёт
|
|
986
|
+
*
|
|
987
|
+
* Да, я сам эти состояния пока не использую в win, но к какой нибуть 2.4
|
|
988
|
+
* я начну над этим работать
|
|
989
|
+
* FIXME: прописать newHelper win адекватную работу со всеми состояниями
|
|
990
|
+
* FIXME: создать x10.iterate функцию
|
|
991
|
+
*
|
|
992
|
+
* !!!: это x.org! Тупая софтина которая просто хранит окна и плюёт события!
|
|
993
|
+
* Управлять окнами и DOM'ом окон все ещё будет оконный менеджер!
|
|
994
|
+
*
|
|
995
|
+
* See also:
|
|
996
|
+
* - https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
|
|
997
|
+
* - https://en.wikipedia.org/wiki/X_Window_System (будет полезно понимать)
|
|
998
|
+
*/
|
|
999
|
+
busName: 'xws:',
|
|
1000
|
+
|
|
1001
|
+
generateId() {
|
|
1002
|
+
let id;
|
|
1003
|
+
// Создаём случайный 6 символьный айди, чтобы каждый раз не совпадало
|
|
1004
|
+
// !!!: в теории можно задать любой айди
|
|
1005
|
+
// HMM: проверить при скольки окнах генератор начинает тормозить
|
|
1006
|
+
do id=Math.random().toString(36).substring(2,8);
|
|
1007
|
+
while (window[_].wins[id]);
|
|
1008
|
+
//while (window[_].wins.has(id));
|
|
1009
|
+
return id;
|
|
1010
|
+
},
|
|
1011
|
+
|
|
1012
|
+
// метод spit() публичный, если вам нужны какие то
|
|
1013
|
+
// специфичные события для вашего WM - пожалуйста
|
|
1014
|
+
// HMM: дать ли ему нормальное название или нет
|
|
1015
|
+
spit(evName, data) {
|
|
1016
|
+
let event = new CustomEvent(window[_].x10.busName + evName, data)
|
|
1017
|
+
document.dispatchEvent(event);
|
|
1018
|
+
},
|
|
1019
|
+
|
|
1020
|
+
create(name, patcher) {
|
|
1021
|
+
let winId = window[_].x10.generateId(),
|
|
1022
|
+
state = {
|
|
1023
|
+
id: winId,
|
|
1024
|
+
name: name,
|
|
1025
|
+
state: 'opened',
|
|
1026
|
+
wm: '',
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
// оконные менеджеры могут вешать свои флаги в окна
|
|
1030
|
+
Object.assign(state, patcher);
|
|
1031
|
+
window[_].wins[winId] = state;
|
|
1032
|
+
window[_].x10.spit('created', window[_].wins[winId]);
|
|
1033
|
+
|
|
1034
|
+
return window[_].wins[winId];
|
|
929
1035
|
},
|
|
930
|
-
},
|
|
931
1036
|
|
|
932
|
-
|
|
1037
|
+
get(winId) {
|
|
1038
|
+
return window[_].wins[winId];
|
|
1039
|
+
},
|
|
1040
|
+
|
|
1041
|
+
// vim ciw отсылка лол
|
|
1042
|
+
ciw(winId, attr, value, events = false) {
|
|
1043
|
+
let winData = window[_].wins[winId];
|
|
1044
|
+
winData[attr] = value;
|
|
1045
|
+
if (events) {
|
|
1046
|
+
window[_].x10.spit('patched', {[attr]: value});
|
|
1047
|
+
window[_].x10.spit('patched:' + attr, value);
|
|
1048
|
+
}
|
|
1049
|
+
},
|
|
1050
|
+
|
|
1051
|
+
setState(winId, state) {
|
|
1052
|
+
let winData = window[_].wins[winId];
|
|
1053
|
+
winData.state = state;
|
|
1054
|
+
window[_].x10.spit('state:' + state, winData);
|
|
1055
|
+
return winData;
|
|
1056
|
+
},
|
|
1057
|
+
|
|
1058
|
+
destroy(winId) {
|
|
1059
|
+
window[_].x10.spit('destroyed', window[_].wins[winId]);
|
|
1060
|
+
delete window[_].wins[winId];
|
|
1061
|
+
},
|
|
1062
|
+
};
|
|
1063
|
+
|
|
1064
|
+
window[_].toast = class {
|
|
1065
|
+
/*
|
|
1066
|
+
* МОДУЛЬ УВЕДОМЛЕНИЙ
|
|
1067
|
+
* Author: MIOBOMB (2026)
|
|
1068
|
+
* Last patch: 2.1.8
|
|
1069
|
+
*
|
|
1070
|
+
* Является фабрикой оконных менеджеров, работает по такому принципу:
|
|
1071
|
+
* errAlert = new window[_].toast('error', DOMelem)
|
|
1072
|
+
* okAlert = new window[_].toast('ok', DOMelem)
|
|
1073
|
+
* loadingAnim = new window[_].toast('loading', DOMelem, 0)
|
|
1074
|
+
*
|
|
1075
|
+
* Сам тонкий оконный менеджер крайне примитивный и простой,
|
|
1076
|
+
* но для тостов обычно большего и не надо.
|
|
1077
|
+
*
|
|
1078
|
+
* Вы также можете переопределить метод generateDOM
|
|
1079
|
+
* под ваши нужны. В целом, это безопасно если иметь меру.
|
|
1080
|
+
* в Object hub это уже используется повсеместно.
|
|
1081
|
+
*
|
|
1082
|
+
* !!!:
|
|
1083
|
+
* если duration = 0 то тост будет закрыт только при вызове close()
|
|
1084
|
+
* !!!:
|
|
1085
|
+
* не вешайте manager'ом document.body!
|
|
1086
|
+
* управление позицией окон отдано на откуп DOM и CSS,
|
|
1087
|
+
* вам придётся настроить элемент менеджера и классы или стили
|
|
1088
|
+
* тостов, чтобы они позиционировались адекватно
|
|
1089
|
+
*/
|
|
1090
|
+
|
|
1091
|
+
constructor(name, manager, duration = 3000, attrs = '', animOpen = '', animClose = '') {
|
|
1092
|
+
this.name = name;
|
|
1093
|
+
this.wm = 'newHelper-toast-' + this.name;
|
|
1094
|
+
this.manager = manager;
|
|
1095
|
+
this.duration = duration;
|
|
1096
|
+
this.attrs = attrs;
|
|
1097
|
+
this.animOpen = animOpen;
|
|
1098
|
+
this.animClose = animClose;
|
|
1099
|
+
}
|
|
1100
|
+
generateDOM = (wId,content) => `<div style=overflow:auto;width:100%;height:100%>${content}</div>`.replace(/\{winId\}/g,wId)
|
|
1101
|
+
|
|
1102
|
+
open(content = '') {
|
|
1103
|
+
let winState = window[_].x10.create(this.name, { wm: this.wm }),
|
|
1104
|
+
wId = winState.id,
|
|
1105
|
+
html = window[_].html`<div id=${wId} ${this.attrs}>
|
|
1106
|
+
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
1107
|
+
${this.generateDOM(wId, content)}
|
|
1108
|
+
</div>
|
|
1109
|
+
</div>`;
|
|
1110
|
+
window[_].fade(html, this.animOpen);
|
|
1111
|
+
this.manager.append(html);
|
|
1112
|
+
|
|
1113
|
+
// сохраним ссылку на dom чтобы достать её в close()
|
|
1114
|
+
// HMM: а может писать в this.elem
|
|
1115
|
+
window[_].x10.ciw(wId, 'elem', document.getElementById(wId));
|
|
1116
|
+
|
|
1117
|
+
if (this.duration > 0)
|
|
1118
|
+
setTimeout(() => this.close(wId), this.duration)
|
|
1119
|
+
}
|
|
1120
|
+
close(winId) {
|
|
1121
|
+
let win = window[_].x10.get(winId), w;
|
|
1122
|
+
if (!win || win.wm !== this.wm)
|
|
1123
|
+
return;
|
|
1124
|
+
w = win.elem;
|
|
1125
|
+
window[_].fade(w, this.animClose, ()=>{
|
|
1126
|
+
w.remove();
|
|
1127
|
+
window[_].x10.destroy(winId);
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
window[_].win = {
|
|
933
1133
|
/*
|
|
934
1134
|
* МОДУЛЬ ОКОН
|
|
935
1135
|
* Author: MIOBOMB (2023-2026)
|
|
936
|
-
* Last patch: 2.1.
|
|
1136
|
+
* Last patch: 2.1.8
|
|
937
1137
|
*
|
|
938
1138
|
* если вы спросите почему ньюхелпер я отвечу
|
|
939
|
-
* winBox.js это 35 килобайт, здесь же вы получаете в
|
|
940
|
-
* И более
|
|
1139
|
+
* winBox.js это 35 килобайт, здесь же вы получаете в 65 килобайт
|
|
1140
|
+
* И более мощный движок окон и документацию уровня...
|
|
941
1141
|
* А у кого нибуть вообще есть такие подробные документации в вебе?
|
|
942
1142
|
*
|
|
943
1143
|
* Реализует ограниченно-гибкий движок окон, функционал:
|
|
@@ -948,6 +1148,7 @@ Intl.newHelper=function() {
|
|
|
948
1148
|
* - сохранение и загрузка окон по вашему выбору
|
|
949
1149
|
*
|
|
950
1150
|
* теперь мне надо вспомнить я рефакторил этот код 4 раза или 7 раз
|
|
1151
|
+
* 25:06:2026 - Вспомнил! раз 6 точно, +x10 значит это уже 7 раз
|
|
951
1152
|
*
|
|
952
1153
|
* !!!: _opn() и toggleFull() могут сломать ваши окна!
|
|
953
1154
|
* Эти функции высчитывают координаты окна, и размер окна с учётом padding'а
|
|
@@ -960,9 +1161,9 @@ Intl.newHelper=function() {
|
|
|
960
1161
|
*
|
|
961
1162
|
* FIXME: вынести lang.winTitle из переводов для устранения "связности" кода
|
|
962
1163
|
*
|
|
963
|
-
* FIXME: придумать что делать с переездом _.wins на new Map
|
|
1164
|
+
* FIXME: придумать что делать с переездом window[_].wins на new Map
|
|
964
1165
|
* я уже пробовал перенос на мапу и результат...
|
|
965
|
-
*
|
|
1166
|
+
* у меня сломались все окна в object hub'е
|
|
966
1167
|
* по этому пусть пока хоть до 2.5 будет объект
|
|
967
1168
|
*
|
|
968
1169
|
* See also:
|
|
@@ -977,6 +1178,7 @@ Intl.newHelper=function() {
|
|
|
977
1178
|
* - html модуль
|
|
978
1179
|
* - lang.winTitle функция
|
|
979
1180
|
* - drag модуль
|
|
1181
|
+
* - x10 подсистема
|
|
980
1182
|
*/
|
|
981
1183
|
manager:false,
|
|
982
1184
|
hider:false,
|
|
@@ -1002,51 +1204,25 @@ Intl.newHelper=function() {
|
|
|
1002
1204
|
animFullOn:'',
|
|
1003
1205
|
animFullOff:'',
|
|
1004
1206
|
|
|
1005
|
-
|
|
1006
|
-
if (anim) {
|
|
1007
|
-
elem.classList.add(anim);
|
|
1008
|
-
actPre();
|
|
1009
|
-
elem.addEventListener('animationend', ()=>{
|
|
1010
|
-
elem.classList.remove(anim);
|
|
1011
|
-
actAfter();
|
|
1012
|
-
}, { once: true });
|
|
1013
|
-
} else {
|
|
1014
|
-
actPre();
|
|
1015
|
-
actAfter();
|
|
1016
|
-
}
|
|
1017
|
-
},
|
|
1018
|
-
|
|
1019
|
-
_ID(){
|
|
1020
|
-
let id;
|
|
1021
|
-
// Создаём случайный 6 символьный айди, чтобы каждый раз не совпадало
|
|
1022
|
-
// !!!: в теории можно задать любой айди
|
|
1023
|
-
// HMM: проверить при скольки окнах генератор начинает тормозить
|
|
1024
|
-
do id=Math.random().toString(36).substring(2,8);
|
|
1025
|
-
while (_.wins[id]);
|
|
1026
|
-
//while (_.wins.has(id));
|
|
1027
|
-
return id;
|
|
1028
|
-
},
|
|
1207
|
+
|
|
1029
1208
|
_winBtn(win,text,func){
|
|
1030
|
-
let b=_.html`<button ${
|
|
1209
|
+
let b=window[_].html`<button ${window[_].win.btnAttrs}>${text}</button>`;
|
|
1031
1210
|
b.addEventListener('click',()=>func(win));
|
|
1032
1211
|
return b;
|
|
1033
1212
|
},
|
|
1034
1213
|
_hiderBtn(win){
|
|
1035
|
-
let title=win.langs!== false ? _.lang.winTitle(_.win.text+win.langs) : `>${win.name}<`,
|
|
1036
|
-
b=_.html`<button id=hider${win.id} ${
|
|
1037
|
-
b.addEventListener('click',()=>
|
|
1214
|
+
let title=win.langs!== false ? window[_].lang.winTitle(window[_].win.text+win.langs) : `>${win.name}<`,
|
|
1215
|
+
b=window[_].html`<button id=hider${win.id} ${window[_].win.hiderAttrs}${title}/button>`;
|
|
1216
|
+
b.addEventListener('click',()=>window[_].win.show(win));
|
|
1038
1217
|
return b;
|
|
1039
1218
|
},
|
|
1040
|
-
|
|
1041
1219
|
_initWin: winState=>
|
|
1042
|
-
_.drag.init(winState.drag, winState.elem, ()=>_.win.manager.appendChild(winState.elem)),
|
|
1220
|
+
window[_].drag.init(winState.drag, winState.elem, ()=>window[_].win.manager.appendChild(winState.elem)),
|
|
1221
|
+
|
|
1043
1222
|
open(name,content='',customAttrs=''){
|
|
1044
|
-
let
|
|
1045
|
-
|
|
1046
|
-
id:winId,
|
|
1047
|
-
name:name,
|
|
1223
|
+
let winState = {
|
|
1224
|
+
wm: 'newHelper-win',
|
|
1048
1225
|
langs:name,
|
|
1049
|
-
state:'opened',
|
|
1050
1226
|
full:false,
|
|
1051
1227
|
inRename:false,
|
|
1052
1228
|
// Если окно новое, координаты полностью нулевые,
|
|
@@ -1056,49 +1232,58 @@ Intl.newHelper=function() {
|
|
|
1056
1232
|
elem:false,
|
|
1057
1233
|
drag:false,
|
|
1058
1234
|
content:false,
|
|
1059
|
-
|
|
1060
|
-
|
|
1235
|
+
|
|
1236
|
+
setTitle(nT) {window[_].win.setTitle(this,nT)},
|
|
1237
|
+
toggleFull(e) {window[_].win.toggleFull(this)},
|
|
1238
|
+
close(e) {window[_].win.close(this)},
|
|
1239
|
+
hide(e) {window[_].win.hide(this)},
|
|
1240
|
+
show(e) {window[_].win.show(this)},
|
|
1241
|
+
},
|
|
1242
|
+
winData = window[_].x10.create(name, winState);
|
|
1243
|
+
return window[_].win._opn(winData,content);
|
|
1061
1244
|
},
|
|
1062
1245
|
_opn(winState,content=''){
|
|
1063
|
-
|
|
1064
|
-
|
|
1246
|
+
// эти проверки жрут драгоценные байты
|
|
1247
|
+
// if (!window[_].win.manager || !window[_].win.hider) throw new Error('Window managers not inited');
|
|
1065
1248
|
let wId=winState.id,
|
|
1066
1249
|
html=
|
|
1067
|
-
_.html`<div id=${wId} ${
|
|
1250
|
+
window[_].html`<div id=${wId} ${window[_].win.winAttrs} ${winState.attrs}>
|
|
1068
1251
|
<div style="display:flex;justify-content:space-between;align-items:center"
|
|
1069
|
-
${
|
|
1070
|
-
<span ${
|
|
1252
|
+
${window[_].win.dragAttrs} id=DRAGGER${wId}>
|
|
1253
|
+
<span ${window[_].win.titleAttrs} id=title${wId}${window[_].lang.winTitle(window[_].win.text+winState.name)}/span>
|
|
1071
1254
|
<div id=btns${wId}></div>
|
|
1072
1255
|
</div>
|
|
1073
1256
|
<div id=content${wId} style=overflow:auto;width:100%;height:100%>
|
|
1074
1257
|
${content.replace(/\{winId\}/g,wId)}
|
|
1075
1258
|
</div>
|
|
1076
1259
|
</div>`,
|
|
1077
|
-
btns=html.querySelector(`#btns${wId}`);
|
|
1078
|
-
for(let b of
|
|
1079
|
-
html.style.overflow='hidden';
|
|
1080
|
-
html.style.resize='both';
|
|
1260
|
+
btns = html.querySelector(`#btns${wId}`);
|
|
1261
|
+
for(let b of window[_].win.defBtns) btns.append(window[_].win._winBtn(winState,...b));
|
|
1262
|
+
html.style.overflow = 'hidden';
|
|
1263
|
+
html.style.resize = 'both';
|
|
1264
|
+
|
|
1265
|
+
window[_].fade(html, window[_].win.animOpen)
|
|
1081
1266
|
|
|
1082
|
-
|
|
1267
|
+
window[_].win.manager.append(html);
|
|
1268
|
+
|
|
1269
|
+
// AFTER INSERT LOGISC !!!!!!!!!!!!!!!!
|
|
1083
1270
|
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
winState.hide=e=>_.win.hide(winState);
|
|
1088
|
-
winState.show=e=>_.win.show(winState);
|
|
1089
|
-
this.manager.append(html);
|
|
1271
|
+
let mainElem = document.getElementById(wId),
|
|
1272
|
+
dragElem = document.getElementById('DRAGGER'+wId),
|
|
1273
|
+
contentElem = document.getElementById('content'+wId);
|
|
1090
1274
|
|
|
1091
|
-
let win=winState.elem=
|
|
1092
|
-
contentRect=document.getElementById('content'+wId).getBoundingClientRect(),
|
|
1093
|
-
windowRect=win.getBoundingClientRect(),
|
|
1275
|
+
let win = winState.elem = mainElem,
|
|
1276
|
+
contentRect = document.getElementById('content'+wId).getBoundingClientRect(),
|
|
1277
|
+
windowRect = win.getBoundingClientRect(),
|
|
1094
1278
|
padX=windowRect.width - contentRect.width,padY=windowRect.height - contentRect.height;
|
|
1095
|
-
winState.drag=
|
|
1096
|
-
winState.content=
|
|
1279
|
+
winState.drag = dragElem,
|
|
1280
|
+
winState.content = contentElem;
|
|
1097
1281
|
|
|
1098
1282
|
if (winState.onUnfull.width === 0) {
|
|
1099
1283
|
// Здесь и задаются координаты...
|
|
1100
1284
|
// Мастера клин кода не выносите мне мозги прошу
|
|
1101
1285
|
// Оно же работает!!!
|
|
1286
|
+
// 26:06:2026 - и вроде гзипается хорошо
|
|
1102
1287
|
if (!winState.attrs.includes('top')) {
|
|
1103
1288
|
win.style.top=win.offsetTop - (win.offsetHeight / 2) + 'px';
|
|
1104
1289
|
win.style.left=win.offsetLeft - (win.offsetWidth / 2) + 'px';
|
|
@@ -1111,125 +1296,126 @@ Intl.newHelper=function() {
|
|
|
1111
1296
|
for (let pos in winState.onUnfull)
|
|
1112
1297
|
win.style[pos] = winState.onUnfull[pos] + 'px'
|
|
1113
1298
|
|
|
1114
|
-
|
|
1115
|
-
winState.drag.addEventListener('contextmenu',(e)=>{
|
|
1299
|
+
dragElem.addEventListener('contextmenu', function(e) {
|
|
1116
1300
|
e.preventDefault();
|
|
1117
|
-
if(e.target.closest('button')) return;
|
|
1118
|
-
let wT=document.getElementById('title'+wId);
|
|
1301
|
+
if (e.target.closest('button')) return;
|
|
1302
|
+
let wT = document.getElementById('title'+wId);
|
|
1119
1303
|
if (!winState.inRename){
|
|
1120
|
-
wT.innerHTML=`<input ${
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
winState.
|
|
1304
|
+
wT.innerHTML=`<input ${window[_].win.renameAttrs} id=rename${wId} value="${wT.textContent}">`;
|
|
1305
|
+
window[_].x10.ciw(wId,'inRename',true);
|
|
1306
|
+
//winState.inRename=true;
|
|
1307
|
+
} else {
|
|
1308
|
+
window[_].win.setTitle(winState,document.getElementById('rename'+wId).value);
|
|
1309
|
+
window[_].x10.ciw(wId,'inRename',false);
|
|
1310
|
+
//winState.inRename=false;
|
|
1125
1311
|
}
|
|
1126
1312
|
});
|
|
1127
1313
|
|
|
1128
|
-
if (winState.state === 'hidened')
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1314
|
+
if (winState.state === 'hidened')
|
|
1315
|
+
winState.hide();
|
|
1316
|
+
else
|
|
1317
|
+
window[_].win._initWin(winState);
|
|
1132
1318
|
return winState;
|
|
1133
1319
|
},
|
|
1134
1320
|
|
|
1135
|
-
setTitle(winState,newT){
|
|
1136
|
-
winState.langs
|
|
1137
|
-
winState.name
|
|
1321
|
+
setTitle(winState, newT) {
|
|
1322
|
+
window[_].x10.ciw(winState.id,'langs',false);
|
|
1323
|
+
window[_].x10.ciw(winState.id,'name',newT);
|
|
1138
1324
|
let t=document.getElementById('title'+winState.id),
|
|
1139
1325
|
h=document.getElementById('hider'+winState.id);
|
|
1140
1326
|
t.innerHTML=newT;
|
|
1141
1327
|
t.removeAttribute('data-trans');
|
|
1142
|
-
if (h){
|
|
1328
|
+
if (h) {
|
|
1143
1329
|
h.innerHTML=newT;
|
|
1144
1330
|
h.removeAttribute('data-trans');
|
|
1145
1331
|
}
|
|
1146
1332
|
},
|
|
1147
1333
|
|
|
1148
|
-
toggleFull(winState){
|
|
1149
|
-
let wEl=winState.elem,
|
|
1150
|
-
ws=wEl.style,
|
|
1151
|
-
wc=wEl.classList,
|
|
1152
|
-
contentRect=document.getElementById('content'+winState.id).getBoundingClientRect(),
|
|
1153
|
-
windowRect=wEl.getBoundingClientRect(),
|
|
1154
|
-
padX=windowRect.width - contentRect.width,
|
|
1155
|
-
padY=windowRect.height - contentRect.height,
|
|
1156
|
-
aOn=
|
|
1157
|
-
aOff=
|
|
1158
|
-
fd={
|
|
1334
|
+
toggleFull(winState) {
|
|
1335
|
+
let wEl = winState.elem,
|
|
1336
|
+
ws = wEl.style,
|
|
1337
|
+
wc = wEl.classList,
|
|
1338
|
+
contentRect = document.getElementById('content'+winState.id).getBoundingClientRect(),
|
|
1339
|
+
windowRect = wEl.getBoundingClientRect(),
|
|
1340
|
+
padX = windowRect.width - contentRect.width,
|
|
1341
|
+
padY = windowRect.height - contentRect.height,
|
|
1342
|
+
aOn = window[_].win.animFullOn,
|
|
1343
|
+
aOff = window[_].win.animFullOff,
|
|
1344
|
+
fd = {
|
|
1159
1345
|
top: windowRect.top, left: windowRect.left,
|
|
1160
1346
|
width: contentRect.width, height: contentRect.height,
|
|
1161
1347
|
},
|
|
1162
|
-
unful=()=>{
|
|
1163
|
-
ws.top=old.top + 'px';
|
|
1164
|
-
ws.left=old.left + 'px';
|
|
1165
|
-
ws.width=old.width + 'px';
|
|
1166
|
-
ws.height=old.height + 'px';
|
|
1348
|
+
unful = ()=>{
|
|
1349
|
+
ws.top = old.top + 'px';
|
|
1350
|
+
ws.left = old.left + 'px';
|
|
1351
|
+
ws.width = old.width + 'px';
|
|
1352
|
+
ws.height = old.height + 'px';
|
|
1167
1353
|
},
|
|
1168
|
-
doFul=()=>{
|
|
1354
|
+
doFul = ()=>{
|
|
1169
1355
|
if (aOn) wc.remove(aOn);
|
|
1170
|
-
winState.full
|
|
1171
|
-
winState.onUnfull
|
|
1172
|
-
ws.top=0;
|
|
1173
|
-
ws.left=0;
|
|
1174
|
-
ws.width
|
|
1175
|
-
ws.height
|
|
1176
|
-
winState.drag.onpointerdown=null;
|
|
1356
|
+
window[_].x10.ciw(winState.id,'full',true);
|
|
1357
|
+
window[_].x10.ciw(winState.id,'onUnfull',fd);
|
|
1358
|
+
ws.top = 0;
|
|
1359
|
+
ws.left = 0;
|
|
1360
|
+
ws.width = `calc(100% - ${padX}px)`;
|
|
1361
|
+
ws.height = `calc(100% - ${padY}px)`;
|
|
1362
|
+
winState.drag.onpointerdown = null;
|
|
1177
1363
|
},
|
|
1178
|
-
doUnful=()=>{
|
|
1364
|
+
doUnful = ()=>{
|
|
1179
1365
|
if (aOff) wc.remove(aOff);
|
|
1180
1366
|
unful();
|
|
1181
|
-
winState.full
|
|
1182
|
-
|
|
1367
|
+
window[_].x10.ciw(winState.id,'full',false);
|
|
1368
|
+
window[_].win._initWin(winState);
|
|
1183
1369
|
},
|
|
1184
|
-
old=winState.onUnfull;
|
|
1370
|
+
old = winState.onUnfull;
|
|
1185
1371
|
if (!winState.full)
|
|
1186
|
-
|
|
1187
|
-
else
|
|
1188
|
-
|
|
1372
|
+
window[_].fade(wEl, window[_].win.animFullOn, doFul)
|
|
1373
|
+
else {
|
|
1374
|
+
unful();
|
|
1375
|
+
window[_].fade(wEl, window[_].win.animFullOff, doUnful);
|
|
1376
|
+
}
|
|
1189
1377
|
},
|
|
1190
1378
|
|
|
1191
|
-
close(winState){
|
|
1192
|
-
let w=winState.elem,
|
|
1193
|
-
remover=()=>{
|
|
1194
|
-
let dr=winState.drag;
|
|
1195
|
-
dr.onpointerdown=dr.ontouchmove=null;
|
|
1379
|
+
close(winState) {
|
|
1380
|
+
let w = winState.elem,
|
|
1381
|
+
remover = ()=>{
|
|
1382
|
+
let dr = winState.drag;
|
|
1383
|
+
dr.onpointerdown = dr.ontouchmove=null;
|
|
1196
1384
|
w.remove();
|
|
1197
|
-
|
|
1198
|
-
//_.wins.delete(winState.id);
|
|
1385
|
+
window[_].x10.destroy(winState.id);
|
|
1199
1386
|
};
|
|
1200
1387
|
if (w.style.display== 'none') {
|
|
1201
1388
|
document.getElementById('hider'+winState.id).remove();
|
|
1202
1389
|
remover();
|
|
1203
1390
|
} else
|
|
1204
|
-
|
|
1205
|
-
|
|
1391
|
+
window[_].fade(w, window[_].win.animClose, remover);
|
|
1206
1392
|
},
|
|
1207
1393
|
|
|
1208
|
-
hide(winState){
|
|
1209
|
-
let wEl=winState.elem,
|
|
1210
|
-
wc=wEl.classList,
|
|
1211
|
-
anim=
|
|
1212
|
-
hider=()=>{
|
|
1213
|
-
wEl.style.display='none';
|
|
1214
|
-
if(anim)wc.remove(anim);
|
|
1215
|
-
winState.
|
|
1216
|
-
|
|
1394
|
+
hide(winState) {
|
|
1395
|
+
let wEl = winState.elem,
|
|
1396
|
+
wc = wEl.classList,
|
|
1397
|
+
anim = window[_].win.animHide,
|
|
1398
|
+
hider = ()=>{
|
|
1399
|
+
wEl.style.display = 'none';
|
|
1400
|
+
if (anim) wc.remove(anim);
|
|
1401
|
+
window[_].x10.setState(winState.id,'hidened');
|
|
1402
|
+
window[_].win.hider.append(window[_].win._hiderBtn(winState));
|
|
1217
1403
|
}
|
|
1218
|
-
|
|
1404
|
+
window[_].fade(wEl, window[_].win.animHide, hider);
|
|
1219
1405
|
},
|
|
1220
1406
|
|
|
1221
|
-
show(winState){
|
|
1222
|
-
let wEl=winState.elem,
|
|
1223
|
-
wc=wEl.classList,
|
|
1224
|
-
anim=
|
|
1225
|
-
hider=document.getElementById('hider'+winState.id),
|
|
1226
|
-
shower=()=>{
|
|
1227
|
-
if(anim)wc.remove(anim);
|
|
1228
|
-
winState.
|
|
1407
|
+
show(winState) {
|
|
1408
|
+
let wEl = winState.elem,
|
|
1409
|
+
wc = wEl.classList,
|
|
1410
|
+
anim = window[_].win.animShow,
|
|
1411
|
+
hider = document.getElementById('hider'+winState.id),
|
|
1412
|
+
shower = ()=>{
|
|
1413
|
+
if (anim) wc.remove(anim);
|
|
1414
|
+
window[_].x10.setState(winState.id,'opened');
|
|
1229
1415
|
}
|
|
1230
|
-
wEl.style.display='';
|
|
1416
|
+
wEl.style.display = '';
|
|
1231
1417
|
hider.remove();
|
|
1232
|
-
|
|
1418
|
+
window[_].fade(wEl, window[_].win.animShow, shower);
|
|
1233
1419
|
},
|
|
1234
1420
|
|
|
1235
1421
|
/*
|
|
@@ -1245,12 +1431,14 @@ Intl.newHelper=function() {
|
|
|
1245
1431
|
* Или как вы ещё придумаете
|
|
1246
1432
|
*
|
|
1247
1433
|
* !!!: Оно работает настолько гибко что в теории можно сделать виртуальные рабочие столы
|
|
1434
|
+
*
|
|
1435
|
+
* FIXME: добавить проверку принадлежности WM
|
|
1248
1436
|
*/
|
|
1249
1437
|
read(){
|
|
1250
1438
|
let store = {};
|
|
1251
|
-
for (let winId in _.wins) {
|
|
1252
|
-
let winPre = _.wins[winId];
|
|
1253
|
-
//for (let [winId, winPre] of _.wins) {
|
|
1439
|
+
for (let winId in window[_].wins) {
|
|
1440
|
+
let winPre = window[_].wins[winId];
|
|
1441
|
+
//for (let [winId, winPre] of window[_].wins) {
|
|
1254
1442
|
let win = { ...winPre },
|
|
1255
1443
|
size=win.onUnfull,
|
|
1256
1444
|
wEl = win.elem,
|
|
@@ -1273,24 +1461,24 @@ Intl.newHelper=function() {
|
|
|
1273
1461
|
let win=state[winId],
|
|
1274
1462
|
content=win.realContent;
|
|
1275
1463
|
delete win.realContent;
|
|
1276
|
-
_.wins[winId] = win;
|
|
1277
|
-
//_.wins.set(winId, win);
|
|
1278
|
-
|
|
1464
|
+
window[_].wins[winId] = win;
|
|
1465
|
+
//window[_].wins.set(winId, win);
|
|
1466
|
+
window[_].win._opn(win,content);
|
|
1279
1467
|
}
|
|
1280
|
-
return _.wins;
|
|
1468
|
+
return window[_].wins;
|
|
1281
1469
|
},
|
|
1282
|
-
}
|
|
1470
|
+
};
|
|
1283
1471
|
|
|
1284
|
-
wins
|
|
1472
|
+
window[_].wins = {};
|
|
1285
1473
|
//wins: new Map(),
|
|
1286
|
-
|
|
1287
|
-
return _
|
|
1474
|
+
|
|
1475
|
+
return window[_];
|
|
1288
1476
|
};
|
|
1289
1477
|
|
|
1290
1478
|
/* полифиллы к удалённым модулям
|
|
1291
1479
|
* (сделаны в формате плагинов)
|
|
1292
1480
|
* DOM хелпер ($), удалён в 2.1.X:
|
|
1293
|
-
_.$ = {
|
|
1481
|
+
window[_].$ = {
|
|
1294
1482
|
D: document,
|
|
1295
1483
|
id: i=> document.getElementById(i),
|
|
1296
1484
|
q: (i,p=document)=> p.querySelector(i),
|
|
@@ -1307,4 +1495,3 @@ _.$ = {
|
|
|
1307
1495
|
* 2. в следствие пункта 1 я удалил весь синтаксический сахар
|
|
1308
1496
|
* потому что "document." гзипается заметно лучше
|
|
1309
1497
|
*/
|
|
1310
|
-
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newhelper-js",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.8",
|
|
4
4
|
"description": "сверх лёгкая библиотека для построения админок",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"admin",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"dialog",
|
|
11
11
|
"router",
|
|
12
12
|
"window-manager",
|
|
13
|
+
"desktop",
|
|
13
14
|
"i18n",
|
|
14
15
|
"internationalization",
|
|
15
16
|
"lazy-loading",
|
|
@@ -17,7 +18,9 @@
|
|
|
17
18
|
"lightweight",
|
|
18
19
|
"vanilla-js",
|
|
19
20
|
"frontend",
|
|
20
|
-
"zero-dependencies"
|
|
21
|
+
"zero-dependencies",
|
|
22
|
+
"toasts",
|
|
23
|
+
"notifications"
|
|
21
24
|
],
|
|
22
25
|
"homepage": "https://github.com/MIOBOMB/newHelper-js#readme",
|
|
23
26
|
"bugs": {
|