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.
Files changed (2) hide show
  1. package/newHelper.js +470 -283
  2. package/package.json +5 -2
package/newHelper.js CHANGED
@@ -1,14 +1,15 @@
1
1
  /*
2
- * Перед вами код newHelper.js версии 2.1.7, он построен на базе фабрики
3
- * Которая начинается с Intl.newHelper=function(){...};
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
- * window.yourVariable = Intl.newHelper()
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
- * #fade (будет портирован из win._animate)
46
- * #toast
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.97.4
80
+ * ибо мне в идеале закончить тосты и Object Hub 0.98
79
81
  */
80
82
 
83
+ // deprecated!!
81
84
  /** @import { NewHelper } from './newHelper.d.ts' */
82
- Intl.newHelper=function() {
83
- /** @type {NewHelper} */
84
- let _ = {
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 (!this._i) {
149
+ if (!window[_].link._i) {
141
150
  // здесь происходит перенос команд при popstate
142
- // читайте _.link.get() если хотите узнать почему
143
- let newUrl='?' + [this.compile()[0],...this._cmd].join('&');
144
- this._i=true;
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
- this.get();
155
+ window[_].link.get();
147
156
  } else
148
- this._i=false;
157
+ window[_].link._i=false;
149
158
  },
150
159
  _cmd: [],
151
160
  popInit: false,
152
161
  _init() {
153
- if (!this.popInit) {
154
- window.addEventListener('popstate', ()=>this._pop());
155
- this.popInit = true;
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 = this.defTitle) {
169
+ set(page, title = window[_].link.defTitle) {
161
170
  if (title) document.title = title;
162
- if (!this._i) {
163
- let link = this.compile();
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
- this._i = false;
176
+ window[_].link._i = false;
168
177
  },
169
178
  add(cmd) {
170
- let link = this.compile();
179
+ let link = window[_].link.compile();
171
180
  if (!link.includes(cmd)) {
172
181
  link.push(cmd);
173
- this._cmd.push(cmd);
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 = this.compile();
187
+ let link = window[_].link.compile();
179
188
  if (link.includes(cmd)){
180
- let c = this._cmd;
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
- this._init();
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 = this.compile(),
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 = this.actions,
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
- this.basePage();
280
+ window[_].link.basePage();
272
281
  throw e;
273
282
  }
274
- this._cmd = cmds;
283
+ window[_].link._cmd = cmds;
275
284
  cmds.forEach(cmdPre => {
276
285
  let [ key, value ] = cmdPre.split('=');
277
- let cmd = this.commands[key];
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 = this.loaded;
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
- this._(script,fn).then(f=>f(...a));
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 this.load(scr); // await короче Promise.then
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
- // FIXME: переделать на fetch для устранения связности
413
- load: name => _.http.req('GET', _.lang.addr + name + '.json'),
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 this.load(name);
422
- this.main = JSON.parse(this.parse(packet)); // без замены языка нельзя начинать перевод
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(`[${this.attr}]`)) {
433
+ for (let el of document.querySelectorAll(`[${window[_].lang.attr}]`)) {
425
434
  let key = el.dataset.trans,
426
- text = this.main[key] || key,
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 = this.from(i),
461
- dataTrans = _.lang.attr[i]+`="${i}"`;
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 = { ...this.defaultHeaders, ...headers };
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 pipeAsync(data, ...fns) {
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: { // TS DONE HMM no
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: class {
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._ = storage;
703
+ this.s = storage;
694
704
  this.n = name;
695
705
  }
696
706
  get = key=>
697
- this._.getItem(this.n + key);
707
+ this.s.getItem(this.n + key);
698
708
  set = (key, value)=>
699
- this._.setItem(this.n + key, value);
709
+ this.s.setItem(this.n + key, value);
700
710
  remove = key=>
701
- this._.removeItem(this.n + key);
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._.removeItem(k));
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 (!this._holds.has(k)) return false;
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 (this._)
802
+ if (window[_].hotkeys._)
793
803
  return;
794
804
  document.addEventListener('keydown', e=>{
795
- this._holds.add(e.code);// key зависит от раскладки (на Qwerty 'KeyZ' — это 'z', на Йцукен — 'я')
805
+ window[_].hotkeys._holds.add(e.code);// key зависит от раскладки (на Qwerty 'KeyZ' — это 'z', на Йцукен — 'я')
796
806
  // code даёт физическое положение клавиши, что важно для игр и хоткеев, и в целом универсальнее
797
807
 
798
- for (let hotkey of this.keys.values()) {
799
- if (!this._match(hotkey.keys))
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
- this._holds.delete(e.code);
818
+ window[_].hotkeys._holds.delete(e.code);
809
819
 
810
- for (let hotkey of this.keys.values()) {
811
- if (hotkey.active && !this._match(hotkey.keys)) {
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 this.keys.values()) {
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
- this._holds.clear();
838
+ window[_].hotkeys._holds.clear();
829
839
  });
830
- this._=true;
840
+ window[_].hotkeys._=true;
831
841
  },
832
842
  on(combo, press, release) {
833
- this._init();
834
- let keys = this._parse(combo);
843
+ window[_].hotkeys._init();
844
+ let keys = window[_].hotkeys._parse(combo);
835
845
 
836
- this.keys.set(combo, {
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
- this.keys.delete(combo);
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 (this.prevent(e)) return;
901
+ if (window[_].drag.prevent(e)) return;
888
902
 
889
903
  e.preventDefault();
890
904
 
891
- this.active.set(e.pointerId,{
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 (!this._i) {
901
- document.addEventListener("pointermove", (e) => this.move(e));
902
- document.addEventListener("pointerup", (e) => this.stop(e));
903
- document.addEventListener("pointercancel", (e) => this.stop(e));
904
- this._i = true;
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=this.active.get(e.pointerId);
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
- this.active.get(e.pointerId)?.onStop?.(e);
928
- this.active.delete(e.pointerId);
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
- win:{
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.7
1136
+ * Last patch: 2.1.8
937
1137
  *
938
1138
  * если вы спросите почему ньюхелпер я отвечу
939
- * winBox.js это 35 килобайт, здесь же вы получаете в 25 килобайт
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
- * но у меня сломались все окна в object hub'е
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
- _animate(elem, anim, actAfter = ()=>{}, actPre = ()=>{}) {
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 ${this.btnAttrs}>${text}</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} ${this.hiderAttrs}${title}/button>`;
1037
- b.addEventListener('click',()=>this.show(win));
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 winId=this._ID(),
1045
- winState={
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
- return this._opn(winState,content);
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
- if (!this.manager || !this.hider) throw new Error('Window managers not inited');
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} ${this.winAttrs} ${winState.attrs}>
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
- ${this.dragAttrs} id=DRAGGER${wId}>
1070
- <span ${this.titleAttrs} id=title${wId}${_.lang.winTitle(_.win.text+winState.name)}/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 this.defBtns) btns.append(this._winBtn(winState,...b));
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
- this._animate(html, this.animOpen)
1267
+ window[_].win.manager.append(html);
1268
+
1269
+ // AFTER INSERT LOGISC !!!!!!!!!!!!!!!!
1083
1270
 
1084
- winState.setTitle=nT=>_.win.setTitle(winState,nT);
1085
- winState.toggleFull=e=>_.win.toggleFull(winState);
1086
- winState.close=e=>_.win.close(winState);
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=document.getElementById(wId),
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=document.getElementById('DRAGGER'+wId);
1096
- winState.content=document.getElementById('content'+wId);
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
- this._initWin(winState);
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 ${this.renameAttrs} id=rename${wId} value="${wT.textContent}">`;
1121
- winState.inRename=true;
1122
- }else{
1123
- this.setTitle(winState,document.getElementById('rename'+wId).value);
1124
- winState.inRename=false;
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') winState.hide();
1129
-
1130
- _.wins[winState.id] = winState;
1131
- //_.wins.set(winState.id, winState);
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=false;
1137
- winState.name=newT;
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=this.animFullOn,
1157
- aOff=this.animFullOff,
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=true;
1171
- winState.onUnfull=fd;
1172
- ws.top=0;
1173
- ws.left=0;
1174
- ws.width=`calc(100% - ${padX}px)`;
1175
- ws.height=`calc(100% - ${padY}px)`;
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=false;
1182
- this._initWin(winState);
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
- this._animate(wEl, this.animFullOn, doFul)
1187
- else
1188
- this._animate(wEl, this.animFullOff, doUnful, unful)
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
- delete _.wins[winState.id];
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
- this._animate(w, this.animClose, remover);
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=this.animHide,
1212
- hider=()=>{
1213
- wEl.style.display='none';
1214
- if(anim)wc.remove(anim);
1215
- winState.state='hidened';
1216
- this.hider.append(this._hiderBtn(winState));
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
- this._animate(wEl, this.animHide, hider);
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=this.animShow,
1225
- hider=document.getElementById('hider'+winState.id),
1226
- shower=()=>{
1227
- if(anim)wc.remove(anim);
1228
- winState.state='opened';
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
- this._animate(wEl, this.animShow, shower);
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
- this._opn(win,content);
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.7",
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": {