@innovastudio/contentbox 1.6.71 → 1.6.73

Sign up to get free protection for your applications and to get access to all the features.
@@ -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