@innovastudio/contentbox 1.6.71 → 1.6.73

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.
@@ -8889,9 +8889,11 @@ class Text {
8889
8889
 
8890
8890
  if (text.trim() === '') {
8891
8891
  elm.style.color = color;
8892
+ elm.style.backgroundClip = '';
8892
8893
  } else {
8893
8894
  if (elm.innerText === text) {
8894
8895
  elm.style.color = color;
8896
+ elm.style.backgroundClip = '';
8895
8897
  } else {
8896
8898
  this.builder.doc.execCommand('ForeColor', false, color); //Cleanup FONTs
8897
8899
 
@@ -10585,6 +10587,26 @@ class Text {
10585
10587
  }
10586
10588
  }
10587
10589
 
10590
+ getElementHeight(element) {
10591
+ if (!element) {
10592
+ return 0;
10593
+ }
10594
+
10595
+ const computedStyle = window.getComputedStyle(element); // Element height including padding and border, but not margin
10596
+
10597
+ const elementHeight = element.offsetHeight; // Extract numerical values for margin, padding, and border
10598
+
10599
+ const marginTop = parseFloat(computedStyle.marginTop);
10600
+ const marginBottom = parseFloat(computedStyle.marginBottom);
10601
+ const paddingTop = parseFloat(computedStyle.paddingTop);
10602
+ const paddingBottom = parseFloat(computedStyle.paddingBottom);
10603
+ const borderTopWidth = parseFloat(computedStyle.borderTopWidth);
10604
+ const borderBottomWidth = parseFloat(computedStyle.borderBottomWidth); // Calculate total height considering margins, padding, and border
10605
+
10606
+ const totalHeight = elementHeight + marginTop + marginBottom + paddingTop + paddingBottom + borderTopWidth + borderBottomWidth;
10607
+ return totalHeight;
10608
+ }
10609
+
10588
10610
  }
10589
10611
 
10590
10612
  /*
@@ -10667,7 +10689,13 @@ class PanelText {
10667
10689
  <button title="${out('Color')}" class="btn-color is-btn-color"></button>
10668
10690
  </div>
10669
10691
  </div>
10670
- <div>
10692
+ <div class="mr-8">
10693
+ <div class="label mt-2">${out('Gradient')}:</div>
10694
+ <div class="group">
10695
+ <button title="${out('Gradient')}" class="btn-gradient is-btn-color"></button>
10696
+ </div>
10697
+ </div>
10698
+ <div class="mr-8">
10671
10699
  <div class="label mt-2">${out('Highlight')}:</div>
10672
10700
  <div class="group">
10673
10701
  <button title="${out('Color')}" class="btn-backcolor is-btn-color"></button>
@@ -10678,7 +10706,7 @@ class PanelText {
10678
10706
  </div>
10679
10707
 
10680
10708
 
10681
- <button class="accordion-item" aria-expanded="false" aria-controls="contenttext0">
10709
+ <button class="accordion-item btn-placement-text" aria-expanded="false" aria-controls="contenttext0">
10682
10710
  ${out('Placement')}
10683
10711
  <span><svg><use xlink:href="#icon-chevron-down"></use></svg></span>
10684
10712
  </button>
@@ -10802,11 +10830,22 @@ class PanelText {
10802
10830
  panel.insertAdjacentHTML('beforeend', html);
10803
10831
  this.panel = panel;
10804
10832
  const btnColor = panel.querySelector('.btn-color');
10833
+ const btnGradient = panel.querySelector('.btn-gradient');
10805
10834
  btnColor.addEventListener('click', () => {
10806
10835
  this.saveForUndo(true);
10807
10836
  let currentColor = btnColor.style.backgroundColor;
10808
10837
  const colorpicker = this.builder.editor.colorpicker();
10809
10838
  colorpicker.open(color => {
10839
+ // remove gradient if exists
10840
+ let elm = this.text.getElm();
10841
+
10842
+ if (elm.style.backgroundImage) {
10843
+ elm.style.backgroundImage = '';
10844
+ elm.style.backgroundClip = ''; // set gradient preview none
10845
+
10846
+ btnGradient.style.backgroundImage = '';
10847
+ }
10848
+
10810
10849
  this.text.setTextColor(color);
10811
10850
  btnColor.style.backgroundColor = color; // preview
10812
10851
  // this.builder.onChange();
@@ -10814,6 +10853,30 @@ class PanelText {
10814
10853
  this.builder.editor.onChange();
10815
10854
  }, currentColor, () => {}, btnColor, true); // overlay=true
10816
10855
  });
10856
+ btnGradient.addEventListener('click', () => {
10857
+ this.builder.editor.saveForUndo(true); // checkLater = true
10858
+
10859
+ let elm = this.text.getElm();
10860
+ let gradientPicker = this.builder.editor.gradientpicker();
10861
+ gradientPicker.open(elm, () => {
10862
+ if (elm.style.backgroundImage) {
10863
+ // apply gradient
10864
+ elm.style.backgroundClip = 'text';
10865
+ elm.style.color = 'transparent'; // set text color preview none
10866
+
10867
+ btnColor.style.backgroundColor = '';
10868
+ } else {
10869
+ // remove gradient
10870
+ elm.style.backgroundClip = '';
10871
+ elm.style.color = ''; // set text color preview back
10872
+
10873
+ setTimeout(() => {
10874
+ let currentColor = this.text.getStyle(elm, 'color');
10875
+ btnColor.style.backgroundColor = currentColor;
10876
+ }, 1);
10877
+ }
10878
+ }, () => {}, btnGradient, true); // overlay=true
10879
+ });
10817
10880
  const btnBackColor = panel.querySelector('.btn-backcolor');
10818
10881
  btnBackColor.addEventListener('click', () => {
10819
10882
  this.saveForUndo(true);
@@ -11072,6 +11135,14 @@ class PanelText {
11072
11135
  const btnColorPick = this.panel.querySelector('.btn-color');
11073
11136
  let currentColor = this.text.getStyle(activeElement, 'color');
11074
11137
  btnColorPick.style.backgroundColor = currentColor;
11138
+ const btnGradient = this.panel.querySelector('.btn-gradient');
11139
+
11140
+ if (activeElement.style.backgroundImage) {
11141
+ btnGradient.style.backgroundImage = activeElement.style.backgroundImage;
11142
+ } else {
11143
+ btnGradient.style.backgroundImage = '';
11144
+ }
11145
+
11075
11146
  const btnBackColorPick = this.panel.querySelector('.btn-backcolor');
11076
11147
  let currentBackColor = this.getHighlight(activeElement);
11077
11148
  btnBackColorPick.style.backgroundColor = currentBackColor;
@@ -11142,6 +11213,27 @@ class PanelText {
11142
11213
  */
11143
11214
 
11144
11215
 
11216
+ const btnPlacementText = this.panel.querySelector('.btn-placement-text');
11217
+ btnPlacementText.style.display = '';
11218
+
11219
+ try {
11220
+ let totalElementHeight = 0;
11221
+ let hasGrow = false;
11222
+ Array.from(activeColumn.children).map(elm => {
11223
+ totalElementHeight += this.text.getElementHeight(elm);
11224
+ if (elm.classList.contains('grow')) hasGrow = true;
11225
+ });
11226
+ const diff = activeColumn.offsetHeight - totalElementHeight;
11227
+
11228
+ if (diff < 30 && !hasGrow) {
11229
+ btnPlacementText.style.display = 'none';
11230
+ btnPlacementText.setAttribute('aria-expanded', 'false');
11231
+ btnPlacementText.nextElementSibling.style.display = 'none';
11232
+ btnPlacementText.nextElementSibling.setAttribute('aria-hidden', 'true');
11233
+ }
11234
+ } catch (e) {// Do Nothing
11235
+ }
11236
+
11145
11237
  const config = this.builder.cssClasses;
11146
11238
  let elm = this.text.getElm();
11147
11239
 
@@ -24892,7 +24984,7 @@ class ImageAdjust {
24892
24984
 
24893
24985
  }
24894
24986
 
24895
- class Modal$1 {
24987
+ class Modal {
24896
24988
  constructor() {
24897
24989
  this.modal = null;
24898
24990
  this.focusableElements = [];
@@ -25244,7 +25336,7 @@ class ControlPanel {
25244
25336
  }
25245
25337
 
25246
25338
  this.controlPanel = controlPanel;
25247
- this.modal = new Modal$1();
25339
+ this.modal = new Modal();
25248
25340
  this.panelText = controlPanel.querySelector('.panel-text');
25249
25341
  this.panelImage = controlPanel.querySelector('.panel-image');
25250
25342
  this.panelVideo = controlPanel.querySelector('.panel-video');
@@ -30821,27 +30913,7 @@ class Util$1 {
30821
30913
  pop.classList.add('pop4');
30822
30914
  overlay.classList.add('pop4');
30823
30915
  }
30824
- const handlePopKeyDown = e => {
30825
- if (e.keyCode === 27) {
30826
- // escape key
30827
- overlay.remove();
30828
- pop.style.display = '';
30829
- pop.classList.remove('active');
30830
- pop.setAttribute('aria-hidden', true);
30831
- overlay.classList.remove('pop1');
30832
- overlay.classList.remove('pop2');
30833
- overlay.classList.remove('pop3');
30834
- overlay.classList.remove('pop4');
30835
- pop.classList.remove('pop1');
30836
- pop.classList.remove('pop2');
30837
- pop.classList.remove('pop3');
30838
- pop.classList.remove('pop4');
30839
- pop.removeEventListener('keydown', handlePopKeyDown);
30840
- if (cancelCallback) cancelCallback();
30841
- if (btn) btn.focus();
30842
- }
30843
- };
30844
- overlay.addEventListener('click', e => {
30916
+ const close = () => {
30845
30917
  overlay.remove();
30846
30918
  pop.style.display = '';
30847
30919
  pop.classList.remove('active');
@@ -30857,6 +30929,17 @@ class Util$1 {
30857
30929
  pop.removeEventListener('keydown', handlePopKeyDown);
30858
30930
  if (cancelCallback) cancelCallback();
30859
30931
  if (btn) btn.focus();
30932
+ };
30933
+ this.hidePopOverlay = close; // so that the close() can be called programmatically (used by gradientpicker.js 411)
30934
+
30935
+ const handlePopKeyDown = e => {
30936
+ if (e.keyCode === 27) {
30937
+ // escape key
30938
+ close();
30939
+ }
30940
+ };
30941
+ overlay.addEventListener('click', e => {
30942
+ close();
30860
30943
  e.preventDefault();
30861
30944
  e.stopImmediatePropagation();
30862
30945
  });
@@ -30876,13 +30959,9 @@ class Util$1 {
30876
30959
  // Hide other pops
30877
30960
  let elms = document.querySelectorAll('.is-pop.active');
30878
30961
  elms.forEach(otherPop => {
30962
+ // do not close parent/caller pop
30879
30963
  let close = true;
30880
- let callerPop;
30881
- if (overlay) {
30882
- // do not close parent/caller pop
30883
- callerPop = btn.closest('.is-pop');
30884
- if (callerPop === otherPop) close = false;
30885
- }
30964
+ if (otherPop.contains(btn)) close = false;
30886
30965
  if (otherPop !== pop && close) {
30887
30966
  otherPop.style.display = '';
30888
30967
  dom.removeClass(otherPop, 'active');
@@ -30908,9 +30987,9 @@ class Util$1 {
30908
30987
  if (!pop.contains(e.target) && !btn.contains(e.target)) {
30909
30988
  // click outside
30910
30989
 
30911
- if (e.target.closest('.is-pop-overlay')) return;
30912
- let overlayExist = document.querySelector('.is-pop-overlay');
30913
- if (overlayExist) return;
30990
+ // if(e.target.closest('.is-pop-overlay')) return;
30991
+ // let overlayExist = document.querySelector('.is-pop-overlay');
30992
+ // if(overlayExist) return;
30914
30993
 
30915
30994
  // hide
30916
30995
  this.hidePop(pop);
@@ -42021,6 +42100,11 @@ const prepareSvgIcons = builder => {
42021
42100
  <path d="M12 5l0 14"></path>
42022
42101
  <path d="M5 12l14 0"></path>
42023
42102
  </symbol>
42103
+
42104
+ <symbol id="icon-minus" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
42105
+ <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
42106
+ <path d="M5 12l14 0"></path>
42107
+ </symbol>
42024
42108
  </svg>`;
42025
42109
  builder.dom.appendHtml(builder.builderStuff, html);
42026
42110
  };
@@ -53957,7 +54041,7 @@ function () {
53957
54041
  return EventEmitter;
53958
54042
  }();
53959
54043
 
53960
- var EventEmitter$1$1 = EventEmitter$2;
54044
+ var EventEmitter$1$2 = EventEmitter$2;
53961
54045
 
53962
54046
  /*
53963
54047
  Copyright (c) 2019 Daybrush
@@ -66468,7 +66552,7 @@ var MoveableManager$1 = /*#__PURE__*/function (_super) {
66468
66552
  "mouseEnter": null,
66469
66553
  "mouseLeave": null
66470
66554
  };
66471
- _this._emitter = new EventEmitter$1$1();
66555
+ _this._emitter = new EventEmitter$1$2();
66472
66556
  _this._prevTarget = null;
66473
66557
  _this._prevDragArea = false;
66474
66558
  _this._observer = null;
@@ -68397,7 +68481,7 @@ function __spreadArrays() {
68397
68481
  * Implement EventEmitter on object or component.
68398
68482
  */
68399
68483
 
68400
- var EventEmitter =
68484
+ var EventEmitter$1 =
68401
68485
  /*#__PURE__*/
68402
68486
  function () {
68403
68487
  function EventEmitter() {
@@ -68630,7 +68714,7 @@ function () {
68630
68714
  return EventEmitter;
68631
68715
  }();
68632
68716
 
68633
- var EventEmitter$1 = EventEmitter;
68717
+ var EventEmitter$1$1 = EventEmitter$1;
68634
68718
 
68635
68719
  /**
68636
68720
  * Moveable is Draggable! Resizable! Scalable! Rotatable!
@@ -68744,7 +68828,7 @@ function (_super) {
68744
68828
  });
68745
68829
  })], MoveableManager);
68746
68830
  return MoveableManager;
68747
- }(EventEmitter$1);
68831
+ }(EventEmitter$1$1);
68748
68832
 
68749
68833
  var Moveable$1 =
68750
68834
  /*#__PURE__*/
@@ -78050,11 +78134,16 @@ class RowTool {
78050
78134
  <a title="${util.out('More')}" id="tabRowMore" href="#" data-content="divRowMore">${util.out('More')}</a>
78051
78135
  </div>
78052
78136
  <div id="divRowGeneral" class="is-tab-content active" data-group="rowsettings" style="display:flex" tabindex="-1">
78053
-
78054
- <div style="padding-bottom: 3px;">${util.out('Background Color')}:</div>
78055
- <div style="display:flex;">
78056
- <button title="${util.out('Background Color')}" class="input-row-bgcolor is-btn-color" style="margin-right:15px"></button>
78057
- <button title="${util.out('Gradient')}" class="input-row-gradient classic" data-value="+"> ${util.out('Gradient')} </button>
78137
+
78138
+ <div style="display:flex;gap:40px">
78139
+ <div>
78140
+ <div style="padding-bottom: 3px;">${util.out('Background Color')}:</div>
78141
+ <button title="${util.out('Background Color')}" class="input-row-bgcolor is-btn-color" style="margin-right:15px"></button>
78142
+ </div>
78143
+ <div>
78144
+ <div style="padding-bottom: 3px;">${util.out('Gradient')}:</div>
78145
+ <button title="${util.out('Gradient')}" class="input-row-gradient is-btn-color"></button>
78146
+ </div>
78058
78147
  </div>
78059
78148
 
78060
78149
  <div style="padding-top:20px;padding-bottom: 3px;">${util.out('Background Image')}:</div>
@@ -78301,11 +78390,6 @@ class RowTool {
78301
78390
  });
78302
78391
 
78303
78392
  // Background gradient
78304
- // const gradientPicker = new GradientPicker({
78305
- // colors: this.builder.colors,
78306
- // gradientcolors: this.builder.opts.gradientcolors,
78307
- // lang: this.builder.opts.lang
78308
- // }, this.builder);
78309
78393
  const gradientPicker = this.builder.gradientpicker();
78310
78394
  let btnRowGradient = rowSettings.querySelector('.input-row-gradient');
78311
78395
  btnRowGradient.addEventListener('click', () => {
@@ -78701,6 +78785,16 @@ class RowTool {
78701
78785
  } else {
78702
78786
  div.innerHTML = '';
78703
78787
  }
78788
+
78789
+ // Gradient
78790
+ let btnGradient = this.rowSettings.querySelector('.input-row-gradient');
78791
+ btnGradient.style.backgroundImage = '';
78792
+ if (row.style.backgroundImage) {
78793
+ if (row.style.backgroundImage.includes('linear')) {
78794
+ let cssGradient = row.style.backgroundImage;
78795
+ btnGradient.style.backgroundImage = cssGradient;
78796
+ }
78797
+ }
78704
78798
  const chkRowGrayscale = this.rowSettings.querySelector('.chk-row-grayscale');
78705
78799
  chkRowGrayscale.checked = false;
78706
78800
  if (row.style.filter) {
@@ -78859,7 +78953,6 @@ class RowAddTool {
78859
78953
  }
78860
78954
  }
78861
78955
 
78862
- // import GradientPicker from './gradientpicker.js';
78863
78956
  class ColumnTool {
78864
78957
  constructor(builder) {
78865
78958
  this.builder = builder;
@@ -79633,10 +79726,15 @@ class ColumnTool {
79633
79726
  </div>
79634
79727
  <div id="divCellGeneral" class="is-tab-content active" data-group="cellsettings" style="display:flex" tabindex="-1">
79635
79728
 
79636
- <div style="padding-bottom: 3px;">${util.out('Background Color')}:</div>
79637
- <div style="display:flex;">
79638
- <button title="${util.out('Background Color')}" class="input-cell-bgcolor is-btn-color" style="margin-right:15px"></button>
79639
- <button title="${util.out('Gradient')}" class="input-cell-gradient classic" data-value="+"> ${util.out('Gradient')} </button>
79729
+ <div style="display:flex;gap:40px">
79730
+ <div>
79731
+ <div style="padding-bottom: 3px;">${util.out('Background Color')}:</div>
79732
+ <button title="${util.out('Background Color')}" class="input-cell-bgcolor is-btn-color" style="margin-right:15px"></button>
79733
+ </div>
79734
+ <div>
79735
+ <div style="padding-bottom: 3px;">${util.out('Gradient')}:</div>
79736
+ <button title="${util.out('Gradient')}" class="input-cell-gradient is-btn-color"></button>
79737
+ </div>
79640
79738
  </div>
79641
79739
 
79642
79740
  <div style="padding-top:20px;padding-bottom: 3px;">${util.out('Background Image')}:</div>
@@ -80028,12 +80126,6 @@ class ColumnTool {
80028
80126
  });
80029
80127
 
80030
80128
  // Background gradient
80031
- // const gradientPicker = new GradientPicker({
80032
- // colors: this.builder.colors,
80033
- // gradientcolors: this.builder.opts.gradientcolors,
80034
- // lang: this.builder.opts.lang
80035
- // }, this.builder);
80036
-
80037
80129
  const gradientPicker = this.builder.gradientpicker();
80038
80130
  let btnCellGradient = cellSettings.querySelector('.input-cell-gradient');
80039
80131
  btnCellGradient.addEventListener('click', () => {
@@ -80805,6 +80897,16 @@ class ColumnTool {
80805
80897
  } else {
80806
80898
  div.innerHTML = '';
80807
80899
  }
80900
+
80901
+ // Gradient
80902
+ let btnGradient = this.cellSettings.querySelector('.input-cell-gradient');
80903
+ btnGradient.style.backgroundImage = '';
80904
+ if (cell.style.backgroundImage) {
80905
+ if (cell.style.backgroundImage.includes('linear')) {
80906
+ let cssGradient = cell.style.backgroundImage;
80907
+ btnGradient.style.backgroundImage = cssGradient;
80908
+ }
80909
+ }
80808
80910
  const inpClickSrc = this.cellSettings.querySelector('.input-src');
80809
80911
  inpClickSrc.value = '';
80810
80912
  let clickUrl = cell.getAttribute('data-modal-url');
@@ -81641,11 +81743,14 @@ class ElementGeneralStyles {
81641
81743
  let panelStuff = builderStuff.querySelector('#divElementGeneral');
81642
81744
  this.panelStuff = panelStuff;
81643
81745
  const html = `
81644
- <div class="is-settings" style="width: 100%">
81645
- <div class="is-label" style="margin:0 0 3px">${util.out('Background Color')}:</div>
81646
- <div>
81746
+ <div class="is-settings" style="width: 100%;display:flex;gap:40px">
81747
+ <div style="display:flex;flex-direction:column;align-items:flex-start;">
81748
+ <div style="padding-bottom: 7px;">${util.out('Background Color')}:</div>
81647
81749
  <button title="${util.out('Background Color')}" class="input-elm-bgcolor is-btn-color" style="margin-right:15px"></button>
81648
- <button title="${util.out('Gradient')}" class="input-elm-gradient classic" data-value="+"> ${util.out('Gradient')} </button>
81750
+ </div>
81751
+ <div style="display:flex;flex-direction:column;align-items:flex-start;">
81752
+ <div style="padding-bottom: 7px;">${util.out('Gradient')}:</div>
81753
+ <button title="${util.out('Gradient')}" class="input-elm-gradient is-btn-color"></button>
81649
81754
  </div>
81650
81755
  </div>
81651
81756
 
@@ -81730,12 +81835,6 @@ class ElementGeneralStyles {
81730
81835
  });
81731
81836
 
81732
81837
  // Background gradient
81733
- // const gradientPicker = new GradientPicker({
81734
- // colors: this.builder.colors,
81735
- // gradientcolors: this.builder.opts.gradientcolors,
81736
- // lang: this.builder.opts.lang
81737
- // }, this.builder);
81738
-
81739
81838
  const gradientPicker = this.builder.gradientpicker();
81740
81839
  let btnElmGradient = panelStuff.querySelector('.input-elm-gradient');
81741
81840
  btnElmGradient.addEventListener('click', () => {
@@ -81934,6 +82033,16 @@ class ElementGeneralStyles {
81934
82033
  let btn = panelStuff.querySelector('.input-elm-bgcolor');
81935
82034
  if (s) btn.style.backgroundColor = s;else btn.style.backgroundColor = 'transparent';
81936
82035
 
82036
+ // Gradient
82037
+ let btnGradient = panelStuff.querySelector('.input-elm-gradient');
82038
+ btnGradient.style.backgroundImage = '';
82039
+ if (elm.style.backgroundImage) {
82040
+ if (elm.style.backgroundImage.includes('linear')) {
82041
+ let cssGradient = elm.style.backgroundImage;
82042
+ btnGradient.style.backgroundImage = cssGradient;
82043
+ }
82044
+ }
82045
+
81937
82046
  // Background image
81938
82047
  let imgUrl = '';
81939
82048
  const div = panelStuff.querySelector('.elm-bgimage-preview');
@@ -89665,7 +89774,8 @@ class ColorPicker {
89665
89774
  pickr.on('change', color => {
89666
89775
  if (poppicker.style.display !== 'flex') return;
89667
89776
  let s = color.toRGBA().toString(0);
89668
- this.opts.onPick(s);
89777
+ if (!this.noCallback) this.opts.onPick(s);
89778
+ this.noCallback = false; //just in case
89669
89779
  }).on('clear', () => {
89670
89780
  this.opts.onPick('');
89671
89781
  poppicker.querySelector('.pcr-result').value = ''; //clear
@@ -89824,6 +89934,7 @@ class ColorPicker {
89824
89934
  this.opts.color = color;
89825
89935
  this.setColor(color, true);
89826
89936
  }
89937
+ this.noCallback = false;
89827
89938
  }
89828
89939
  openByTab(color) {
89829
89940
  // Rte
@@ -89839,9 +89950,10 @@ class ColorPicker {
89839
89950
  setColorRte(color) {
89840
89951
  this.pickrRte.setColor(color);
89841
89952
  }
89842
- setColor(color) {
89953
+ setColor(color, noCallback) {
89843
89954
  //, noCallback
89844
89955
 
89956
+ if (noCallback) this.noCallback = true; // will be passed to onChange, since the onChanhe calls onPick(color)
89845
89957
  this.pickr.setColor(color);
89846
89958
 
89847
89959
  // if(!noCallback) this.opts.onPick(color);
@@ -89871,451 +89983,601 @@ class ColorPicker {
89871
89983
  }
89872
89984
  }
89873
89985
 
89874
- class Modal {
89875
- constructor(opts = {}) {
89876
- let defaults = {
89877
- animateModal: false,
89878
- elementToAnimate: '',
89879
- stuffPlacement: '#_cbhtml'
89986
+ class RoundedSlider {
89987
+ constructor(element, settings = {}) {
89988
+ const defaults = {
89989
+ selector: '.myslider',
89990
+ onStart: () => {}
89880
89991
  };
89881
- this.opts = Object.assign(this, defaults, opts);
89882
- this.id = this.makeId();
89883
- let builderStuff = document.querySelector(this.opts.stuffPlacement);
89884
- if (!builderStuff) {
89885
- builderStuff = document.createElement('div');
89886
- builderStuff.id = '_cbhtml';
89887
- document.body.appendChild(builderStuff);
89888
- }
89889
- this.builderStuff = builderStuff;
89992
+ this.opts = Object.assign(this, defaults, settings);
89993
+ this.startDrag = this.startDrag.bind(this);
89994
+ this.onDrag = this.onDrag.bind(this);
89995
+ this.endDrag = this.endDrag.bind(this);
89996
+ this.handleTouchMove = this.handleTouchMove.bind(this);
89997
+ this.element = element; //document.querySelector(this.opts.selector);
89890
89998
 
89891
- // Stuff placement for this (single) instance
89892
- const objStuff = document.createElement('div');
89893
- objStuff.id = this.id;
89894
- builderStuff.appendChild(objStuff);
89895
- this.objStuff = objStuff;
89999
+ this.created = false;
89896
90000
  }
89897
- confirm(message, callback, animated) {
89898
- let html = `<div class="is-modal is-confirm" tabindex="-1" role="dialog" aria-modal="true" aria-hidden="true">
89899
- <div class="is-modal-content" style="padding-bottom:20px;">
89900
- <div style="margin: 20px 0 30px;font-size: 14px;">${message}</div>
89901
- <button title="${this.out('Delete')}" class="input-ok classic">${this.out('Delete')}</button>
89902
- </div>
89903
- </div>`;
89904
- let confirmModal = this.objStuff.querySelector('.is-confirm');
89905
- if (!confirmModal) {
89906
- this.objStuff.insertAdjacentHTML('beforeend', html);
89907
- confirmModal = this.builderStuff.querySelector('.is-confirm');
89908
- }
89909
- this.show(confirmModal, false, () => {
89910
- //this function runs when overlay is clicked. Remove modal.
89911
- confirmModal.parentNode.removeChild(confirmModal);
89912
-
89913
- //do task
89914
- callback(false);
89915
- }, animated);
89916
- let buttonok = confirmModal.querySelector('.is-confirm .input-ok');
89917
- this.addEventListener(buttonok, 'click', () => {
89918
- this.hide(confirmModal);
89919
- confirmModal.parentNode.removeChild(confirmModal); //remove modal
89920
-
89921
- //do task
89922
- callback(true);
90001
+ create() {
90002
+ if (this.created === true) return; // so that it is saved to call multiple times
90003
+ this.created = true;
90004
+ const element = this.element;
90005
+ const container = document.createElement('div');
90006
+ container.classList.add('roundslider-container');
90007
+ container.innerHTML = `
90008
+ <div class="roundslider">
90009
+ <div class="knob"></div>
90010
+ </div>
90011
+ `;
90012
+ element.insertAdjacentElement('afterend', container);
90013
+ this.container = container;
90014
+ const knob = container.querySelector('.knob');
90015
+ const roundslider = container.querySelector('.roundslider');
90016
+ const angleValue = element;
90017
+ this.knob = knob;
90018
+ this.roundslider = roundslider;
90019
+ this.angleValue = angleValue;
90020
+ this.isDragging = false;
90021
+ this.angleOffset = 0;
90022
+ knob.addEventListener('mousedown', this.startDrag);
90023
+ document.addEventListener('mousemove', this.onDrag);
90024
+ document.addEventListener('mouseup', this.endDrag);
90025
+ knob.addEventListener('touchstart', this.startDrag, {
90026
+ passive: false
89923
90027
  });
90028
+ // document.addEventListener('touchmove', e => this.onDrag(e.touches[0]));
90029
+ document.addEventListener('touchmove', this.handleTouchMove);
90030
+ document.addEventListener('touchend', this.endDrag);
90031
+ this.setKnobPosition(angleValue.value, true); // no trigger for initial create
90032
+
90033
+ element.style.display = 'none';
90034
+ }
90035
+ setValue(val, noTrigger = false) {
90036
+ // true = no trigger only for setting angle position (gradientpicker.js 500)
90037
+ this.setKnobPosition(val, noTrigger);
89924
90038
  }
89925
- show(modal, overlayStay, cancelCallback, animated) {
89926
- this.addClass(modal, 'active');
90039
+ setKnobPosition(angle, noTrigger = false) {
90040
+ const knob = this.knob;
90041
+ const roundslider = this.roundslider;
90042
+ const angleValue = this.angleValue;
90043
+ const degToRad = deg => deg * Math.PI / 180;
90044
+ const radius = roundslider.offsetWidth / 2;
90045
+ const x = radius + radius * Math.cos(degToRad(angle - 90));
90046
+ const y = radius + radius * Math.sin(degToRad(angle - 90));
90047
+ knob.style.left = `${x - knob.offsetWidth / 2}px`;
90048
+ knob.style.top = `${y - knob.offsetHeight / 2}px`;
90049
+ angle = angle % 360;
89927
90050
 
89928
- // animated param (if set) will overide global setting
89929
- let animate = false;
89930
- if (!(typeof animated === 'undefined' || animated === null)) {
89931
- // animated param is set
89932
- animate = animated;
89933
- } else {
89934
- // if animated param is not set
89935
- animate = this.opts.animateModal; // use global setting
89936
- }
90051
+ // angleValue.value = `${Math.round(angle)}°`;
90052
+ angleValue.value = `${Math.round(angle)}`;
90053
+ knob.dataset.angle = angle.toString(); // Update the internal state with the new angle
89937
90054
 
89938
- if (animate) {
89939
- const buildercontainers = document.querySelectorAll(this.opts.elementToAnimate);
89940
- Array.prototype.forEach.call(buildercontainers, buildercontainer => {
89941
- // buildercontainer.style.transform = 'scale(0.98)';
89942
- // buildercontainer.style.WebkitTransform= 'scale(0.98)';
89943
- // buildercontainer.style.MozTransform= 'scale(0.98)';
89944
- buildercontainer.style.transform = `scale(${this.builder.opts.zoom - 0.02})`;
89945
- buildercontainer.style.WebkitTransform = `scale(${this.builder.opts.zoom - 0.02})`;
89946
- buildercontainer.style.MozTransform = `scale(${this.builder.opts.zoom - 0.02})`;
89947
- buildercontainer.setAttribute('scaled-down', '1');
90055
+ if (!noTrigger) {
90056
+ const event = new Event('input', {
90057
+ bubbles: true
89948
90058
  });
90059
+ angleValue.dispatchEvent(event);
89949
90060
  }
89950
- if (!modal.querySelector('.is-modal-overlay')) {
89951
- let html;
89952
- if (overlayStay) {
89953
- html = '<div class="is-modal-overlay overlay-stay"></div>';
89954
- } else {
89955
- html = '<div class="is-modal-overlay"></div>';
89956
- }
89957
- modal.insertAdjacentHTML('afterbegin', html);
89958
- if (!overlayStay) {
89959
- let overlay = modal.querySelector('.is-modal-overlay');
89960
- this.addEventListener(overlay, 'click', () => {
89961
- //cancelCallback
89962
- if (cancelCallback) cancelCallback();
89963
- this.hide(modal);
89964
- });
89965
- }
90061
+ }
90062
+ startDrag(e) {
90063
+ e.preventDefault();
90064
+ const radToDeg = rad => rad * 180 / Math.PI;
90065
+ const knob = this.knob;
90066
+ const roundslider = this.roundslider;
90067
+ const angleValue = this.angleValue;
90068
+ const rect = roundslider.getBoundingClientRect();
90069
+ const centerX = rect.left + rect.width / 2;
90070
+ const centerY = rect.top + rect.height / 2;
90071
+ const mouseX = e.clientX || e.touches[0].clientX;
90072
+ const mouseY = e.clientY || e.touches[0].clientY;
90073
+ const startAngle = radToDeg(Math.atan2(mouseY - centerY, mouseX - centerX)) + 180;
90074
+ const knobAngle = parseInt(knob.dataset.angle || `${angleValue.value}`, 10);
90075
+ this.angleOffset = knobAngle - startAngle;
90076
+ this.isDragging = true;
90077
+ this.onStart();
90078
+ }
90079
+ handleTouchMove(e) {
90080
+ if (e.touches && e.touches.length > 0) {
90081
+ this.onDrag(e.touches[0]);
89966
90082
  }
89967
90083
  }
89968
- hide(modal) {
89969
- if (this.opts.elementToAnimate !== '') {
89970
- const buildercontainers = document.querySelectorAll(this.opts.elementToAnimate);
89971
- Array.prototype.forEach.call(buildercontainers, buildercontainer => {
89972
- // buildercontainer.style.transform = '';
89973
- // buildercontainer.style.WebkitTransform= '';
89974
- // buildercontainer.style.MozTransform= '';
89975
- if (buildercontainer.getAttribute('scaled-down')) {
89976
- buildercontainer.style.transform = `scale(${this.builder.opts.zoom})`;
89977
- buildercontainer.style.WebkitTransform = `scale(${this.builder.opts.zoom})`;
89978
- buildercontainer.style.MozTransform = `scale(${this.builder.opts.zoom})`;
89979
- buildercontainer.removeAttribute('scaled-down');
89980
- }
90084
+ onDrag(e) {
90085
+ if (!this.isDragging) return;
90086
+ const radToDeg = rad => rad * 180 / Math.PI;
90087
+ const knob = this.knob;
90088
+ const roundslider = this.roundslider;
90089
+ const rect = roundslider.getBoundingClientRect();
90090
+ const centerX = rect.left + rect.width / 2;
90091
+ const centerY = rect.top + rect.height / 2;
90092
+ const mouseX = e.clientX || e.touches[0].clientX;
90093
+ const mouseY = e.clientY || e.touches[0].clientY;
90094
+ let angle = radToDeg(Math.atan2(mouseY - centerY, mouseX - centerX)) + 180;
90095
+ angle += this.angleOffset;
90096
+ angle = angle % 360;
90097
+ angle = angle < 0 ? 359 + angle : angle;
90098
+ knob.dataset.angle = angle.toString();
90099
+ this.setKnobPosition(angle);
90100
+ }
90101
+ endDrag() {
90102
+ this.isDragging = false;
90103
+ }
90104
+ destroy() {
90105
+ const element = this.element;
90106
+ const knob = this.knob;
90107
+ const container = this.container;
90108
+ knob.removeEventListener('mousedown', this.startDrag);
90109
+ document.removeEventListener('mousemove', this.onDrag);
90110
+ document.removeEventListener('mouseup', this.endDrag);
90111
+ knob.removeEventListener('touchstart', this.startDrag);
90112
+ // document.removeEventListener('touchmove', e => this.onDrag(e.touches[0]));
90113
+ document.removeEventListener('touchmove', this.handleTouchMove);
90114
+ document.removeEventListener('touchend', this.endDrag);
90115
+ container.remove();
90116
+ element.style.display = '';
90117
+ }
90118
+ }
90119
+
90120
+ class EventEmitter {
90121
+ constructor() {
90122
+ this.listeners = {};
90123
+ }
90124
+ on(event, listener) {
90125
+ if (!this.listeners[event]) {
90126
+ this.listeners[event] = [];
90127
+ }
90128
+ this.listeners[event].push(listener);
90129
+ }
90130
+ emit(event, ...args) {
90131
+ if (this.listeners[event]) {
90132
+ this.listeners[event].forEach(listener => {
90133
+ listener(...args);
89981
90134
  });
89982
90135
  }
89983
- this.removeClass(modal, 'active');
89984
90136
  }
90137
+ }
89985
90138
 
89986
- // http://stackoverflow.com/questions/1349404/generate-a-string-of-5-random-characters-in-javascript
89987
- makeId() {
89988
- let text = '';
89989
- let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
89990
- for (let i = 0; i < 2; i++) text += possible.charAt(Math.floor(Math.random() * possible.length));
89991
- let text2 = '';
89992
- let possible2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
89993
- for (let i = 0; i < 5; i++) text2 += possible2.charAt(Math.floor(Math.random() * possible2.length));
89994
- return text + text2;
90139
+ /*
90140
+ // Usage example
90141
+
90142
+ const myGradientSlider = document.querySelector('.myslider');
90143
+ const slider = new GradientSlider(myGradientSlider);
90144
+ slider.draw([
90145
+ { color: 'rgba(4, 98, 183, 1)', position: 0 },
90146
+ { color: 'rgba(97, 110, 204, 1)', position: 25 },
90147
+ { color: 'rgba(246, 108, 168, 1)', position: 50 },
90148
+ { color: 'rgba(255, 211, 111, 1)', position: 75 },
90149
+ { color: 'rgba(255, 253, 193, 1)', position: 100 }
90150
+ ]
90151
+ );
90152
+
90153
+ slider.on('slideStart', (sliderPoint) => {
90154
+ console.log('Sliding started', sliderPoint);
90155
+ });
90156
+ slider.on('slideEnd', () => {
90157
+ console.log('Sliding ended');
90158
+ });
90159
+ slider.on('change', (pointsArray) => {
90160
+ console.log('Slider changed', pointsArray);
90161
+ });
90162
+ slider.on('slideChange', (pointsArray) => {
90163
+ console.log('Slider changed', pointsArray);
90164
+ });
90165
+ */
90166
+
90167
+ class GradientSlider extends EventEmitter {
90168
+ constructor(element, settings = {}) {
90169
+ super(); // Call the constructor of EventEmitter first
90170
+
90171
+ const defaults = {
90172
+ label: 'Gradient Slider'
90173
+ };
90174
+ this.opts = Object.assign(this, defaults, settings);
90175
+ this.element = element;
90176
+
90177
+ // Generate a unique ID for this slider instance
90178
+ this.uniqueId = GradientSlider.getUniqueId();
90179
+ this.drag = this.drag.bind(this);
90180
+ this.dragStop = this.dragStop.bind(this);
90181
+ this.addColorOnClick = this.addColorOnClick.bind(this);
89995
90182
  }
89996
- addClass(element, classname) {
89997
- if (!element) return;
89998
- if (this.hasClass(element, classname)) return;
89999
- if (element.classList.length === 0) element.className = classname;else element.className = element.className + ' ' + classname;
90183
+
90184
+ // Static method to generate a unique ID
90185
+ static getUniqueId() {
90186
+ if (!this.uniqueCounter) {
90187
+ this.uniqueCounter = 0; // Initialize if it doesn't exist
90188
+ }
90189
+
90190
+ this.uniqueCounter++; // Increment the counter for each new instance
90191
+ return `gradientSliderLabel${this.uniqueCounter}`; // Return a unique ID
90000
90192
  }
90001
- removeClass(element, classname) {
90002
- if (!element) return;
90003
- if (element.classList.length > 0) {
90004
- element.className = element.className.replace(classname, '');
90193
+
90194
+ constructGradientString(pointsArray) {
90195
+ const gradientParts = pointsArray.map(color => `${color.color} ${color.position}%`);
90196
+ return `linear-gradient(90deg, ${gradientParts.join(', ')})`;
90197
+ }
90198
+
90199
+ /*
90200
+ pointsArray = [
90201
+ { color: 'rgba(4, 98, 183, 1)', position: 0 },
90202
+ { color: 'rgba(246, 108, 168, 1)', position: 50 },
90203
+ { color: 'rgba(255, 253, 193, 1)', position: 100 }
90204
+ ]
90205
+ */
90206
+ draw(pointsArray) {
90207
+ this.sliderPoints = [];
90208
+ let label = this.element.querySelector('.visually-hidden');
90209
+ if (!label) {
90210
+ label = document.createElement('div');
90211
+ label.className = 'visually-hidden';
90212
+ label.id = this.uniqueId;
90213
+ label.textContent = this.opts.label;
90214
+ this.element.prepend(label); // Add label to the slider element
90215
+ }
90216
+
90217
+ if (!this.sliderContainer) {
90218
+ this.sliderContainer = document.createElement('div');
90219
+ this.sliderContainer.className = 'gradient-slider-container';
90220
+ this.element.insertAdjacentElement('afterend', this.sliderContainer);
90221
+ this.shadowContainer = document.createElement('div');
90222
+ this.shadowContainer.classList.add('gradient-slider-container-shadow');
90223
+ this.sliderContainer.insertAdjacentElement('afterbegin', this.shadowContainer);
90224
+ this.setupAddColorOnClick();
90225
+ } else {
90226
+ this.clearPoints();
90227
+ }
90228
+ pointsArray.forEach(point => {
90229
+ const knob = document.createElement('div');
90230
+ knob.className = 'slider-point';
90231
+ knob.style.left = `${point.position}%`;
90232
+ knob.style.backgroundColor = point.color;
90233
+ this.sliderContainer.insertAdjacentElement('beforeend', knob);
90234
+ this.sliderPoints.push(knob); // this.sliderPoints contains list of knobs
90235
+
90236
+ // Accessibility Enhancements
90237
+ knob.setAttribute('tabindex', '0'); // Make it focusable
90238
+ knob.setAttribute('role', 'slider');
90239
+ knob.setAttribute('aria-valuemin', '0');
90240
+ knob.setAttribute('aria-valuemax', '100');
90241
+ knob.setAttribute('aria-valuenow', point.position);
90242
+ knob.setAttribute('aria-valuetext', `Color: ${point.color}, Position: ${point.position}%`);
90243
+ knob.setAttribute('aria-labelledby', this.uniqueId);
90244
+
90245
+ // Initialize drag functionality
90246
+ knob.addEventListener('mousedown', this.dragStart.bind(this, knob), {
90247
+ passive: false
90248
+ });
90249
+ knob.addEventListener('touchstart', this.dragStart.bind(this, knob), {
90250
+ passive: false
90251
+ });
90252
+
90253
+ // Keyboard interaction
90254
+ knob.addEventListener('keydown', e => this.handleKeydown(e, knob));
90255
+ });
90256
+
90257
+ // Update the slider's gradient background
90258
+ const cssGradient = this.constructGradientString(pointsArray);
90259
+ this.setContainerGradient(cssGradient);
90260
+
90261
+ // show hide container
90262
+ this.showHideContainer();
90263
+ }
90264
+ showHideContainer() {
90265
+ let hide = false;
90266
+ if (this.sliderPoints.length === 2) {
90267
+ let color1 = this.sliderPoints[0].style.backgroundColor;
90268
+ let color2 = this.sliderPoints[1].style.backgroundColor;
90269
+ if (color1 === 'rgba(255, 255, 255, 1)' && color2 === 'rgba(255, 255, 255, 1)') {
90270
+ hide = true;
90271
+ }
90272
+ if (color1 === 'rgb(255, 255, 255)' && color2 === 'rgb(255, 255, 255)') {
90273
+ hide = true;
90274
+ }
90275
+ }
90276
+ if (hide) {
90277
+ this.sliderContainer.style.display = 'none';
90278
+ } else {
90279
+ this.sliderContainer.style.display = '';
90005
90280
  }
90006
90281
  }
90007
- hasClass(element, classname) {
90008
- if (!element) return false;
90009
- return element.classList ? element.classList.contains(classname) : new RegExp('\\b' + classname + '\\b').test(element.className);
90282
+ updateColor(color, index) {
90283
+ // update array (this also applies to the knob, because this.sliderPoints contains list of knobs)
90284
+ this.sliderPoints[index].style.backgroundColor = color;
90285
+
90286
+ // show hide container
90287
+ this.showHideContainer();
90288
+ this.update();
90010
90289
  }
90011
- addEventListener(parent, type, listener) {
90012
- parent.addEventListener(type, listener);
90290
+ removeColor(index) {
90291
+ // remove knob
90292
+ let sliderKnobs = this.sliderContainer.querySelectorAll('.slider-point');
90293
+ let knob = sliderKnobs[index];
90294
+ knob.removeEventListener('mousedown', this.dragStart);
90295
+ knob.removeEventListener('touchstart', this.dragStart);
90296
+ knob.remove();
90297
+
90298
+ // update array
90299
+ this.sliderPoints.splice(index, 1);
90300
+ this.update();
90013
90301
  }
90014
- }
90302
+ setupAddColorOnClick() {
90303
+ this.sliderContainer.addEventListener('click', this.addColorOnClick);
90304
+ // this.sliderContainer.addEventListener('touchstart', this.addColorOnClick, {passive: true});
90015
90305
 
90016
- // import ColorPicker from './colorpicker.js';
90306
+ // Indicate that the user can add a knob by changing the cursor
90307
+ this.sliderContainer.style.cursor = 'copy'; // Or use a custom cursor icon that indicates addition
90308
+ }
90017
90309
 
90018
- class GradientPicker {
90019
- constructor(opts = {}, builder) {
90020
- this.builder = builder;
90021
- let defaults = {
90022
- colors: ['#ff9f01', '#f57c00', '#e64918', '#d32f2f', '#5d4038', '#37474f', '#353535', '#fbc02c', '#b0b42a', '#689f39', '#c21f5b', '#7b21a2', '#522da8', '#616161', '#01b8c9', '#009688', '#388d3c', '#0388d0', '#1465c0', '#2f3f9e', '#9e9e9e'],
90023
- gradientcolors: [['linear-gradient(0deg, rgb(255, 57, 25), rgb(249, 168, 37))'], ['linear-gradient(0deg, rgb(255, 57, 25), rgb(255, 104, 15))'], ['linear-gradient(0deg, #FF5722, #FF9800)'], ['linear-gradient(0deg, #613ca2, rgb(110, 123, 217))'], ['linear-gradient(0deg, rgb(65, 70, 206), rgb(236, 78, 130))'], ['linear-gradient(0deg, rgb(0, 150, 102), rgb(90, 103, 197))'], ['linear-gradient(30deg, rgb(249, 119, 148), rgb(98, 58, 162))'], ['linear-gradient(0deg, rgb(223, 70, 137), rgb(90, 103, 197))'], ['linear-gradient(0deg, rgb(40, 53, 147), rgb(90, 103, 197))'], ['linear-gradient(0deg, rgb(21, 101, 192), rgb(52, 169, 239))'], ['linear-gradient(0deg, rgb(32, 149, 219), rgb(139, 109, 230))'], ['linear-gradient(0deg, rgb(90, 103, 197), rgb(0, 184, 201))'], ['linear-gradient(0deg, rgb(0, 184, 201), rgb(253, 187, 45))'], ['linear-gradient(0deg, rgb(255, 208, 100), rgb(239, 98, 159))'], ['linear-gradient(0deg, rgb(0, 214, 223), rgb(130, 162, 253))'], ['linear-gradient(0deg, rgb(50, 234, 251), rgb(248, 247, 126))'], ['linear-gradient(0deg, rgb(141, 221, 255), rgb(255, 227, 255))'], ['linear-gradient(0deg, rgb(255, 170, 170), rgb(255, 255, 200))'], ['linear-gradient(0deg, rgb(239, 239, 239), rgb(252, 252, 252))']],
90024
- animateModal: false,
90025
- elementToAnimate: '',
90026
- stuffPlacement: '#_cbhtml',
90027
- lang: []
90028
- };
90029
- this.opts = Object.assign(this, defaults, opts);
90030
- this.id = makeid();
90031
- let builderStuff = document.querySelector(this.opts.stuffPlacement);
90032
- if (!builderStuff) {
90033
- builderStuff = document.createElement('div');
90034
- builderStuff.id = '_cbhtml';
90035
- builderStuff.className = 'is-ui';
90036
- document.body.appendChild(builderStuff);
90310
+ interpolateColor(color1) {
90311
+ //, color2, fraction
90312
+ // Iimplement color interpolation logic.
90313
+ // fraction is a value between 0 and 1 indicating the relative position of the new stop.
90314
+ return color1; // for simplicity, just return color1
90315
+ }
90316
+
90317
+ addColorOnClick(e) {
90318
+ /*
90319
+ // Prevent the event if it's a touch event to stop it from triggering click events afterwards
90320
+ e.preventDefault();
90321
+ // Determine whether this is a touch event and extract the appropriate X position
90322
+ let clientX;
90323
+ if (e.touches) {
90324
+ clientX = e.touches[0].clientX; // Use the first touch point
90325
+ } else {
90326
+ clientX = e.clientX; // Use the mouse click position
90037
90327
  }
90038
- this.builderStuff = builderStuff;
90328
+ */
90329
+ let clientX = e.clientX;
90039
90330
 
90040
- // Stuff placement for this (single) instance
90041
- const objStuff = document.createElement('div');
90042
- objStuff.id = this.id;
90043
- builderStuff.appendChild(objStuff);
90044
- this.objStuff = objStuff;
90045
- const modal = new Modal({
90046
- animateModal: this.opts.animateModal,
90047
- elementToAnimate: this.opts.elementToAnimate,
90048
- stuffPlacement: this.opts.stuffPlacement
90049
- });
90050
- this.modal = modal;
90051
- let html_gradcolors = '';
90052
- for (var i = 0; i < this.opts.gradientcolors.length; i++) {
90053
- html_gradcolors += `<button data-elmgradient="${this.opts.gradientcolors[i][0]}" data-textcolor="${this.opts.gradientcolors[i][1] ? this.opts.gradientcolors[i][1] : ''}" style="background-image:${this.opts.gradientcolors[i][0]};"></button>`;
90331
+ // Ensure the action is triggered only when the container itself is touched, not its children
90332
+ if (!e.target.classList.contains('gradient-slider-container-shadow')) return;
90333
+ const rect = this.sliderContainer.getBoundingClientRect();
90334
+ const clickX = clientX - rect.left; // Click position within the sliderContainer, in pixels
90335
+ const width = rect.width;
90336
+ const positionPercentage = clickX / width * 100;
90337
+
90338
+ // Find the two closest stops surrounding the click position
90339
+ const sortedPoints = this.sliderPoints.map(knob => {
90340
+ return {
90341
+ position: parseFloat(knob.style.left),
90342
+ color: knob.style.backgroundColor
90343
+ };
90344
+ }).sort((a, b) => a.position - b.position);
90345
+
90346
+ // Find the surrounding stops
90347
+ let lowerStop = sortedPoints[0]; // Initialize with the first stop
90348
+ let upperStop = sortedPoints[sortedPoints.length - 1]; // Initialize with the last stop
90349
+ for (let i = 0; i < sortedPoints.length - 1; i++) {
90350
+ if (positionPercentage >= sortedPoints[i].position && positionPercentage <= sortedPoints[i + 1].position) {
90351
+ lowerStop = sortedPoints[i];
90352
+ upperStop = sortedPoints[i + 1];
90353
+ break;
90354
+ }
90054
90355
  }
90055
- let html = `<div class="is-pop pickgradientcolor" style="z-index:10005" tabindex="-1" role="dialog" aria-modal="true" aria-hidden="true">
90056
- <div class="div-gradients" style="display: flex;flex-flow: wrap;margin-bottom:10px;">
90057
- ${html_gradcolors}
90058
- <button class="input-gradient-clear" title="${this.out('Clear')}" data-value="" style="width:35px;height:35px;"><svg class="is-icon-flex" style="width:23px;height:23px;"><use xlink:href="#ion-ios-close-empty"></use></svg></button>
90059
- </div>
90060
- <div class="is-settings" style="margin-bottom:0">
90061
- <div class="is-label" style="margin-top:0">${this.out('Custom')}:</div>
90062
- <div class="div-custom-gradients" style="height:auto;display: flex;flex-flow: wrap;"></div>
90063
- <div style="display: flex;align-items: center;">
90064
- <button title="${this.out('Select Color')}" class="input-gradient-color1 is-btn-color" data-value="dark" style="width:36px;height:36px;"></button>
90065
- <button title="${this.out('Select Color')}" class="input-gradient-color2 is-btn-color" data-value="dark" style="width:36px;height:36px;"></button>
90066
- <input type="text" class="input-gradient-deg" id="{id}" value="0" style="width:60px;height:35px;margin-left:7px;margin-right:5px;font-size:14px;"/> deg
90067
- </div>
90068
- </div>
90069
- <div class="is-settings" style="margin-bottom:0">
90070
- <button title="${this.out('Add')}" class="input-gradient-save classic" style="width:100%;border:none;"> ${this.out('Add')} </button>
90071
- </div>
90072
- </div>
90073
- `;
90074
- objStuff.insertAdjacentHTML('beforeend', html.replace(/{id}/g, this.makeId()));
90075
- const pickGradient = objStuff.querySelector('.is-pop.pickgradientcolor');
90076
- this.pickGradient = pickGradient;
90077
- const setupTabKeys = div => {
90078
- let inputs = div.querySelectorAll('a[href], input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), *[tabindex]');
90079
- if (inputs.length === 0) return;
90080
- let firstInput = inputs[0];
90081
- let lastInput = inputs[inputs.length - 1];
90082
- // firstInput.focus();
90083
-
90084
- // console.log(lastInput)
90085
- // console.log(firstInput)
90086
-
90087
- // Redirect last tab to first input
90088
- lastInput.addEventListener('keydown', e => {
90089
- if (e.which === 9 && !e.shiftKey) {
90090
- e.preventDefault();
90091
- firstInput.focus();
90092
- }
90093
- });
90094
90356
 
90095
- // Redirect first shift+tab to last input
90096
- firstInput.addEventListener('keydown', e => {
90097
- if (e.which === 9 && e.shiftKey) {
90098
- e.preventDefault();
90099
- lastInput.focus();
90100
- }
90101
- });
90102
- };
90103
- setupTabKeys(pickGradient);
90104
- new Draggable$2({
90105
- selector: '#' + this.id + ' .is-draggable'
90357
+ // Calculate the fraction of the position between the lower and upper stops
90358
+ const fraction = (positionPercentage - lowerStop.position) / (upperStop.position - lowerStop.position);
90359
+
90360
+ // Interpolate the color
90361
+ const interpolatedColor = this.interpolateColor(lowerStop.color, upperStop.color, fraction);
90362
+
90363
+ // Now, add the color knob at the calculated position with the interpolated color
90364
+ this.addColor(interpolatedColor, positionPercentage);
90365
+ }
90366
+ addColor(color, position) {
90367
+ position = position - 4; // adjustment
90368
+
90369
+ // First, find the correct position to insert the new knob
90370
+ let insertAt = this.sliderPoints.findIndex(knob => {
90371
+ const knobPosition = parseFloat(knob.style.left);
90372
+ return position < knobPosition;
90106
90373
  });
90107
90374
 
90108
- // const colorPicker = new ColorPicker({
90109
- // colors: this.opts.colors,
90110
- // animateModal: this.opts.animateModal,
90111
- // elementToAnimate: this.opts.container,
90112
- // lang: this.opts.lang
90113
- // });
90114
- const colorPicker = this.builder.colorPicker;
90115
- let btnColor1 = objStuff.querySelector('.input-gradient-color1');
90116
- btnColor1.addEventListener('click', () => {
90117
- colorPicker.open(color => {
90118
- if (color === '') color = 'transparent';
90119
-
90120
- // set element style
90121
- let color1 = color;
90122
- let color2 = objStuff.querySelector('.input-gradient-color2').style.backgroundColor;
90123
- let deg = objStuff.querySelector('.input-gradient-deg').value;
90124
- if (color2 === '') color2 = '#ffffff';
90125
- let css = `linear-gradient(${deg}deg, ${color1}, ${color2})`;
90126
- this.targetElement.style.backgroundImage = css;
90127
- if (this.opts.onChange) this.opts.onChange(css);
90128
-
90129
- // update preview
90130
- btnColor1.style.backgroundColor = color;
90131
- }, btnColor1.style.backgroundColor, () => {
90132
- btnColor1.removeAttribute('data-focus');
90133
- btnColor1.focus();
90134
- }, btnColor1, true); // overlay=true
90135
-
90136
- btnColor1.setAttribute('data-focus', true);
90137
- });
90138
- let btnColor2 = objStuff.querySelector('.input-gradient-color2');
90139
- btnColor2.addEventListener('click', () => {
90140
- colorPicker.open(color => {
90141
- if (color === '') color = 'transparent';
90142
-
90143
- // set element style
90144
- let color1 = objStuff.querySelector('.input-gradient-color1').style.backgroundColor;
90145
- let color2 = color;
90146
- let deg = objStuff.querySelector('.input-gradient-deg').value;
90147
- if (color1 === '') color1 = '#ffffff';
90148
- let css = `linear-gradient(${deg}deg, ${color1}, ${color2})`;
90149
- this.targetElement.style.backgroundImage = css;
90150
- if (this.opts.onChange) this.opts.onChange(css);
90151
-
90152
- // update preview
90153
- btnColor2.style.backgroundColor = color;
90154
- }, btnColor2.style.backgroundColor, () => {
90155
- btnColor2.removeAttribute('data-focus');
90156
- btnColor2.focus();
90157
- }, btnColor2, true); // overlay=true
90158
-
90159
- btnColor2.setAttribute('data-focus', true);
90160
- });
90161
-
90162
- // Apply default gradient
90163
- let btns = objStuff.querySelectorAll('.div-gradients [data-elmgradient]');
90164
- Array.prototype.forEach.call(btns, btn => {
90165
- let grad = btn.getAttribute('data-elmgradient');
90166
- let textcolor = btn.getAttribute('data-textcolor');
90167
- btn.addEventListener('click', () => {
90168
- this.targetElement.style.backgroundImage = grad;
90169
- if (this.opts.onChange) this.opts.onChange(grad, textcolor);
90170
-
90171
- // Read gradient
90172
- const s = this.targetElement.style.backgroundImage;
90173
- if (s.indexOf('linear-gradient') !== -1) {
90174
- const result = getGradient(s);
90175
- if (result !== null) {
90176
- try {
90177
- let color1 = result.colorStopList[0].color;
90178
- let color2 = result.colorStopList[1].color;
90179
- let line = result.line;
90180
- this.objStuff.querySelector('.input-gradient-color1').style.backgroundColor = color1;
90181
- this.objStuff.querySelector('.input-gradient-color2').style.backgroundColor = color2;
90182
- if (line.indexOf('deg') !== -1) {
90183
- this.objStuff.querySelector('.input-gradient-deg').value = line.replace('deg', '');
90184
- }
90185
- } catch (e) {
90186
- // Do Nothing
90187
- }
90188
- }
90189
- }
90190
- let btns = objStuff.querySelectorAll('.div-gradients [data-elmgradient]');
90191
- Array.prototype.forEach.call(btns, btn => {
90192
- this.removeClass(btn, 'active');
90193
- });
90194
- this.addClass(btn, 'active');
90195
- });
90375
+ // If no suitable position is found (i.e., we're inserting at the end or the array is empty), adjust insertAt accordingly
90376
+ if (insertAt === -1) insertAt = this.sliderPoints.length;
90377
+
90378
+ // Create and configure the new knob
90379
+ const knob = document.createElement('div');
90380
+ knob.className = 'slider-point';
90381
+ knob.style.left = `${position}%`;
90382
+ knob.style.backgroundColor = color;
90383
+
90384
+ // Accessibility Enhancements
90385
+ knob.setAttribute('tabindex', '0');
90386
+ knob.setAttribute('role', 'slider');
90387
+ knob.setAttribute('aria-valuemin', '0');
90388
+ knob.setAttribute('aria-valuemax', '100');
90389
+ knob.setAttribute('aria-valuenow', position);
90390
+ knob.setAttribute('aria-valuetext', `Color: ${color}, Position: ${position}%`);
90391
+ knob.setAttribute('aria-labelledby', this.uniqueId);
90392
+
90393
+ // Initialize drag functionality
90394
+ knob.addEventListener('mousedown', this.dragStart.bind(this, knob), {
90395
+ passive: false
90196
90396
  });
90197
- let btnClear = objStuff.querySelector('.input-gradient-clear');
90198
- btnClear.addEventListener('click', () => {
90199
- this.targetElement.style.backgroundImage = '';
90200
- if (this.opts.onChange) this.opts.onChange('');
90201
- this.objStuff.querySelector('.input-gradient-color1').style.backgroundColor = '';
90202
- this.objStuff.querySelector('.input-gradient-color2').style.backgroundColor = '';
90203
- this.objStuff.querySelector('.input-gradient-deg').value = '0';
90397
+ knob.addEventListener('touchstart', this.dragStart.bind(this, knob), {
90398
+ passive: false
90204
90399
  });
90205
- let inputDeg = objStuff.querySelector('.input-gradient-deg');
90206
- inputDeg.addEventListener('keyup', () => {
90207
- // set element style
90208
- let color1 = objStuff.querySelector('.input-gradient-color1').style.backgroundColor;
90209
- let color2 = objStuff.querySelector('.input-gradient-color2').style.backgroundColor;
90210
- let deg = inputDeg.value;
90400
+ if (insertAt === this.sliderPoints.length) {
90401
+ // If inserting at the end, simply add the knob to the container
90402
+ this.sliderContainer.appendChild(knob);
90403
+ } else {
90404
+ // Otherwise, insert the knob before the knob currently at the insertAt position
90405
+ this.sliderContainer.insertBefore(knob, this.sliderPoints[insertAt]);
90406
+ }
90211
90407
 
90212
- // if(color1 === '') color1 = '#ffffff';
90213
- // if(color2 === '') color2 = '#ffffff';
90408
+ // Update the internal representation and the displayed gradient
90409
+ this.sliderPoints.splice(insertAt, 0, knob); // Insert the knob into the internal array at the correct position
90410
+
90411
+ this.update(true); // Update the gradient and emit the change event
90412
+ }
90214
90413
 
90215
- let css = `linear-gradient(${deg}deg, ${color1}, ${color2})`;
90216
- this.targetElement.style.backgroundImage = css;
90217
- if (this.opts.onChange) this.opts.onChange(css);
90414
+ update(triggerAddpoint) {
90415
+ // Generate pointsArray based on the points color & position
90416
+ const pointsArray = this.sliderPoints.map(point => {
90417
+ const position = parseFloat(point.style.left); // Assuming style.left is always in '%'
90418
+ return {
90419
+ color: point.style.backgroundColor,
90420
+ position: position
90421
+ };
90218
90422
  });
90219
- let btnSave = objStuff.querySelector('.input-gradient-save');
90220
- btnSave.addEventListener('click', () => {
90221
- let color1 = objStuff.querySelector('.input-gradient-color1').style.backgroundColor;
90222
- let color2 = objStuff.querySelector('.input-gradient-color2').style.backgroundColor;
90223
- let deg = inputDeg.value;
90224
90423
 
90225
- // if(color1 === '') color1 = '#ffffff';
90226
- // if(color2 === '') color2 = '#ffffff';
90424
+ // Update the slider's gradient background
90425
+ const cssGradient = this.constructGradientString(pointsArray);
90426
+ this.setContainerGradient(cssGradient);
90227
90427
 
90228
- let css = `linear-gradient(${deg}deg, ${color1}, ${color2})`;
90428
+ // Emit a "change" event with the pointsArray as the detail
90429
+ this.emit('change', pointsArray, cssGradient);
90430
+ if (triggerAddpoint) {
90431
+ this.emit('addpoint', pointsArray, cssGradient);
90432
+ }
90433
+ }
90434
+ dragStart(knob, e) {
90435
+ this.knob = knob;
90436
+ e.preventDefault();
90437
+ this.isDragging = true;
90229
90438
 
90230
- // Save
90231
- let customgradcolors = [];
90232
- if (localStorage.getItem('_customgradcolors') !== null) {
90233
- customgradcolors = JSON.parse(localStorage.getItem('_customgradcolors'));
90234
- }
90235
- customgradcolors.push(css);
90236
- localStorage.setItem('_customgradcolors', JSON.stringify(customgradcolors));
90439
+ // Get the initial offset by subtracting the slider point's left position from the cursor's X position
90440
+ const startX = e.touches ? e.touches[0].clientX : e.clientX;
90441
+ const pointRect = knob.getBoundingClientRect();
90442
+ this.initialOffsetX = startX - pointRect.left;
90443
+ document.addEventListener('mousemove', this.drag);
90444
+ document.addEventListener('touchmove', this.drag);
90445
+ document.addEventListener('mouseup', this.dragStop);
90446
+ document.addEventListener('touchend', this.dragStop);
90447
+ this.emit('slideStart', knob);
90448
+ }
90449
+ drag(e) {
90450
+ if (!this.isDragging) return;
90451
+ const knob = this.knob;
90237
90452
 
90238
- // Render custom gradients
90239
- if (localStorage.getItem('_customgradcolors') !== null) {
90240
- let customgradcolors = JSON.parse(localStorage.getItem('_customgradcolors'));
90241
- let html_gradcolors = '';
90242
- for (var i = 0; i < customgradcolors.length; i++) {
90243
- html_gradcolors += `<button class="is-elmgrad-item" data-elmgradient="${customgradcolors[i]}" style="background-image:${customgradcolors[i]};"><div class="is-elmgrad-remove"><svg class="is-icon-flex" style="fill:rgba(255, 255, 255, 1);width:20px;height:20px;"><use xlink:href="#ion-ios-close-empty"></use></svg></div></button>`;
90244
- }
90245
- this.objStuff.querySelector('.div-custom-gradients').innerHTML = html_gradcolors;
90246
- }
90453
+ // Update knob (left) position
90454
+ let touch = e.touches ? e.touches[0] : e;
90455
+ let rect = this.sliderContainer.getBoundingClientRect();
90456
+ let x = touch.clientX - rect.left - this.initialOffsetX; // Adjust position based on initial offset
90457
+ let percentage = Math.max(0, Math.min(100, x / rect.width * 100));
90458
+ knob.style.left = `${percentage}%`;
90247
90459
 
90248
- // Apply custom gradient
90249
- let btns = this.objStuff.querySelectorAll('.div-custom-gradients [data-elmgradient]');
90250
- Array.prototype.forEach.call(btns, btn => {
90251
- let grad = btn.getAttribute('data-elmgradient');
90252
- btn.addEventListener('click', () => {
90253
- this.targetElement.style.backgroundImage = grad;
90254
- if (this.opts.onChange) this.opts.onChange(grad);
90255
-
90256
- // Read gradient
90257
- const s = this.targetElement.style.backgroundImage;
90258
- if (s.indexOf('linear-gradient') !== -1) {
90259
- const result = getGradient(s);
90260
- if (result !== null) {
90261
- try {
90262
- let color1 = result.colorStopList[0].color;
90263
- let color2 = result.colorStopList[1].color;
90264
- let line = result.line;
90265
- this.objStuff.querySelector('.input-gradient-color1').style.backgroundColor = color1;
90266
- this.objStuff.querySelector('.input-gradient-color2').style.backgroundColor = color2;
90267
- if (line.indexOf('deg') !== -1) {
90268
- this.objStuff.querySelector('.input-gradient-deg').value = line.replace('deg', '');
90269
- }
90270
- } catch (e) {
90271
- // Do Nothing
90272
- }
90273
- }
90274
- }
90275
- let btns = objStuff.querySelectorAll('.div-custom-gradients [data-elmgradient]');
90276
- Array.prototype.forEach.call(btns, btn => {
90277
- this.removeClass(btn, 'active');
90278
- });
90279
- this.addClass(btn, 'active');
90280
- });
90281
- });
90460
+ // Updating knob (left) position will also update the this.sliderPoints
90461
+ // console.log(this.sliderPoints[1].style.left); // to test
90282
90462
 
90283
- // Delete custom gradient
90284
- let btnsRemoveGrad = this.objStuff.querySelectorAll('.div-custom-gradients .is-elmgrad-remove');
90285
- Array.prototype.forEach.call(btnsRemoveGrad, btnRemoveGrad => {
90286
- btnRemoveGrad.addEventListener('click', e => {
90287
- //Custom grad colors
90288
- let customgradcolors = [];
90289
- if (localStorage.getItem('_customgradcolors') !== null) {
90290
- customgradcolors = JSON.parse(localStorage.getItem('_customgradcolors'));
90291
- }
90292
- var css = btnRemoveGrad.parentNode.getAttribute('data-elmgradient');
90293
- for (var i = 0; i < customgradcolors.length; i++) {
90294
- if (customgradcolors[i] === css) {
90295
- customgradcolors.splice(i, 1);
90296
- }
90297
- }
90298
- localStorage.setItem('_customgradcolors', JSON.stringify(customgradcolors));
90299
- btnRemoveGrad.closest('.is-elmgrad-item').remove();
90300
- e.preventDefault();
90301
- e.stopImmediatePropagation();
90302
- });
90303
- });
90463
+ // this.update() //The code below is similar to update(), only that it triggers sliderChange
90464
+
90465
+ // Generate pointsArray based on the points color & position
90466
+ const pointsArray = this.sliderPoints.map(point => {
90467
+ const position = parseFloat(point.style.left); // Assuming style.left is always in '%'
90468
+ return {
90469
+ color: point.style.backgroundColor,
90470
+ position: position
90471
+ };
90304
90472
  });
90305
- } //constructor
90306
90473
 
90307
- makeId() {
90308
- let text = '';
90309
- let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
90310
- for (let i = 0; i < 2; i++) text += possible.charAt(Math.floor(Math.random() * possible.length));
90311
- let text2 = '';
90312
- let possible2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
90313
- for (let i = 0; i < 5; i++) text2 += possible2.charAt(Math.floor(Math.random() * possible2.length));
90314
- return text + text2;
90474
+ // Update the slider's gradient background
90475
+ const cssGradient = this.constructGradientString(pointsArray);
90476
+ this.setContainerGradient(cssGradient);
90477
+
90478
+ // Emit a "slideChange" event with the pointsArray as the detail
90479
+ this.emit('slideChange', pointsArray, cssGradient);
90480
+ }
90481
+ dragStop() {
90482
+ this.isDragging = false;
90483
+ document.removeEventListener('mousemove', this.drag);
90484
+ document.removeEventListener('touchmove', this.drag);
90485
+ document.removeEventListener('mouseup', this.dragStop);
90486
+ document.removeEventListener('touchend', this.dragStop);
90487
+ this.emit('slideEnd');
90488
+ }
90489
+ clearPoints() {
90490
+ // Remove all child slider points from the container
90491
+ const sliderKnobs = this.sliderContainer.querySelectorAll('.slider-point');
90492
+ sliderKnobs.forEach(knob => {
90493
+ knob.removeEventListener('mousedown', this.dragStart);
90494
+ knob.removeEventListener('touchstart', this.dragStart);
90495
+ knob.remove();
90496
+ });
90497
+
90498
+ // update array
90499
+ this.sliderPoints = []; // Clear
90315
90500
  }
90501
+
90502
+ handleKeydown(e, sliderPoint) {
90503
+ const key = e.key;
90504
+ let newPosition = parseFloat(sliderPoint.style.left);
90505
+ if (key === 'ArrowRight' || key === 'ArrowUp') {
90506
+ newPosition = Math.min(100, newPosition + 1); // Increase position
90507
+ } else if (key === 'ArrowLeft' || key === 'ArrowDown') {
90508
+ newPosition = Math.max(0, newPosition - 1); // Decrease position
90509
+ } else {
90510
+ return; // Ignore other keys
90511
+ }
90512
+
90513
+ sliderPoint.style.left = `${newPosition}%`;
90514
+ sliderPoint.setAttribute('aria-valuenow', newPosition);
90515
+ sliderPoint.setAttribute('aria-valuetext', `Color: ${sliderPoint.style.backgroundColor}, Position: ${newPosition}%`);
90516
+
90517
+ // Update gradient and invoke onChange callback with the new positions
90518
+ this.dragStop(); // Simulate dragStop to update positions and gradient
90519
+ }
90520
+
90521
+ setContainerGradient(cssGradient) {
90522
+ this.shadowContainer.style.backgroundImage = cssGradient;
90523
+ }
90524
+ destroy() {
90525
+ if (this.element.nextElementSibling && this.element.nextElementSibling.classList.contains('gradient-slider-container')) {
90526
+ this.clearPoints();
90527
+ this.element.nextElementSibling.remove();
90528
+ }
90529
+ }
90530
+ }
90531
+
90532
+ class GradientPicker {
90533
+ constructor(builder) {
90534
+ this.builder = builder;
90535
+ this.builderStuff = this.builder.builderStuff;
90536
+ this.util = this.builder.util;
90537
+ let html_gradcolors = '';
90538
+ this.builder.gradientColors.forEach(s => {
90539
+ html_gradcolors += `
90540
+ <button
90541
+ title="${this.out('Select')}"
90542
+ class="btn-graditem" data-value="${s}"
90543
+ style="background-image:${s}"></button>
90544
+ `;
90545
+ });
90546
+ let html = `<div class="is-pop pickgradientcolor" style="z-index:10005" tabindex="-1" role="dialog" aria-modal="true" aria-hidden="true">
90547
+ <div class="div-presets">
90548
+ ${html_gradcolors}
90549
+ </div>
90550
+
90551
+ <div class="label-saved">${this.out('Saved')}:</div>
90552
+ <div class="div-saved"></div>
90553
+
90554
+ <div class="label-saved">${this.out('Gradient Colors')}:</div>
90555
+
90556
+ <div class="gradient-slider" role="application"></div>
90557
+
90558
+ <div class="div-sort"></div>
90559
+
90560
+ <div class="div-add">
90561
+ <button title="${this.out('Clear')}" class="btn-clear">
90562
+ <svg><use xlink:href="#icon-eraser"></use></svg>
90563
+ </button>
90564
+ <input type="text" class="inp-angle" value="0">
90565
+ <button title="${this.out('Add')}" class="btn-addstop"><svg class="is-icon-flex"><use xlink:href="#icon-plus"></use></svg></button>
90566
+ </div>
90567
+
90568
+ <div class="div-save">
90569
+ <button title="${this.out('Save')}" class="btn-save">${this.out('Save')}</button>
90570
+ </div>
90571
+ `;
90572
+ this.builderStuff.insertAdjacentHTML('beforeend', html);
90573
+ const pickGradient = this.builderStuff.querySelector('.is-pop.pickgradientcolor');
90574
+ this.pickGradient = pickGradient;
90575
+ this.init();
90576
+ } //constructor
90577
+
90316
90578
  out(s) {
90317
- if (this.opts.lang) {
90318
- let val = this.opts.lang[s];
90579
+ if (this.builder.lang) {
90580
+ let val = this.builder.lang[s];
90319
90581
  if (val) return val;else {
90320
90582
  return s;
90321
90583
  }
@@ -90323,135 +90585,328 @@ class GradientPicker {
90323
90585
  return s;
90324
90586
  }
90325
90587
  }
90326
- open(elm, onChange, onFinish, btn, overlay) {
90327
- this.opts.onChange = onChange;
90328
- this.opts.onFinish = onFinish;
90329
- this.targetElement = elm;
90330
-
90331
- // Read gradient
90332
- this.objStuff.querySelector('.input-gradient-color1').style.backgroundColor = '';
90333
- this.objStuff.querySelector('.input-gradient-color2').style.backgroundColor = '';
90334
- this.objStuff.querySelector('.input-gradient-deg').value = '0';
90335
- const s = elm.style.backgroundImage;
90336
- if (s.indexOf('linear-gradient') !== -1) {
90337
- const result = getGradient(s);
90338
- if (result !== null) {
90339
- try {
90340
- let color1 = result.colorStopList[0].color;
90341
- let color2 = result.colorStopList[1].color;
90342
- let line = result.line;
90343
- this.objStuff.querySelector('.input-gradient-color1').style.backgroundColor = color1;
90344
- this.objStuff.querySelector('.input-gradient-color2').style.backgroundColor = color2;
90345
- if (line.indexOf('deg') !== -1) {
90346
- this.objStuff.querySelector('.input-gradient-deg').value = line.replace('deg', '');
90347
- }
90348
- } catch (e) {
90349
- // Do Nothing
90350
- }
90588
+ init() {
90589
+ this.renderSavedGradients();
90590
+ const divGradSlider = this.pickGradient.querySelector('.gradient-slider');
90591
+ const gradSlider = new GradientSlider(divGradSlider, {
90592
+ label: this.out('Gradient Slider')
90593
+ });
90594
+ this.gradSlider = gradSlider;
90595
+ gradSlider.on('slideStart', () => {
90596
+ this.builder.uo.saveForUndo(true);
90597
+ });
90598
+ gradSlider.on('slideEnd', () => {
90599
+ if (this.onChange) this.onChange();
90600
+ this.builder.onChange();
90601
+ });
90602
+ gradSlider.on('slideChange', pointsArray => {
90603
+ this.colorsPosArray = pointsArray;
90604
+ this.applyGradient();
90605
+ });
90606
+ gradSlider.on('change', pointsArray => {
90607
+ this.colorsPosArray = pointsArray;
90608
+ this.applyGradient();
90609
+ if (this.onChange) this.onChange();
90610
+ this.builder.onChange();
90611
+ });
90612
+ gradSlider.on('addpoint', () => {
90613
+ this.renderColorStops();
90614
+ });
90615
+ const inpAngle = this.pickGradient.querySelector('.inp-angle');
90616
+ this.slider = new RoundedSlider(inpAngle, {
90617
+ onStart: () => {
90618
+ this.builder.uo.saveForUndo(true); // checkLater = true
90351
90619
  }
90352
- }
90620
+ });
90621
+
90622
+ inpAngle.oninput = () => {
90623
+ this.angle = inpAngle.value;
90624
+ this.applyGradient();
90625
+ if (this.onChange) this.onChange();
90626
+ this.builder.onChange();
90627
+ };
90628
+ const btnAddStop = this.pickGradient.querySelector('.btn-addstop');
90629
+ if (btnAddStop) btnAddStop.addEventListener('click', () => {
90630
+ this.builder.uo.saveForUndo();
90631
+ const lastItem = this.colorsPosArray[this.colorsPosArray.length - 1];
90632
+ lastItem.position = lastItem.position - 15;
90633
+ this.colorsPosArray.push({
90634
+ color: lastItem.color,
90635
+ position: 100
90636
+ });
90637
+ this.renderColorPositions();
90638
+ this.renderColorStops();
90639
+ this.applyGradient();
90640
+ if (this.onChange) this.onChange();
90641
+ this.builder.onChange();
90642
+ });
90643
+ const btnSave = this.pickGradient.querySelector('.btn-save');
90644
+ if (btnSave) btnSave.addEventListener('click', () => {
90645
+ this.saveGradient();
90646
+ this.renderSavedGradients();
90647
+ });
90648
+ const btnClear = this.pickGradient.querySelector('.btn-clear');
90649
+ if (btnClear) btnClear.addEventListener('click', () => {
90650
+ this.builder.uo.saveForUndo();
90651
+ this.angle = 0;
90652
+ this.renderAngle();
90653
+ this.colorsPosArray = [{
90654
+ color: 'rgba(255, 255, 255, 1)',
90655
+ position: 0
90656
+ }, {
90657
+ color: 'rgba(255, 255, 255, 1)',
90658
+ position: 100
90659
+ }];
90660
+ this.renderColorPositions();
90661
+ this.renderColorStops();
90662
+
90663
+ // this.applyGradient();
90664
+ this.element.style.backgroundImage = '';
90665
+ this.btn.style.backgroundImage = '';
90666
+ if (this.onChange) this.onChange();
90667
+ this.builder.onChange();
90668
+ });
90353
90669
 
90354
- // Save original style
90355
- this.original = s;
90670
+ // presets
90671
+ const divPreset = this.pickGradient.querySelector('.div-presets');
90672
+ const btnApply = divPreset.querySelectorAll('.btn-graditem');
90673
+ btnApply.forEach(btn => {
90674
+ btn.addEventListener('click', () => {
90675
+ this.builder.uo.saveForUndo();
90676
+ let cssGradient = btn.getAttribute('data-value');
90677
+ const angle = this.extractAngle(cssGradient);
90678
+ this.angle = angle;
90679
+ this.renderAngle();
90680
+ const colorsPosArray = this.extractColorsPos(cssGradient);
90681
+ this.colorsPosArray = colorsPosArray;
90682
+ this.renderColorPositions();
90683
+ this.renderColorStops();
90684
+ this.applyGradient();
90685
+ if (this.onChange) this.onChange();
90686
+ this.builder.onChange();
90687
+ });
90688
+ });
90689
+ }
90690
+ saveGradient() {
90691
+ let gradient = {
90692
+ angle: this.angle,
90693
+ colors: this.colorsPosArray
90694
+ };
90695
+ this.savedGrads.push(gradient);
90696
+ localStorage.setItem('_savedgrads', JSON.stringify(this.savedGrads));
90697
+ }
90698
+ renderSavedGradients() {
90699
+ let savedGrads = [];
90700
+ if (localStorage.getItem('_savedgrads') !== null) {
90701
+ savedGrads = JSON.parse(localStorage.getItem('_savedgrads'));
90702
+ }
90703
+ this.savedGrads = savedGrads;
90356
90704
 
90357
- // Render custom gradients
90705
+ // backward (move old saved gradients to the new. Then delete the old)
90706
+ let oldGrads = [];
90358
90707
  let customgradcolors = [];
90359
90708
  if (localStorage.getItem('_customgradcolors') !== null) {
90360
90709
  customgradcolors = JSON.parse(localStorage.getItem('_customgradcolors'));
90361
- let html_gradcolors = '';
90362
- for (var i = 0; i < customgradcolors.length; i++) {
90363
- html_gradcolors += `<button class="is-elmgrad-item" data-elmgradient="${customgradcolors[i]}" style="background-image:${customgradcolors[i]};"><div class="is-elmgrad-remove"><svg class="is-icon-flex" style="fill:rgba(255, 255, 255, 1);width:20px;height:20px;"><use xlink:href="#ion-ios-close-empty"></use></svg></div></button>`;
90364
- }
90365
- this.objStuff.querySelector('.div-custom-gradients').innerHTML = html_gradcolors;
90710
+ customgradcolors.forEach(cssGradient => {
90711
+ const colorsPosArray = this.extractColorsPos(cssGradient);
90712
+ const angle = this.extractAngle(cssGradient);
90713
+ let gradient = {
90714
+ angle: angle,
90715
+ colors: colorsPosArray
90716
+ };
90717
+ oldGrads.push(gradient);
90718
+ });
90719
+ Array.prototype.push.apply(this.savedGrads, oldGrads); // combine old with the new
90720
+ localStorage.setItem('_savedgrads', JSON.stringify(this.savedGrads));
90721
+ localStorage.removeItem('_customgradcolors');
90366
90722
  }
90723
+ // /backward
90367
90724
 
90368
- // Apply custom gradient
90369
- let btns = this.objStuff.querySelectorAll('.div-custom-gradients [data-elmgradient]');
90370
- Array.prototype.forEach.call(btns, btn => {
90371
- let grad = btn.getAttribute('data-elmgradient');
90725
+ const divSaved = this.pickGradient.querySelector('.div-saved');
90726
+ const labelSaved = this.pickGradient.querySelector('.label-saved');
90727
+ let html = '';
90728
+ savedGrads.forEach((gradient, index) => {
90729
+ let angle = gradient.angle;
90730
+ let colorsPosArray = gradient.colors;
90731
+ let cssGradient = this.constructGradientString(colorsPosArray, angle); // set the angle
90732
+ html += `
90733
+ <div>
90734
+ <button
90735
+ data-index="${index}"
90736
+ title="${this.out('Select')}"
90737
+ class="btn-graditem" data-value="${cssGradient}"
90738
+ style="background-image:${cssGradient}"></button>
90739
+
90740
+ <button title="${this.out('Remove')}" class="btn-remove">
90741
+ <svg class="is-icon-flex"><use xlink:href="#icon-minus"></use></svg>
90742
+ </button>
90743
+ </div>
90744
+ `;
90745
+ });
90746
+ divSaved.innerHTML = html;
90747
+ if (savedGrads.length === 0) {
90748
+ divSaved.style.display = 'none';
90749
+ labelSaved.style.display = 'none';
90750
+ } else {
90751
+ divSaved.style.display = '';
90752
+ labelSaved.style.display = '';
90753
+ }
90754
+ const btnApply = divSaved.querySelectorAll('.btn-graditem');
90755
+ btnApply.forEach(btn => {
90372
90756
  btn.addEventListener('click', () => {
90373
- this.targetElement.style.backgroundImage = grad;
90374
- if (this.opts.onChange) this.opts.onChange(grad);
90375
-
90376
- // Read gradient
90377
- const s = this.targetElement.style.backgroundImage;
90378
- if (s.indexOf('linear-gradient') !== -1) {
90379
- const result = getGradient(s);
90380
- if (result !== null) {
90381
- try {
90382
- let color1 = result.colorStopList[0].color;
90383
- let color2 = result.colorStopList[1].color;
90384
- let line = result.line;
90385
- this.objStuff.querySelector('.input-gradient-color1').style.backgroundColor = color1;
90386
- this.objStuff.querySelector('.input-gradient-color2').style.backgroundColor = color2;
90387
- if (line.indexOf('deg') !== -1) {
90388
- this.objStuff.querySelector('.input-gradient-deg').value = line.replace('deg', '');
90389
- }
90390
- } catch (e) {
90391
- // Do Nothing
90392
- }
90393
- }
90394
- }
90395
- let btns = this.objStuff.querySelectorAll('.div-custom-gradients [data-elmgradient]');
90396
- Array.prototype.forEach.call(btns, btn => {
90397
- this.removeClass(btn, 'active');
90398
- });
90399
- this.addClass(btn, 'active');
90757
+ this.builder.uo.saveForUndo();
90758
+ let cssGradient = btn.getAttribute('data-value');
90759
+ const angle = this.extractAngle(cssGradient);
90760
+ this.angle = angle;
90761
+ this.renderAngle();
90762
+ const colorsPosArray = this.extractColorsPos(cssGradient);
90763
+ this.colorsPosArray = colorsPosArray;
90764
+ this.renderColorPositions();
90765
+ this.renderColorStops();
90766
+ this.applyGradient();
90767
+ if (this.onChange) this.onChange();
90768
+ this.builder.onChange();
90400
90769
  });
90401
90770
  });
90402
-
90403
- // Delete custom gradient
90404
- let btnsRemoveGrad = this.objStuff.querySelectorAll('.div-custom-gradients .is-elmgrad-remove');
90405
- Array.prototype.forEach.call(btnsRemoveGrad, btnRemoveGrad => {
90406
- btnRemoveGrad.addEventListener('click', e => {
90407
- //Custom grad colors
90408
- let customgradcolors = [];
90409
- if (localStorage.getItem('_customgradcolors') !== null) {
90410
- customgradcolors = JSON.parse(localStorage.getItem('_customgradcolors'));
90411
- }
90412
- var css = btnRemoveGrad.parentNode.getAttribute('data-elmgradient');
90413
- for (var i = 0; i < customgradcolors.length; i++) {
90414
- if (customgradcolors[i] === css) {
90415
- customgradcolors.splice(i, 1);
90416
- }
90771
+ const btnRemove = divSaved.querySelectorAll('.btn-remove');
90772
+ btnRemove.forEach(btn => {
90773
+ btn.addEventListener('click', e => {
90774
+ let index = btn.getAttribute('data-index');
90775
+ btn.parentNode.remove();
90776
+ this.removeItemByIndex(this.savedGrads, index);
90777
+ localStorage.setItem('_savedgrads', JSON.stringify(this.savedGrads));
90778
+ if (this.savedGrads.length === 0) {
90779
+ divSaved.style.display = 'none';
90780
+ labelSaved.style.display = 'none';
90781
+ } else {
90782
+ divSaved.style.display = '';
90783
+ labelSaved.style.display = '';
90417
90784
  }
90418
- localStorage.setItem('_customgradcolors', JSON.stringify(customgradcolors));
90419
- btnRemoveGrad.closest('.is-elmgrad-item').remove();
90420
90785
  e.preventDefault();
90421
90786
  e.stopImmediatePropagation();
90422
90787
  });
90423
90788
  });
90424
- const handleKeyDown = e => {
90425
- if (e.keyCode === 27) {
90426
- // escape key
90427
- this.pickGradient.classList.remove('active'); // hide
90428
-
90429
- this.pickGradient.removeEventListener('keydown', handleKeyDown);
90789
+ }
90790
+ applyGradient() {
90791
+ let cssGradient;
90792
+ if (this.colorsPosArray === 0) {
90793
+ cssGradient = '';
90794
+ } else {
90795
+ cssGradient = this.constructGradientString(this.colorsPosArray);
90796
+ }
90430
90797
 
90431
- // no change
90432
- if (this.opts.onFinish) {
90433
- this.opts.onFinish(false);
90434
- }
90798
+ // apply to element
90799
+ this.element.style.backgroundImage = cssGradient;
90800
+ this.btn.style.backgroundImage = cssGradient;
90801
+ }
90802
+ renderColorStops() {
90803
+ if (this.colorsPosArray.length === 0) {
90804
+ this.colorsPosArray = [{
90805
+ color: 'rgba(255, 255, 255, 1)',
90806
+ position: 0
90807
+ }, {
90808
+ color: 'rgba(255, 255, 255, 1)',
90809
+ position: 100
90810
+ }];
90811
+ }
90812
+ let htmlStop = '';
90813
+ this.colorsPosArray.forEach((item, index) => {
90814
+ htmlStop += `<div>
90815
+ <button data-color="${item.color}"
90816
+ data-index="${index}"
90817
+ title="${this.out('Select Color')}"
90818
+ class="btn-colorstop is-btn-color"
90819
+ data-value="${item.color}"
90820
+ style="background-color:${item.color}"></button>
90821
+
90822
+ <button title="${this.out('Remove')}" class="btn-remove">
90823
+ <svg class="is-icon-flex"><use xlink:href="#icon-minus"></use></svg>
90824
+ </button>
90825
+ </div>`;
90826
+ });
90827
+ const divSort = this.pickGradient.querySelector('.div-sort');
90828
+ divSort.innerHTML = htmlStop;
90829
+ new Sortable$1(divSort, {
90830
+ animation: 600,
90831
+ dragClass: 'hide-drag-class',
90832
+ onStart: () => {},
90833
+ onSort: () => {
90834
+ // TODO
90835
+
90836
+ const btnPicks = this.pickGradient.querySelectorAll('.btn-colorstop');
90837
+ let colors = [];
90838
+ btnPicks.forEach(btn => {
90839
+ let color = btn.style.backgroundColor;
90840
+ colors.push(color);
90841
+ });
90842
+ this.colorsPosArray.map((item, index) => {
90843
+ item.color = colors[index];
90844
+ });
90845
+ this.gradSlider.draw(this.colorsPosArray);
90846
+ this.renderColorStops();
90847
+ this.applyGradient();
90848
+ if (this.onChange) this.onChange();
90849
+ this.builder.onChange();
90435
90850
  }
90436
- };
90851
+ });
90852
+ const colorPicker = this.builder.colorPicker;
90853
+ const btnPicks = this.pickGradient.querySelectorAll('.btn-colorstop');
90854
+ btnPicks.forEach((btn, index) => {
90855
+ btn.addEventListener('click', () => {
90856
+ this.builder.uo.saveForUndo(true);
90857
+ colorPicker.open(color => {
90858
+ if (color === '') {
90859
+ const allow = this.allowRemoveStop();
90860
+ if (allow) {
90861
+ // remove
90862
+ btn.parentNode.querySelector('.btn-remove').click();
90863
+ this.builder.util.hidePopOverlay(); // if pop is opened using overlay, to programmatically close, use this
90864
+ return;
90865
+ }
90866
+ }
90867
+ if (color === '') color = 'rgba(255, 255, 255, 1)'; // gradient stop requires value
90437
90868
 
90438
- // this.modal.show(this.pickGradient, false, ()=>{
90869
+ btn.setAttribute('data-color', color);
90870
+ btn.style.backgroundColor = color;
90871
+ this.gradSlider.updateColor(color, index); // triggers gradSlider.on('change')
90872
+ }, btn.style.backgroundColor, () => {
90873
+ btn.removeAttribute('data-focus');
90874
+ btn.focus();
90875
+ }, btn, true); // overlay=true
90439
90876
 
90440
- // this.pickGradient.removeEventListener('keydown', handleKeyDown);
90877
+ btn.setAttribute('data-focus', true);
90878
+ });
90879
+ });
90880
+ const btnRemove = divSort.querySelectorAll('.btn-remove');
90881
+ btnRemove.forEach((btn, index) => {
90882
+ btn.addEventListener('click', e => {
90883
+ this.builder.uo.saveForUndo();
90884
+ const allow = this.allowRemoveStop();
90885
+ if (allow) {
90886
+ btn.parentNode.remove();
90887
+ this.colorsPosArray.splice(index, 1);
90888
+ this.renderColorStops(); // a must
90441
90889
 
90442
- // if(this.original === this.targetElement.style.backgroundImage) {
90443
- // // no change
90444
- // if(this.opts.onFinish) {
90445
- // this.opts.onFinish(false);
90446
- // }
90447
- // } else {
90448
- // // changed
90449
- // if(this.opts.onFinish) {
90450
- // this.opts.onFinish(true);
90451
- // }
90452
- // }
90890
+ this.gradSlider.removeColor(index);
90891
+ }
90892
+ e.preventDefault();
90893
+ e.stopImmediatePropagation();
90894
+ });
90895
+ });
90896
+ }
90897
+ renderColorPositions() {
90898
+ this.gradSlider.draw(this.colorsPosArray);
90899
+ }
90900
+ renderAngle() {
90901
+ const inpAngle = this.pickGradient.querySelector('.inp-angle');
90902
+ inpAngle.value = this.angle;
90903
+ if (this.slider.created) this.slider.setValue(this.angle, true); // use only after slider.create()
90904
+ // true = no trigger only for setting angle position
90905
+ }
90906
+
90907
+ open(elm, onChange, onFinish, btn, overlay) {
90908
+ // Pop Stuff first
90453
90909
 
90454
- // }, false);
90455
90910
  if (!btn) {
90456
90911
  const iframes = document.getElementsByTagName('iframe');
90457
90912
  for (let i = 0; i < iframes.length; i++) {
@@ -90468,7 +90923,7 @@ class GradientPicker {
90468
90923
  if (!btn) btn = document.activeElement;
90469
90924
  }
90470
90925
  let popGradient = this.pickGradient;
90471
- this.builder.util.showPop(popGradient, false, btn, overlay);
90926
+ this.builder.util.showPop(popGradient, onFinish, btn, overlay);
90472
90927
  const w = popGradient.offsetWidth;
90473
90928
  const h = popGradient.offsetHeight;
90474
90929
  const newPos = this.getElementPosition(btn);
@@ -90539,29 +90994,126 @@ class GradientPicker {
90539
90994
  };
90540
90995
  doc.addEventListener('click', handlePopClickOut);
90541
90996
  }
90542
- this.pickGradient.addEventListener('keydown', handleKeyDown);
90543
90997
 
90544
- // const btn = this.pickGradient.querySelector('button');
90545
- // btn.focus();
90998
+ // Gradient Stuff
90999
+
91000
+ this.element = elm;
91001
+ this.btn = btn;
91002
+ this.onChange = onChange;
91003
+ // this.onFinish = onFinish; // used in showPop below
91004
+
91005
+ let cssGradient = elm.style.backgroundImage;
91006
+ if (!cssGradient) {
91007
+ this.angle = 0;
91008
+ this.renderAngle();
91009
+ this.colorsPosArray = [{
91010
+ color: 'rgba(255, 255, 255, 1)',
91011
+ position: 0
91012
+ }, {
91013
+ color: 'rgba(255, 255, 255, 1)',
91014
+ position: 100
91015
+ }];
91016
+ this.renderColorPositions();
91017
+ this.renderColorStops();
91018
+ } else {
91019
+ const angle = this.extractAngle(cssGradient);
91020
+ this.angle = angle;
91021
+ this.renderAngle();
91022
+ const colorsPosArray = this.extractColorsPos(cssGradient);
91023
+ this.colorsPosArray = colorsPosArray;
91024
+ this.renderColorPositions();
91025
+ this.renderColorStops();
91026
+ }
91027
+ setTimeout(() => {
91028
+ this.slider.create();
91029
+ }, 0);
90546
91030
  }
91031
+ extractColorsPos(gradientString) {
91032
+ // Regular expression to match rgb(a) colors and hex colors (with optional alpha) and their positions
91033
+ const colorPositionRegex = /((rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*\d*\.?\d+\s*)?\)|#[0-9a-fA-F]{6}([0-9a-fA-F]{2})?))(?:\s+(\d+)%\s*)?/g;
91034
+ const matches = [...gradientString.matchAll(colorPositionRegex)];
91035
+ let colorsWithPositions = matches.map(match => ({
91036
+ color: match[1],
91037
+ // The color value
91038
+ position: match[5] ? parseInt(match[5], 10) : undefined // The position, if present
91039
+ }));
90547
91040
 
90548
- addClass(element, classname) {
90549
- if (!element) return;
90550
- if (this.hasClass(element, classname)) return;
90551
- if (element.classList.length === 0) element.className = classname;else element.className = element.className + ' ' + classname;
90552
- //else element.classList.add(classname); //error if there is -
91041
+ // Additional operation to correctly parse positions
91042
+ const positionMatches = [...gradientString.matchAll(/\d+\.?\d*%/g)].map(match => parseFloat(match[0]));
91043
+ positionMatches.forEach((position, index) => {
91044
+ if (colorsWithPositions[index]) {
91045
+ colorsWithPositions[index].position = position;
91046
+ }
91047
+ });
91048
+
91049
+ // For gradients without explicit positions, we'll distribute positions evenly
91050
+ if (colorsWithPositions.some(c => c.position === undefined)) {
91051
+ const step = 100 / (colorsWithPositions.length - 1);
91052
+ colorsWithPositions.forEach((c, i) => c.position = i * step);
91053
+ }
91054
+ return colorsWithPositions;
91055
+ }
91056
+ extractAngle(gradientString) {
91057
+ const anglePattern = /linear-gradient\((\d+)deg,/;
91058
+ const match = anglePattern.exec(gradientString);
91059
+ if (match && match[1]) {
91060
+ return parseInt(match[1], 10);
91061
+ } else {
91062
+ return 0;
91063
+ }
90553
91064
  }
90554
91065
 
90555
- removeClass(element, classname) {
90556
- if (!element) return;
90557
- if (element.classList.length > 0) {
90558
- element.className = element.className.replace(classname, '');
91066
+ // Utils
91067
+
91068
+ removeItemByIndex(arr, index) {
91069
+ if (index > -1 && index < arr.length) {
91070
+ arr.splice(index, 1);
90559
91071
  }
91072
+ return arr;
90560
91073
  }
90561
- hasClass(element, classname) {
90562
- if (!element) return false;
90563
- return element.classList ? element.classList.contains(classname) : new RegExp('\\b' + classname + '\\b').test(element.className);
91074
+ allowRemoveStop() {
91075
+ const divSort = this.pickGradient.querySelector('.div-sort');
91076
+ const btns = divSort.querySelectorAll('button[data-color]');
91077
+ if (btns.length === 2) {
91078
+ return false;
91079
+ } else {
91080
+ return true;
91081
+ }
91082
+ }
91083
+ convertColorsToGradient(colorsArray, deg = 0) {
91084
+ let gradientString = `linear-gradient(${deg}deg, `;
91085
+ colorsArray.forEach((color, index) => {
91086
+ gradientString += color;
91087
+ if (index < colorsArray.length - 1) {
91088
+ gradientString += ', ';
91089
+ }
91090
+ });
91091
+ gradientString += ')';
91092
+ return gradientString;
91093
+ }
91094
+ constructGradientString(points, angle) {
91095
+ const gradientParts = points.map(color => `${color.color} ${color.position}%`);
91096
+ if (angle) {
91097
+ return `linear-gradient(${angle}deg, ${gradientParts.join(', ')})`;
91098
+ } else {
91099
+ return `linear-gradient(${this.angle}deg, ${gradientParts.join(', ')})`;
91100
+ }
91101
+ }
91102
+ areArraysIdentical(arr1, arr2) {
91103
+ if (arr1.length !== arr2.length) {
91104
+ return false; // Arrays of different lengths cannot be identical
91105
+ }
91106
+
91107
+ for (let i = 0; i < arr1.length; i++) {
91108
+ if (arr1[i] !== arr2[i]) {
91109
+ return false; // Found elements that are not the same
91110
+ }
91111
+ }
91112
+
91113
+ return true; // All elements are the same and in the same order
90564
91114
  }
91115
+
91116
+ // Pop stuff
90565
91117
  getElementPosition(element) {
90566
91118
  const top = element.getBoundingClientRect().top;
90567
91119
  const left = element.getBoundingClientRect().left;
@@ -90586,156 +91138,6 @@ class GradientPicker {
90586
91138
  }
90587
91139
  }
90588
91140
 
90589
- // source: http://stackoverflow.com/questions/1349404/generate-a-string-of-5-random-characters-in-javascript
90590
- function makeid() {
90591
- let text = '';
90592
- let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
90593
- for (let i = 0; i < 2; i++) text += possible.charAt(Math.floor(Math.random() * possible.length));
90594
- let text2 = '';
90595
- let possible2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
90596
- for (let i = 0; i < 5; i++) text2 += possible2.charAt(Math.floor(Math.random() * possible2.length));
90597
- return text + text2;
90598
- }
90599
-
90600
- // source: https://stackoverflow.com/questions/20215440/parse-css-gradient-rule-with-javascript-regex
90601
- function getGradient(input) {
90602
- var result,
90603
- regExpLib = generateRegExp(),
90604
- //rGradientEnclosedInBrackets = /.*gradient\s*\(((?:\([^\)]*\)|[^\)\(]*)*)\)/,// Captures inside brackets - max one additional inner set.
90605
- rGradientEnclosedInBrackets = /.*gradient\s*\(((?:\([^)]*\)|[^)(]*)*)\)/,
90606
- // Oct 29, 2019
90607
- match = rGradientEnclosedInBrackets.exec(input);
90608
- if (match !== null) {
90609
- // Get the parameters for the gradient
90610
- result = parseGradient(regExpLib, match[1]);
90611
- if (result.original.trim() !== match[1].trim()) {
90612
- // Did not match the input exactly - possible parsing error.
90613
- result.parseWarning = true;
90614
- }
90615
- } else {
90616
- result = 'Failed to find gradient';
90617
- }
90618
- return result;
90619
- }
90620
- var combineRegExp = function (regexpList, flags) {
90621
- var i,
90622
- source = '';
90623
- for (i = 0; i < regexpList.length; i++) {
90624
- if (typeof regexpList[i] === 'string') {
90625
- source += regexpList[i];
90626
- } else {
90627
- source += regexpList[i].source;
90628
- }
90629
- }
90630
- return new RegExp(source, flags);
90631
- };
90632
- var generateRegExp = function () {
90633
- // Note any variables with "Capture" in name include capturing bracket set(s).
90634
- var searchFlags = 'gi',
90635
- // ignore case for angles, "rgb" etc
90636
- rAngle = /(?:[+-]?\d*\.?\d+)(?:deg|grad|rad|turn)/,
90637
- // Angle +ive, -ive and angle types
90638
- rSideCornerCapture = /to\s+((?:(?:left|right)(?:\s+(?:top|bottom))?))/,
90639
- // optional 2nd part
90640
- rComma = /\s*,\s*/,
90641
- // Allow space around comma.
90642
- //rColorHex = /\#(?:[a-f0-9]{6}|[a-f0-9]{3})/, // 3 or 6 character form
90643
- rColorHex = /#(?:[a-f0-9]{6}|[a-f0-9]{3})/,
90644
- // 3 or 6 character form // Oct 29, 2019
90645
- rDigits3 = /\(\s*(?:\d{1,3}\s*,\s*){2}\d{1,3}\s*\)/,
90646
- // "(1, 2, 3)"
90647
- rDigits4 = /\(\s*(?:\d{1,3}\s*,\s*){2}\d{1,3}\s*,\s*\d*\.?\d+\)/,
90648
- // "(1, 2, 3, 4)"
90649
- rValue = /(?:[+-]?\d*\.?\d+)(?:%|[a-z]+)?/,
90650
- // ".9", "-5px", "100%".
90651
- rKeyword = /[_a-z-][_a-z0-9-]*/,
90652
- // "red", "transparent", "border-collapse".
90653
- rColor = combineRegExp(['(?:', rColorHex, '|', '(?:rgb|hsl)', rDigits3, '|', '(?:rgba|hsla)', rDigits4, '|', rKeyword, ')'], ''),
90654
- rColorStop = combineRegExp([rColor, '(?:\\s+', rValue, '(?:\\s+', rValue, ')?)?'], ''),
90655
- // Single Color Stop, optional %, optional length.
90656
- rColorStopList = combineRegExp(['(?:', rColorStop, rComma, ')*', rColorStop], ''),
90657
- // List of color stops min 1.
90658
- rLineCapture = combineRegExp(['(?:(', rAngle, ')|', rSideCornerCapture, ')'], ''),
90659
- // Angle or SideCorner
90660
- rGradientSearch = combineRegExp(['(?:(', rLineCapture, ')', rComma, ')?(', rColorStopList, ')'], searchFlags),
90661
- // Capture 1:"line", 2:"angle" (optional), 3:"side corner" (optional) and 4:"stop list".
90662
- rColorStopSearch = combineRegExp(['\\s*(', rColor, ')', '(?:\\s+', '(', rValue, '))?', '(?:', rComma, '\\s*)?'], searchFlags); // Capture 1:"color" and 2:"position" (optional).
90663
-
90664
- return {
90665
- gradientSearch: rGradientSearch,
90666
- colorStopSearch: rColorStopSearch
90667
- };
90668
- };
90669
- var parseGradient = function (regExpLib, input) {
90670
- var result, matchGradient, matchColorStop, stopResult;
90671
-
90672
- // reset search position, because we reuse regex.
90673
- regExpLib.gradientSearch.lastIndex = 0;
90674
- matchGradient = regExpLib.gradientSearch.exec(input);
90675
- if (matchGradient !== null) {
90676
- result = {
90677
- original: matchGradient[0],
90678
- colorStopList: []
90679
- };
90680
-
90681
- // // Line (Angle or Side-Corner).
90682
- // if (!!matchGradient[1]) {
90683
- // result.line = matchGradient[1];
90684
- // }
90685
- // // Angle or undefined if side-corner.
90686
- // if (!!matchGradient[2]) {
90687
- // result.angle = matchGradient[2];
90688
- // }
90689
- // // Side-corner or undefined if angle.
90690
- // if (!!matchGradient[3]) {
90691
- // result.sideCorner = matchGradient[3];
90692
- // }
90693
-
90694
- // Oct 29, 2019
90695
- // Line (Angle or Side-Corner).
90696
- if (matchGradient[1]) {
90697
- result.line = matchGradient[1];
90698
- }
90699
- // Angle or undefined if side-corner.
90700
- if (matchGradient[2]) {
90701
- result.angle = matchGradient[2];
90702
- }
90703
- // Side-corner or undefined if angle.
90704
- if (matchGradient[3]) {
90705
- result.sideCorner = matchGradient[3];
90706
- }
90707
-
90708
- // reset search position, because we reuse regex.
90709
- regExpLib.colorStopSearch.lastIndex = 0;
90710
-
90711
- // Loop though all the color-stops.
90712
- matchColorStop = regExpLib.colorStopSearch.exec(matchGradient[4]);
90713
- while (matchColorStop !== null) {
90714
- stopResult = {
90715
- color: matchColorStop[1]
90716
- };
90717
-
90718
- // // Position (optional).
90719
- // if (!!matchColorStop[2]) {
90720
- // stopResult.position = matchColorStop[2];
90721
- // }
90722
-
90723
- // Oct 29, 2019
90724
- // Position (optional).
90725
- if (matchColorStop[2]) {
90726
- stopResult.position = matchColorStop[2];
90727
- }
90728
- result.colorStopList.push(stopResult);
90729
-
90730
- // Continue searching from previous position.
90731
- matchColorStop = regExpLib.colorStopSearch.exec(matchGradient[4]);
90732
- }
90733
- }
90734
-
90735
- // Can be undefined if match not found.
90736
- return result;
90737
- };
90738
-
90739
91141
  const fontList = [{
90740
91142
  value: '',
90741
91143
  label: '',
@@ -100569,10 +100971,21 @@ function injectAssets(url, waitFor, callback) {
100569
100971
  };
100570
100972
  document.body.appendChild(script);
100571
100973
  }
100974
+
100975
+ // Modified:
100572
100976
  function isMobile$1() {
100977
+ if (typeof window === "undefined") {
100978
+ // This means we're on the server, return false or handle appropriately
100979
+ return false;
100980
+ }
100573
100981
  return 'navigator' in window && window.navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(Android)|(PlayBook)|(BB10)|(BlackBerry)|(Opera Mini)|(IEMobile)|(webOS)|(MeeGo)/i);
100574
100982
  }
100983
+ // Modified:
100575
100984
  function isTouch$1() {
100985
+ if (typeof document === "undefined") {
100986
+ // This means we're on the server, return false or handle appropriately
100987
+ return false;
100988
+ }
100576
100989
  return isMobile$1() !== null || document.createTouch !== undefined || 'ontouchstart' in window || 'onmsgesturechange' in window || navigator.msMaxTouchPoints;
100577
100990
  }
100578
100991
  function isFunction(f) {
@@ -102242,7 +102655,13 @@ class Slide {
102242
102655
  const version$3 = '3.2.0';
102243
102656
  const isMobile = isMobile$1();
102244
102657
  const isTouch = isTouch$1();
102245
- const html$2 = document.getElementsByTagName('html')[0];
102658
+
102659
+ // Modified:
102660
+ // let html = document.getElementsByTagName('html')[0];
102661
+ let html$2;
102662
+ if (typeof document === "undefined") ; else {
102663
+ html$2 = document.getElementsByTagName('html')[0];
102664
+ }
102246
102665
  const defaults$2 = {
102247
102666
  selector: '.glightbox',
102248
102667
  elements: null,
@@ -107908,6 +108327,10 @@ class Dictation {
107908
108327
  this.builderStuff = builderStuff;
107909
108328
  const util = this.builder.util;
107910
108329
  this.util = util;
108330
+ let disclaimerText = util.out('AI-Disclaimer');
108331
+ if (disclaimerText === 'AI-Disclaimer') {
108332
+ disclaimerText = this.builder.disclaimerAI;
108333
+ }
107911
108334
 
107912
108335
  // const dom = this.builder.dom;
107913
108336
 
@@ -108117,7 +108540,7 @@ class Dictation {
108117
108540
  ${util.out('AI-Powered Features')}
108118
108541
  <button class="is-modal-close" tabindex="-1" title="${util.out('Close')}">&#10005;</button>
108119
108542
  </div>
108120
- ${util.out('AI-Disclaimer', this.builder.disclaimerAI)}
108543
+ ${disclaimerText}
108121
108544
  <div style="text-align:right;margin-top:20px;">
108122
108545
  <button title="${util.out('Ok')}" class="input-ok classic-primary" style="width:100%;text-transform: uppercase;
108123
108546
  font-size: 14px;">${util.out('Ok')}</button>
@@ -110822,22 +111245,25 @@ class Command$1 {
110822
111245
  const builderStuff = this.builder.builderStuff;
110823
111246
  this.builderStuff = builderStuff;
110824
111247
  this.lib = new Lib$1(builder);
110825
- let html = `
110826
- <div class="is-modal ai-disclaimer" style="z-index:10005" tabindex="-1" role="dialog" aria-modal="true" aria-hidden="true">
110827
- <div class="is-modal-content" style="max-width:450px;padding:55px 40px 35px;font-size:16px;line-height:1.4;letter-spacing: 1px;">
110828
- <div class="is-modal-bar is-draggable">
110829
- ${util.out('AI-Powered Features')}
110830
- <button class="is-modal-close" tabindex="-1" title="${util.out('Close')}">&#10005;</button>
110831
- </div>
110832
- ${util.out('AI-Disclaimer', this.builder.disclaimerAI)}
110833
- <div style="text-align:right;margin-top:20px;">
110834
- <button title="${util.out('Ok')}" class="input-ok classic-primary" style="width:100%;text-transform: uppercase;
110835
- font-size: 14px;">${util.out('Ok')}</button>
110836
- </div>
110837
- </div>
110838
- </div>`;
110839
- builderStuff.insertAdjacentHTML('beforeend', html);
110840
- this.modalDisclaimer = builderStuff.querySelector('.ai-disclaimer');
111248
+ let html = '';
111249
+ // let html = `
111250
+ // <div class="is-modal ai-disclaimer" style="z-index:10005" tabindex="-1" role="dialog" aria-modal="true" aria-hidden="true">
111251
+ // <div class="is-modal-content" style="max-width:450px;padding:55px 40px 35px;font-size:16px;line-height:1.4;letter-spacing: 1px;">
111252
+ // <div class="is-modal-bar is-draggable">
111253
+ // ${util.out('AI-Powered Features')}
111254
+ // <button class="is-modal-close" tabindex="-1" title="${util.out('Close')}">&#10005;</button>
111255
+ // </div>
111256
+ // ${util.out('AI-Disclaimer', this.builder.disclaimerAI)}
111257
+ // <div style="text-align:right;margin-top:20px;">
111258
+ // <button title="${util.out('Ok')}" class="input-ok classic-primary" style="width:100%;text-transform: uppercase;
111259
+ // font-size: 14px;">${util.out('Ok')}</button>
111260
+ // </div>
111261
+ // </div>
111262
+ // </div>`;
111263
+ // builderStuff.insertAdjacentHTML('beforeend', html);
111264
+
111265
+ // this.modalDisclaimer = builderStuff.querySelector('.ai-disclaimer');
111266
+
110841
111267
  let cl = contextBlockList$1;
110842
111268
  if (this.builder.contextList) cl = this.builder.contextList;
110843
111269
  const localProcess = question => {
@@ -117362,7 +117788,9 @@ class ContentBuilder {
117362
117788
  defaultFontSizes: [16, 17, 18, 19, 21, 24, 32, 35, 42, 48, 54, 64 /*, 76, 96, 120, 200, 300*/],
117363
117789
  fontSizeClassValues: [12, 14, 15, 16, 17, 18, 19, 21, 24, 28, 32, 35, 38, 42, 46, 48, 50, 54, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 256, 260, 264, 268, 272, 276, 280, 284, 288, 292, 296, 300, 304, 308, 312, 316, 320, 324, 328, 332, 336, 340, 344, 348, 352, 356, 360, 364, 368, 372, 376, 380, 384, 388, 392, 396, 400],
117364
117790
  /* If not empty, applying font size will apply class: size-12, size-14, and so on. All responsive, defined in content.css */
117365
- gradientcolors: [['linear-gradient(0deg, rgb(255, 57, 25), rgb(249, 168, 37))'], ['linear-gradient(0deg, rgb(255, 57, 25), rgb(255, 104, 15))'], ['linear-gradient(0deg, #FF5722, #FF9800)'], ['linear-gradient(0deg, #613ca2, rgb(110, 123, 217))'], ['linear-gradient(0deg, rgb(65, 70, 206), rgb(236, 78, 130))'], ['linear-gradient(0deg, rgb(0, 150, 102), rgb(90, 103, 197))'], ['linear-gradient(30deg, rgb(249, 119, 148), rgb(98, 58, 162))'], ['linear-gradient(0deg, rgb(223, 70, 137), rgb(90, 103, 197))'], ['linear-gradient(0deg, rgb(40, 53, 147), rgb(90, 103, 197))'], ['linear-gradient(0deg, rgb(21, 101, 192), rgb(52, 169, 239))'], ['linear-gradient(0deg, rgb(32, 149, 219), rgb(139, 109, 230))'], ['linear-gradient(0deg, rgb(90, 103, 197), rgb(0, 184, 201))'], ['linear-gradient(0deg, rgb(0, 184, 201), rgb(253, 187, 45))'], ['linear-gradient(0deg, rgb(255, 208, 100), rgb(239, 98, 159))'], ['linear-gradient(0deg, rgb(0, 214, 223), rgb(130, 162, 253))'], ['linear-gradient(0deg, rgb(50, 234, 251), rgb(248, 247, 126))'], ['linear-gradient(0deg, rgb(141, 221, 255), rgb(255, 227, 255))'], ['linear-gradient(0deg, rgb(255, 170, 170), rgb(255, 255, 200))'], ['linear-gradient(0deg, rgb(239, 239, 239), rgb(252, 252, 252))']],
117791
+ gradientColors: [
117792
+ // 'linear-gradient(234deg, rgba(255, 253, 185, 1), rgb(255, 208, 100), rgb(239, 98, 159), rgb(73, 88, 195), rgba(2, 20, 145, 1))',
117793
+ 'linear-gradient(32deg, rgb(4, 98, 183) 0%, rgb(97, 110, 204) 23.5075%, rgb(246, 108, 168) 50%, rgb(255, 211, 111) 75%, rgb(255, 253, 193) 100%)', 'linear-gradient(15deg, rgba(222, 90, 69, 1), rgba(255, 118, 96, 1), rgba(249, 214, 137, 1), rgba(255, 242, 172, 1))', 'linear-gradient(357deg, rgba(68, 85, 204, 1), rgba(4, 166, 240, 1), rgba(51, 241, 255, 1))', 'linear-gradient(26deg, rgba(41, 145, 255, 1), rgba(49, 103, 240, 1), rgba(67, 107, 208, 1), rgba(149, 115, 255, 1), rgba(159, 159, 255, 1))', 'linear-gradient(0deg, rgba(198, 233, 155, 1), rgba(97, 221, 180, 1), rgba(244, 255, 190, 1))', 'linear-gradient(342deg, rgb(189, 156, 219), rgb(163, 172, 240), rgba(154, 203, 253, 1))', 'linear-gradient(45deg, rgb(255, 225, 172), rgb(253, 194, 141), rgba(246, 150, 183, 1), rgba(221, 140, 207, 1))', 'linear-gradient(0deg, rgba(157, 172, 246, 1), rgba(129, 205, 255, 1), rgba(202, 255, 207, 1))'],
117366
117794
  elementEditor: true,
117367
117795
  customval: '',
117368
117796
  moduleConfig: [],
@@ -118705,13 +119133,7 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
118705
119133
  }, this);
118706
119134
 
118707
119135
  // Gradient Picker
118708
- this.gradpicker = new GradientPicker({
118709
- gradientcolors: this.opts.gradientcolors,
118710
- colors: this.opts.colors,
118711
- animateModal: this.opts.animateModal,
118712
- elementToAnimate: this.opts.container,
118713
- lang: this.opts.lang
118714
- }, this);
119136
+ this.gradpicker = new GradientPicker(this);
118715
119137
 
118716
119138
  // Shortcut Info
118717
119139
  this.ShortcutInfo = new ShortcutInfo(this);
@@ -119264,7 +119686,7 @@ Add an image for each feature.`, 'Create a new content showcasing a photo galler
119264
119686
  dropdown.style.display = 'none';
119265
119687
  });
119266
119688
  }
119267
- const clrPicker = document.querySelector('.pop-picker.active');
119689
+ const clrPicker = document.querySelector('.pop-picker.active') || document.querySelector('.pickgradientcolor.active');
119268
119690
  // if(clrPicker) return;
119269
119691
 
119270
119692
  // Image Resizer
@@ -137445,8 +137867,7 @@ class Box {
137445
137867
  setBoxBgColor(s) {
137446
137868
  const activeBox = this.builder.activeBox;
137447
137869
  let overlay = activeBox.querySelector('.is-overlay');
137448
- overlay.style.backgroundColor = s;
137449
- overlay.style.backgroundImage = ''; // remove gradient
137870
+ overlay.style.backgroundColor = s; // overlay.style.backgroundImage = ''; // remove gradient
137450
137871
  } // Box Size
137451
137872
 
137452
137873