Q2W3 Fixed Widget - Version 6.0.0-beta-3

Version Description

Version 6.0.0 is a full rewrite of the frontend script. It fixes many edge cases like jumping, reloading, or resizing widgets. The rewrite also resolves bad Cumulative Layout Shifts.

Most changes are available when you switch on "Test new version" under Appearance > Fixed Widget Options.

Please test and let us know if you discover any issues.

  • added new (and optional) script version that uses position: sticky instead of position: fixed
  • the frontend script does not need jQuery anymore
  • removed unneeded options that previously helped resolving edge cases
  • "Stop Elements" and "Custom Fixed Elements" now accept any selector, including IDs, Class, and Type selectors.
  • improved option descriptions on the admin page
  • improved behavior for elements higher than the screen they first stick at the top and scroll to the bottom later
  • removed duplicating widget code
Download this release

Release Info

Developer webzunft
Plugin Icon 128x128 Q2W3 Fixed Widget
Version 6.0.0-beta-3
Comparing to
See all releases

Code changes from version 6.0.0-beta-2 to 6.0.0-beta-3

Files changed (6) hide show
  1. js/backend.asset.php +1 -1
  2. js/backend.js +26 -29
  3. js/frontend.js +141 -113
  4. js/frontend.min.js +1 -1
  5. q2w3-fixed-widget.php +2 -2
  6. readme.txt +22 -19
js/backend.asset.php CHANGED
@@ -1 +1 @@
1
- <?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-compose', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-polyfill'), 'version' => '1dcd7da92f570e27f7433b7d8e719c95');
1
+ <?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-compose', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-polyfill'), 'version' => '006095307ebee232aeda0a37d521a047');
js/backend.js CHANGED
@@ -1386,14 +1386,27 @@ const FixedWidgetBlock = (0,_wordpress_compose__WEBPACK_IMPORTED_MODULE_3__.crea
1386
  if (!(0,_consts__WEBPACK_IMPORTED_MODULE_6__.isFixableWidget)(props.name)) {
1387
  return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(BlockEdit, Object.assign({}, props), void 0);
1388
  }
1389
- const isDynamicWidget = props.name in _consts__WEBPACK_IMPORTED_MODULE_6__.dynamicWidgets;
1390
- return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_wordpress_element__WEBPACK_IMPORTED_MODULE_4__.Fragment, { children: [(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(BlockEdit, Object.assign({}, props), void 0), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.InspectorControls, { children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.PanelBody, Object.assign({ title: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__.__)('Fixed Widget', 'q2w3-fixed-widget'), initialOpen: true }, { children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(WidgetTypeSelector, { selected: isDynamicWidget ? _consts__WEBPACK_IMPORTED_MODULE_6__.dynamicWidgets[props.name] : props.attributes.fixed_widget, onSelect: (fixed_widget) => {
1391
- if (isDynamicWidget) {
1392
- _consts__WEBPACK_IMPORTED_MODULE_6__.dynamicWidgets[props.name] = fixed_widget;
1393
- props.setAttributes({ className: (0,_consts__WEBPACK_IMPORTED_MODULE_6__.assignClassName)(props.attributes.className, fixed_widget) });
1394
- }
1395
- props.setAttributes({ fixed_widget });
1396
- } }, void 0) }), void 0) }, void 0)] }, void 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
1397
  }, 'withInspectorControl');
1398
 
1399
 
@@ -1409,9 +1422,7 @@ __webpack_require__.r(__webpack_exports__);
1409
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1410
  /* harmony export */ "StopWidgetClassName": function() { return /* binding */ StopWidgetClassName; },
1411
  /* harmony export */ "FixedWidgetClassName": function() { return /* binding */ FixedWidgetClassName; },
1412
- /* harmony export */ "dynamicWidgets": function() { return /* binding */ dynamicWidgets; },
1413
  /* harmony export */ "isFixableWidget": function() { return /* binding */ isFixableWidget; },
1414
- /* harmony export */ "isDynamicWidget": function() { return /* binding */ isDynamicWidget; },
1415
  /* harmony export */ "isPluginEnabled": function() { return /* binding */ isPluginEnabled; },
1416
  /* harmony export */ "filterWidgetClassName": function() { return /* binding */ filterWidgetClassName; },
1417
  /* harmony export */ "assignClassName": function() { return /* binding */ assignClassName; }
@@ -1421,25 +1432,11 @@ const FixedWidgetClassName = 'FixedWidget__fixed_widget';
1421
  const unFixableWidgets = {
1422
  'core/legacy-widget': true
1423
  };
1424
- const dynamicWidgets = {};
1425
  /**
1426
  * @param {string} widget - Widget's name
1427
  * @returns {boolean} `true`, if widget is fixable
1428
  */
1429
  const isFixableWidget = (widget) => !(widget in unFixableWidgets);
1430
- /**
1431
- * Dynamic Widgets return null from save method
1432
- * @param w
1433
- * @returns true, if widget is dynamic
1434
- */
1435
- const isDynamicWidget = (w) => {
1436
- try {
1437
- return w.save(w.example) === null;
1438
- }
1439
- catch (_e) {
1440
- return false;
1441
- }
1442
- };
1443
  const availablePages = ['/widgets.php'];
1444
  const isPluginEnabled = (pathname) => availablePages.some((page) => pathname.includes(page));
1445
  /**
@@ -1476,13 +1473,13 @@ const addWidgetTypeAttribute = (settings, name) => {
1476
  if (!(0,_consts__WEBPACK_IMPORTED_MODULE_0__.isFixableWidget)(name)) {
1477
  return settings;
1478
  }
1479
- if ((0,_consts__WEBPACK_IMPORTED_MODULE_0__.isDynamicWidget)(settings)) {
1480
- _consts__WEBPACK_IMPORTED_MODULE_0__.dynamicWidgets[name] = '';
1481
- return settings;
1482
- }
1483
  return Object.assign({}, settings, {
1484
  attributes: Object.assign({}, settings.attributes, {
1485
- fixed_widget: { default: '', type: 'string', },
 
 
 
 
1486
  }),
1487
  });
1488
  };
1386
  if (!(0,_consts__WEBPACK_IMPORTED_MODULE_6__.isFixableWidget)(props.name)) {
1387
  return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(BlockEdit, Object.assign({}, props), void 0);
1388
  }
1389
+ (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_4__.useEffect)(() => {
1390
+ if (!props.attributes.className) {
1391
+ return;
1392
+ }
1393
+ /**
1394
+ * On first render extract fixed_widget attribute from dynamic widget's className
1395
+ */
1396
+ [_consts__WEBPACK_IMPORTED_MODULE_6__.FixedWidgetClassName, _consts__WEBPACK_IMPORTED_MODULE_6__.StopWidgetClassName]
1397
+ .filter((className) => props.attributes.className.includes(className))
1398
+ .forEach(onSelect);
1399
+ }, []);
1400
+ const onSelect = (fixed_widget) => {
1401
+ if (fixed_widget === props.attributes.fixed_widget) {
1402
+ return;
1403
+ }
1404
+ /**
1405
+ * Additionally store fixed_widget attribute as className for dynamic widgets
1406
+ */
1407
+ props.setAttributes({ className: (0,_consts__WEBPACK_IMPORTED_MODULE_6__.assignClassName)(props.attributes.className, fixed_widget), fixed_widget });
1408
+ };
1409
+ return (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(_wordpress_element__WEBPACK_IMPORTED_MODULE_4__.Fragment, { children: [(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(BlockEdit, Object.assign({}, props), void 0), (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.InspectorControls, { children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.PanelBody, Object.assign({ title: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__.__)('Fixed Widget', 'q2w3-fixed-widget'), initialOpen: true }, { children: (0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(WidgetTypeSelector, { selected: props.attributes.fixed_widget, onSelect: onSelect }, void 0) }), void 0) }, void 0)] }, void 0);
1410
  }, 'withInspectorControl');
1411
 
1412
 
1422
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1423
  /* harmony export */ "StopWidgetClassName": function() { return /* binding */ StopWidgetClassName; },
1424
  /* harmony export */ "FixedWidgetClassName": function() { return /* binding */ FixedWidgetClassName; },
 
1425
  /* harmony export */ "isFixableWidget": function() { return /* binding */ isFixableWidget; },
 
1426
  /* harmony export */ "isPluginEnabled": function() { return /* binding */ isPluginEnabled; },
1427
  /* harmony export */ "filterWidgetClassName": function() { return /* binding */ filterWidgetClassName; },
1428
  /* harmony export */ "assignClassName": function() { return /* binding */ assignClassName; }
1432
  const unFixableWidgets = {
1433
  'core/legacy-widget': true
1434
  };
 
1435
  /**
1436
  * @param {string} widget - Widget's name
1437
  * @returns {boolean} `true`, if widget is fixable
1438
  */
1439
  const isFixableWidget = (widget) => !(widget in unFixableWidgets);
 
 
 
 
 
 
 
 
 
 
 
 
 
1440
  const availablePages = ['/widgets.php'];
1441
  const isPluginEnabled = (pathname) => availablePages.some((page) => pathname.includes(page));
1442
  /**
1473
  if (!(0,_consts__WEBPACK_IMPORTED_MODULE_0__.isFixableWidget)(name)) {
1474
  return settings;
1475
  }
 
 
 
 
1476
  return Object.assign({}, settings, {
1477
  attributes: Object.assign({}, settings.attributes, {
1478
+ fixed_widget: {
1479
+ default: '',
1480
+ type: 'string',
1481
+ enum: [_consts__WEBPACK_IMPORTED_MODULE_0__.FixedWidgetClassName, _consts__WEBPACK_IMPORTED_MODULE_0__.StopWidgetClassName, '']
1482
+ },
1483
  }),
1484
  });
1485
  };
js/frontend.js CHANGED
@@ -42,26 +42,12 @@ var __assign = function() {
42
  return __assign.apply(this, arguments);
43
  };
44
 
45
- function __spreadArray(to, from, pack) {
46
- if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
47
- if (ar || !(i in from)) {
48
- if (!ar) ar = Array.prototype.slice.call(from, 0, i);
49
- ar[i] = from[i];
50
- }
51
- }
52
- return to.concat(ar || Array.prototype.slice.call(from));
53
- }
54
-
55
- var queryWidgets = function (container, className) {
56
- return Array.from(container.querySelectorAll("." + className))
57
- .filter(function (el) { return el !== null; });
58
- };
59
-
60
  var Widget = /** @class */ (function () {
61
  function Widget(el) {
62
  this.el = el;
63
  this.top_offset = 0;
64
- /** total offset from current element to root parent */
65
  this.root_offset = 0;
66
  this.need_to_calc_el_offset = function (_) { return false; };
67
  }
@@ -74,24 +60,35 @@ var Widget = /** @class */ (function () {
74
  this.top_offset = this.get_total_top_offset(user_margins);
75
  this.root_offset = get_root_offset(this.el, document.body);
76
  };
77
- Widget.prototype.getSidebar = function () {
78
- return this.el && this.el.parentElement;
 
 
 
 
79
  };
80
  Widget.prototype.get_total_top_offset = function (margins) {
81
  var next = function (el) { return el && el.previousElementSibling; };
82
  return get_sibilings_offset(next, this.need_to_calc_el_offset, next(this.el), margins.margin_top);
83
  };
84
- Widget.queryAll = function () {
85
- var _this = this;
86
  return []
87
- .concat(Array.from(document.querySelectorAll("." + this.CLASSNAME)), Array.from(document.querySelectorAll("[data-fixed_widget=" + this.CLASSNAME)))
88
  .map(function (el) {
89
- el.classList.remove(_this.CLASSNAME);
90
  el.removeAttribute('data-fixed_widget');
91
- return new _this(getWidgetContainer(el));
 
 
 
92
  });
93
  };
94
- Widget.CLASSNAME = 'FixedWidget__';
 
 
 
 
 
95
  return Widget;
96
  }());
97
  var getWidgetContainer = function (el) {
@@ -100,8 +97,42 @@ var getWidgetContainer = function (el) {
100
  * Group can contain multiple children, but this is one Widget,
101
  */
102
  el.parentElement.classList.toString().includes('wp-block-group') ||
 
103
  el.parentElement.classList.contains('widget')) ? getWidgetContainer(el.parentElement) : el;
104
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  var PositionWidget = /** @class */ (function (_super) {
106
  __extends(PositionWidget, _super);
107
  function PositionWidget() {
@@ -112,7 +143,6 @@ var PositionWidget = /** @class */ (function (_super) {
112
  _this.max_top_offset = 0;
113
  _this.bottom_margin = 0;
114
  _this.user_margins = {};
115
- _this.prevScrollTop = 0;
116
  return _this;
117
  }
118
  PositionWidget.prototype.mount = function (user_margins, layer, max_top_offset) {
@@ -125,56 +155,28 @@ var PositionWidget = /** @class */ (function (_super) {
125
  this.bottom_margin = parseInt(marginBottom);
126
  this.top_margin = parseInt(marginTop);
127
  this.bottom_offset = this.get_total_bottom_offset(user_margins);
128
- this.max_top_offset = max_top_offset;
 
 
 
129
  };
130
  PositionWidget.prototype.render = function () {
131
  if (!this.el || !this.el.parentElement) {
132
  return;
133
  }
134
  var scrollTop = document.documentElement.scrollTop;
135
- this.prevScrollTop = scrollTop;
136
  this.onScroll(scrollTop);
137
  };
 
 
 
138
  PositionWidget.prototype.onScroll = function (_scrollTop) { };
139
  PositionWidget.prototype.get_total_bottom_offset = function (margins) {
140
- var next = function (el) { return el && el.nextElementSibling; };
141
  return get_sibilings_offset(next, this.need_to_calc_el_offset, next(this.el), margins.margin_bottom);
142
  };
143
- PositionWidget.CLASSNAME = 'FixedWidget__fixed_widget';
144
  return PositionWidget;
145
  }(Widget));
146
- /**
147
- * Calc total offset of all fixed/sticked sibislings
148
- * @param next
149
- * @param el
150
- * @param offset
151
- * @returns
152
- */
153
- var get_sibilings_offset = function (next, need_to_calc_el_offset, el, offset) {
154
- if (offset === void 0) { offset = 0; }
155
- if (!el) {
156
- return offset;
157
- }
158
- if (!need_to_calc_el_offset(el)) {
159
- return get_sibilings_offset(next, need_to_calc_el_offset, next(el), offset);
160
- }
161
- var _a = getComputedStyle(el), marginTop = _a.marginTop, marginBottom = _a.marginBottom;
162
- return get_sibilings_offset(next, need_to_calc_el_offset, next(el), offset + el.offsetHeight + parseInt(marginTop || '0') + parseInt(marginBottom || '0'));
163
- };
164
- /**
165
- * Calc total offset from current element to root parent
166
- * @param el
167
- * @param top_parent
168
- * @param offset
169
- * @returns
170
- */
171
- var get_root_offset = function (el, top_parent, offset) {
172
- if (offset === void 0) { offset = 0; }
173
- if (!el || el === top_parent) {
174
- return offset;
175
- }
176
- return offset + get_root_offset(el.offsetParent, top_parent, el.offsetTop);
177
- };
178
 
179
  var FixedWidget = /** @class */ (function (_super) {
180
  __extends(FixedWidget, _super);
@@ -184,12 +186,12 @@ var FixedWidget = /** @class */ (function (_super) {
184
  _this.relative_top = 0;
185
  _this.init_style = { position: 'static', top: '', bottom: '', width: '', height: '' };
186
  _this.need_to_calc_el_offset = function (el) {
187
- return el.classList.contains(FixedWidget.CLASSNAME);
188
  };
189
  if (!_this.el || !_this.el.parentElement) {
190
  return _this;
191
  }
192
- _this.el.classList.add(FixedWidget.CLASSNAME);
193
  return _this;
194
  }
195
  FixedWidget.prototype.mount = function (margins, layer, max_top_offset) {
@@ -273,33 +275,11 @@ var FixedWidget = /** @class */ (function (_super) {
273
  };
274
  FixedWidget.is = function (selector) {
275
  var el = document.querySelector(selector);
276
- return !!el && el.classList.contains(FixedWidget.CLASSNAME);
277
  };
278
  return FixedWidget;
279
  }(PositionWidget));
280
 
281
- var StopWidget = /** @class */ (function (_super) {
282
- __extends(StopWidget, _super);
283
- function StopWidget(el) {
284
- var _this = _super.call(this, el) || this;
285
- _this.need_to_calc_el_offset = function () { return true; };
286
- if (!_this.el || !_this.el.parentElement) {
287
- return _this;
288
- }
289
- _this.el.classList.add(StopWidget.CLASSNAME);
290
- return _this;
291
- }
292
- StopWidget.new = function (selector) {
293
- return new StopWidget(document.querySelector(selector));
294
- };
295
- StopWidget.is = function (selector) {
296
- var el = document.querySelector(selector);
297
- return !!el && el.classList.contains(StopWidget.CLASSNAME);
298
- };
299
- StopWidget.CLASSNAME = 'FixedWidget__stop_widget';
300
- return StopWidget;
301
- }(Widget));
302
-
303
  var StickyWidget = /** @class */ (function (_super) {
304
  __extends(StickyWidget, _super);
305
  function StickyWidget(el) {
@@ -307,13 +287,12 @@ var StickyWidget = /** @class */ (function (_super) {
307
  _this.margins = 0;
308
  _this.borderBox = 0; /** cleintHeight+ top & bottom margins */
309
  _this.need_to_calc_el_offset = function (el) {
310
- return el.classList.contains(StickyWidget.CLASSNAME) ||
311
- el.classList.contains(StopWidget.CLASSNAME);
312
  };
313
  if (!_this.el || !_this.el.parentElement) {
314
  return _this;
315
  }
316
- _this.el.classList.add(StickyWidget.CLASSNAME);
317
  return _this;
318
  }
319
  StickyWidget.prototype.mount = function (margins, layer, max_top_offset) {
@@ -341,53 +320,89 @@ var StickyWidget = /** @class */ (function (_super) {
341
  }
342
  this.el.style.transform = "translateY(" + (bottom_margin - this.bottom_offset) + "px)";
343
  };
 
344
  StickyWidget.new = function (selector) {
345
  return new StickyWidget(document.querySelector(selector));
346
  };
347
  StickyWidget.is = function (selector) {
348
  var el = document.querySelector(selector);
349
- return !!el && el.classList.contains(StickyWidget.CLASSNAME);
350
  };
351
  return StickyWidget;
352
  }(PositionWidget));
353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  var initSidebars = function (options) {
355
- var WidgetContructor = typeof options.use_sticky_position === 'undefined' || options.use_sticky_position ? StickyWidget : FixedWidget;
356
- var sticky_widgets = WidgetContructor.queryAll() // widgets by classNames from editor's plugin
357
- .concat((options.widgets || []) // widgets from option's custom selectors
358
- .filter(Boolean)
359
- .map(WidgetContructor.new));
360
- var stop_widgets = StopWidget.queryAll() // widgets by classNames from editor's plugin;
361
- .concat((options.stop_elements_selectors || '') // widgets from option's custom selectors
362
- .split('/n')
363
- .filter(Boolean)
364
- .map(StopWidget.new));
365
- var sidebars = create_sidebars(__spreadArray(__spreadArray([], sticky_widgets, true), stop_widgets, true), options);
 
 
 
 
 
 
 
366
  sidebars.forEach(function (sidebar) { sidebar.mount(); });
367
  document.addEventListener('scroll', function () {
368
  sidebars.forEach(function (sidebar) { return sidebar.render(); });
369
  });
370
  };
371
- var create_sidebars = function (widgets, options) {
372
- return Array.from(new Set(widgets.map(function (widget) { return widget.getSidebar(); })))
373
- .filter(function (sidebar_el) { return sidebar_el !== null; })
374
- .map(function (sidebar_el) {
375
- return new Sidebar(sidebar_el, options, typeof options.use_sticky_position === 'undefined' || options.use_sticky_position);
376
- });
377
- };
378
  var Sidebar = /** @class */ (function () {
379
  function Sidebar(el, margins, use_sticky_position) {
380
  this.el = el;
381
  this.margins = margins;
382
  this.use_sticky_position = use_sticky_position;
383
- this.not_widgets = [];
384
  this.widgets = [];
385
  this.stop_widgets = [];
386
  this.min_top_offset = 0;
387
- this.stop_widgets = queryWidgets(this.el, StopWidget.CLASSNAME).map(function (el) { return new StopWidget(el); });
388
- this.not_widgets = Array.from(this.el.querySelectorAll(".widget:not(." + StickyWidget.CLASSNAME + ",." + StopWidget.CLASSNAME + ")"));
389
  var WidgetContructor = typeof use_sticky_position === 'undefined' || use_sticky_position ? StickyWidget : FixedWidget;
390
- this.widgets = queryWidgets(this.el, WidgetContructor.CLASSNAME).map(function (el) { return new WidgetContructor(el); });
391
  if (!use_sticky_position) {
392
  return;
393
  }
@@ -395,7 +410,7 @@ var Sidebar = /** @class */ (function () {
395
  if (this.stop_widgets.length !== 0) {
396
  return;
397
  }
398
- this.el.style.height = '100%';
399
  }
400
  Sidebar.prototype.mount = function () {
401
  var _this = this;
@@ -409,8 +424,21 @@ var Sidebar = /** @class */ (function () {
409
  Sidebar.prototype.render = function () {
410
  this.widgets.forEach(function (widget) { return widget.render(); });
411
  };
 
 
 
 
 
 
 
412
  return Sidebar;
413
  }());
 
 
 
 
 
 
414
 
415
  var initPlugin = function (options) {
416
  if (options === void 0) { options = []; }
42
  return __assign.apply(this, arguments);
43
  };
44
 
45
+ var StopWidgetClassName = 'FixedWidget__stop_widget';
46
+ var FixedWidgetClassName = 'FixedWidget__fixed_widget';
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  var Widget = /** @class */ (function () {
48
  function Widget(el) {
49
  this.el = el;
50
  this.top_offset = 0;
 
51
  this.root_offset = 0;
52
  this.need_to_calc_el_offset = function (_) { return false; };
53
  }
60
  this.top_offset = this.get_total_top_offset(user_margins);
61
  this.root_offset = get_root_offset(this.el, document.body);
62
  };
63
+ Widget.prototype.getElement = function () {
64
+ return this.el;
65
+ };
66
+ Widget.prototype.toString = function () {
67
+ var _a;
68
+ return "" + ((_a = this.el) === null || _a === void 0 ? void 0 : _a.innerHTML);
69
  };
70
  Widget.prototype.get_total_top_offset = function (margins) {
71
  var next = function (el) { return el && el.previousElementSibling; };
72
  return get_sibilings_offset(next, this.need_to_calc_el_offset, next(this.el), margins.margin_top);
73
  };
74
+ Widget.queryAllWidgetsContainers = function (className) {
 
75
  return []
76
+ .concat(Array.from(document.querySelectorAll("." + className)), Array.from(document.querySelectorAll("[data-fixed_widget=" + className)))
77
  .map(function (el) {
78
+ el.classList.remove(className);
79
  el.removeAttribute('data-fixed_widget');
80
+ var container = getWidgetContainer(el);
81
+ container.classList.remove(FixedWidgetClassName);
82
+ container.classList.remove(StopWidgetClassName);
83
+ return container;
84
  });
85
  };
86
+ Widget.from = function (root, className) {
87
+ var _this = this;
88
+ return Array.from(root.querySelectorAll("." + className))
89
+ .filter(function (el) { return el !== null; })
90
+ .map(function (e) { return new _this(e); });
91
+ };
92
  return Widget;
93
  }());
94
  var getWidgetContainer = function (el) {
97
  * Group can contain multiple children, but this is one Widget,
98
  */
99
  el.parentElement.classList.toString().includes('wp-block-group') ||
100
+ el.parentElement.classList.toString().includes('wp-block-column') ||
101
  el.parentElement.classList.contains('widget')) ? getWidgetContainer(el.parentElement) : el;
102
  };
103
+ /**
104
+ * Calc total offset of all fixed/sticked sibislings
105
+ * @param next
106
+ * @param el
107
+ * @param offset
108
+ * @returns
109
+ */
110
+ var get_sibilings_offset = function (next, need_to_calc_el_offset, el, offset) {
111
+ if (offset === void 0) { offset = 0; }
112
+ if (!el) {
113
+ return offset;
114
+ }
115
+ if (!need_to_calc_el_offset(el)) {
116
+ return get_sibilings_offset(next, need_to_calc_el_offset, next(el), offset);
117
+ }
118
+ var _a = getComputedStyle(el), marginTop = _a.marginTop, marginBottom = _a.marginBottom;
119
+ return get_sibilings_offset(next, need_to_calc_el_offset, next(el), offset + el.offsetHeight + parseInt(marginTop || '0') + parseInt(marginBottom || '0'));
120
+ };
121
+ /**
122
+ * Calc total offset from current element to root parent
123
+ * @param el
124
+ * @param top_parent
125
+ * @param offset
126
+ * @returns
127
+ */
128
+ var get_root_offset = function (el, top_parent, offset) {
129
+ if (offset === void 0) { offset = 0; }
130
+ if (!el || el === top_parent) {
131
+ return offset;
132
+ }
133
+ return offset + get_root_offset(el.offsetParent, top_parent, el.offsetTop);
134
+ };
135
+
136
  var PositionWidget = /** @class */ (function (_super) {
137
  __extends(PositionWidget, _super);
138
  function PositionWidget() {
143
  _this.max_top_offset = 0;
144
  _this.bottom_margin = 0;
145
  _this.user_margins = {};
 
146
  return _this;
147
  }
148
  PositionWidget.prototype.mount = function (user_margins, layer, max_top_offset) {
155
  this.bottom_margin = parseInt(marginBottom);
156
  this.top_margin = parseInt(marginTop);
157
  this.bottom_offset = this.get_total_bottom_offset(user_margins);
158
+ /** StopWidget can limit top offset if it is placed only after widget*/
159
+ if (max_top_offset > this.el.offsetTop) {
160
+ this.max_top_offset = max_top_offset;
161
+ }
162
  };
163
  PositionWidget.prototype.render = function () {
164
  if (!this.el || !this.el.parentElement) {
165
  return;
166
  }
167
  var scrollTop = document.documentElement.scrollTop;
 
168
  this.onScroll(scrollTop);
169
  };
170
+ PositionWidget.from = function (root) {
171
+ return _super.from.call(this, root, FixedWidgetClassName);
172
+ };
173
  PositionWidget.prototype.onScroll = function (_scrollTop) { };
174
  PositionWidget.prototype.get_total_bottom_offset = function (margins) {
175
+ var next = function (el) { return el && !el.classList.contains(StopWidgetClassName) ? el.nextElementSibling : null; };
176
  return get_sibilings_offset(next, this.need_to_calc_el_offset, next(this.el), margins.margin_bottom);
177
  };
 
178
  return PositionWidget;
179
  }(Widget));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
  var FixedWidget = /** @class */ (function (_super) {
182
  __extends(FixedWidget, _super);
186
  _this.relative_top = 0;
187
  _this.init_style = { position: 'static', top: '', bottom: '', width: '', height: '' };
188
  _this.need_to_calc_el_offset = function (el) {
189
+ return el.classList.contains(FixedWidgetClassName);
190
  };
191
  if (!_this.el || !_this.el.parentElement) {
192
  return _this;
193
  }
194
+ _this.el.classList.add(FixedWidgetClassName);
195
  return _this;
196
  }
197
  FixedWidget.prototype.mount = function (margins, layer, max_top_offset) {
275
  };
276
  FixedWidget.is = function (selector) {
277
  var el = document.querySelector(selector);
278
+ return !!el && el.classList.contains(FixedWidgetClassName);
279
  };
280
  return FixedWidget;
281
  }(PositionWidget));
282
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  var StickyWidget = /** @class */ (function (_super) {
284
  __extends(StickyWidget, _super);
285
  function StickyWidget(el) {
287
  _this.margins = 0;
288
  _this.borderBox = 0; /** cleintHeight+ top & bottom margins */
289
  _this.need_to_calc_el_offset = function (el) {
290
+ return el.classList.contains(FixedWidgetClassName);
 
291
  };
292
  if (!_this.el || !_this.el.parentElement) {
293
  return _this;
294
  }
295
+ _this.el.classList.add(FixedWidgetClassName);
296
  return _this;
297
  }
298
  StickyWidget.prototype.mount = function (margins, layer, max_top_offset) {
320
  }
321
  this.el.style.transform = "translateY(" + (bottom_margin - this.bottom_offset) + "px)";
322
  };
323
+ // || el.classList.contains(StopWidget.CLASSNAME);
324
  StickyWidget.new = function (selector) {
325
  return new StickyWidget(document.querySelector(selector));
326
  };
327
  StickyWidget.is = function (selector) {
328
  var el = document.querySelector(selector);
329
+ return !!el && el.classList.contains(FixedWidgetClassName);
330
  };
331
  return StickyWidget;
332
  }(PositionWidget));
333
 
334
+ var StopWidget = /** @class */ (function (_super) {
335
+ __extends(StopWidget, _super);
336
+ function StopWidget(el) {
337
+ var _this = _super.call(this, el) || this;
338
+ _this.need_to_calc_el_offset = function () { return true; };
339
+ if (!_this.el || !_this.el.parentElement) {
340
+ return _this;
341
+ }
342
+ _this.el.classList.add(StopWidgetClassName);
343
+ return _this;
344
+ }
345
+ StopWidget.new = function (selector) {
346
+ return new StopWidget(document.querySelector(selector));
347
+ };
348
+ StopWidget.is = function (selector) {
349
+ var el = document.querySelector(selector);
350
+ return !!el && el.classList.contains(StopWidgetClassName);
351
+ };
352
+ StopWidget.from = function (root) {
353
+ return _super.from.call(this, root, StopWidgetClassName);
354
+ };
355
+ return StopWidget;
356
+ }(Widget));
357
+
358
+ /**
359
+ *
360
+ * @param arr1
361
+ * @param arr2
362
+ * @returns [uniq elements from arr2, dublicates]
363
+ */
364
+ var findIntersections = function (arr1, arr2) {
365
+ return [
366
+ arr2.filter(function (e) { return !arr1.includes(e); }),
367
+ arr1.filter(function (e) { return arr2.includes(e); }),
368
+ ];
369
+ };
370
+
371
  var initSidebars = function (options) {
372
+ var fixedWidgetsContainers = Array.from(new Set(// use Set to remove duplicates
373
+ Widget
374
+ .queryAllWidgetsContainers(FixedWidgetClassName) // widgets by classNames from editor's plugin
375
+ .concat(queryElements(options.widgets)) // widgets from option's custom selectors
376
+ ));
377
+ var stopWidgetsContainers = Array.from(new Set(// use Set to remove duplicates
378
+ Widget
379
+ .queryAllWidgetsContainers(StopWidgetClassName) // widgets by classNames from editor's plugin;
380
+ .concat(options.stop_elements_selectors ?
381
+ queryElements(options.stop_elements_selectors.split('/n')) // widgets from option's custom selectors
382
+ : [])));
383
+ var _a = findIntersections(fixedWidgetsContainers, stopWidgetsContainers), stopWidgetsUniqContainers = _a[0], duplicates = _a[1];
384
+ duplicates.forEach(function (w) {
385
+ console.error("The Widget is detected as fixed block and stop block!\n" + w.innerHTML);
386
+ });
387
+ fixedWidgetsContainers.forEach(function (c) { c.classList.add(FixedWidgetClassName); });
388
+ stopWidgetsUniqContainers.forEach(function (c) { c.classList.add(StopWidgetClassName); });
389
+ var sidebars = Sidebar.create(fixedWidgetsContainers.concat(stopWidgetsUniqContainers), options);
390
  sidebars.forEach(function (sidebar) { sidebar.mount(); });
391
  document.addEventListener('scroll', function () {
392
  sidebars.forEach(function (sidebar) { return sidebar.render(); });
393
  });
394
  };
 
 
 
 
 
 
 
395
  var Sidebar = /** @class */ (function () {
396
  function Sidebar(el, margins, use_sticky_position) {
397
  this.el = el;
398
  this.margins = margins;
399
  this.use_sticky_position = use_sticky_position;
 
400
  this.widgets = [];
401
  this.stop_widgets = [];
402
  this.min_top_offset = 0;
403
+ this.stop_widgets = StopWidget.from(this.el);
 
404
  var WidgetContructor = typeof use_sticky_position === 'undefined' || use_sticky_position ? StickyWidget : FixedWidget;
405
+ this.widgets = WidgetContructor.from(this.el);
406
  if (!use_sticky_position) {
407
  return;
408
  }
410
  if (this.stop_widgets.length !== 0) {
411
  return;
412
  }
413
+ this.el.style.minHeight = '100%';
414
  }
415
  Sidebar.prototype.mount = function () {
416
  var _this = this;
424
  Sidebar.prototype.render = function () {
425
  this.widgets.forEach(function (widget) { return widget.render(); });
426
  };
427
+ Sidebar.create = function (elements, options) {
428
+ return Array.from(new Set(elements.map(function (widget) { return widget.parentElement; })))
429
+ .filter(function (sidebar_el) { return sidebar_el !== null; })
430
+ .map(function (sidebar_el) {
431
+ return new Sidebar(sidebar_el, options, typeof options.use_sticky_position === 'undefined' || options.use_sticky_position);
432
+ });
433
+ };
434
  return Sidebar;
435
  }());
436
+ var queryElements = function (selectors) {
437
+ if (selectors === void 0) { selectors = []; }
438
+ return Array.from((selectors)
439
+ .map(function (selector) { return document.querySelector(selector); }))
440
+ .filter(function (e) { return e instanceof HTMLElement; });
441
+ };
442
 
443
  var initPlugin = function (options) {
444
  if (options === void 0) { options = []; }
js/frontend.min.js CHANGED
@@ -12,4 +12,4 @@ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14
  PERFORMANCE OF THIS SOFTWARE.
15
- ***************************************************************************** */var t=function(e,i){return t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i])},t(e,i)};function e(e,i){if("function"!=typeof i&&null!==i)throw new TypeError("Class extends value "+String(i)+" is not a constructor or null");function n(){this.constructor=e}t(e,i),e.prototype=null===i?Object.create(i):(n.prototype=i.prototype,new n)}var i=function(){return i=Object.assign||function(t){for(var e,i=1,n=arguments.length;i<n;i++)for(var o in e=arguments[i])Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t},i.apply(this,arguments)};function n(t,e,i){if(i||2===arguments.length)for(var n,o=0,s=e.length;o<s;o++)!n&&o in e||(n||(n=Array.prototype.slice.call(e,0,o)),n[o]=e[o]);return t.concat(n||Array.prototype.slice.call(e))}var o=function(t,e){return Array.from(t.querySelectorAll("."+e)).filter((function(t){return null!==t}))},s=function(){function t(t){this.el=t,this.top_offset=0,this.root_offset=0,this.need_to_calc_el_offset=function(t){return!1}}return t.prototype.render=function(){},t.prototype.mount=function(t,e,i){this.el&&this.el.parentElement&&(this.el.style.zIndex=""+e,this.top_offset=this.get_total_top_offset(t),this.root_offset=f(this.el,document.body))},t.prototype.getSidebar=function(){return this.el&&this.el.parentElement},t.prototype.get_total_top_offset=function(t){var e=function(t){return t&&t.previousElementSibling};return c(e,this.need_to_calc_el_offset,e(this.el),t.margin_top)},t.queryAll=function(){var t=this;return[].concat(Array.from(document.querySelectorAll("."+this.CLASSNAME)),Array.from(document.querySelectorAll("[data-fixed_widget="+this.CLASSNAME))).map((function(e){return e.classList.remove(t.CLASSNAME),e.removeAttribute("data-fixed_widget"),new t(r(e))}))},t.CLASSNAME="FixedWidget__",t}(),r=function(t){return t.parentElement&&(1===t.parentElement.childElementCount||t.parentElement.classList.toString().includes("wp-block-group")||t.parentElement.classList.contains("widget"))?r(t.parentElement):t},l=function(t){function i(){var e=null!==t&&t.apply(this,arguments)||this;return e.bottom_offset=0,e.top_margin=0,e.max_top_offset=0,e.bottom_margin=0,e.user_margins={},e.prevScrollTop=0,e}return e(i,t),i.prototype.mount=function(e,i,n){if(t.prototype.mount.call(this,e,i,n),this.el&&this.el.parentElement){this.user_margins=e;var o=getComputedStyle(this.el),s=o.marginTop,r=o.marginBottom;this.bottom_margin=parseInt(r),this.top_margin=parseInt(s),this.bottom_offset=this.get_total_bottom_offset(e),this.max_top_offset=n}},i.prototype.render=function(){if(this.el&&this.el.parentElement){var t=document.documentElement.scrollTop;this.prevScrollTop=t,this.onScroll(t)}},i.prototype.onScroll=function(t){},i.prototype.get_total_bottom_offset=function(t){var e=function(t){return t&&t.nextElementSibling};return c(e,this.need_to_calc_el_offset,e(this.el),t.margin_bottom)},i.CLASSNAME="FixedWidget__fixed_widget",i}(s),c=function(t,e,i,n){if(void 0===n&&(n=0),!i)return n;if(!e(i))return c(t,e,t(i),n);var o=getComputedStyle(i),s=o.marginTop,r=o.marginBottom;return c(t,e,t(i),n+i.offsetHeight+parseInt(s||"0")+parseInt(r||"0"))},f=function(t,e,i){return void 0===i&&(i=0),t&&t!==e?i+f(t.offsetParent,e,t.offsetTop):i},h=function(t){function i(e){var n=t.call(this,e)||this;return n.is_pinned=!1,n.relative_top=0,n.init_style={position:"static",top:"",bottom:"",width:"",height:""},n.need_to_calc_el_offset=function(t){return t.classList.contains(i.CLASSNAME)},n.el&&n.el.parentElement?(n.el.classList.add(i.CLASSNAME),n):n}return e(i,t),i.prototype.mount=function(e,i,n){t.prototype.mount.call(this,e,i,n),this.el&&(this.relative_top=this.max_top_offset-this.top_offset-this.el.clientHeight-this.bottom_offset-this.bottom_margin-this.top_margin,this.clone(),this.store_style(getComputedStyle(this.el)))},i.prototype.clone=function(){var t,e=this;this.el&&(this.clone_el=this.el.cloneNode(!1),this.clone_el.getAttributeNames().forEach((function(t){e.clone_el.removeAttribute(t)})),this.clone_el.style.height=this.el.clientHeight+"px",this.clone_el.style.width=this.el.clientWidth+"px",this.clone_el.style.display="none",null===(t=this.el.parentElement)||void 0===t||t.insertBefore(this.clone_el,this.el))},i.prototype.store_style=function(t){this.init_style.position=t.position,this.init_style.top=t.top,this.init_style.width=t.width,this.init_style.height=t.top},i.prototype.restore_style=function(t){this.is_pinned&&(this.is_pinned=!1,t.position=this.init_style.position,t.top=this.init_style.top,this.clone_el&&(this.clone_el.style.display="none"))},i.prototype.onScroll=function(t){if(this.el){var e=t>this.root_offset-this.top_offset,i=0!==this.max_top_offset&&t>this.relative_top?this.relative_top-t+this.top_offset:this.top_offset;e?this.fix(i):this.restore_style(this.el.style)}},i.prototype.fix=function(t){this.el&&(this.el.style.top=t+"px",this.is_pinned||(this.is_pinned=!0,this.el.style.position="fixed",this.el.style.transition="transform 0.5s",this.el.style.width=this.init_style.width,this.el.style.height=this.init_style.height,this.clone_el&&(this.clone_el.style.display="block")))},i.new=function(t){return new i(document.querySelector(t))},i.is=function(t){var e=document.querySelector(t);return!!e&&e.classList.contains(i.CLASSNAME)},i}(l),u=function(t){function i(e){var n=t.call(this,e)||this;return n.need_to_calc_el_offset=function(){return!0},n.el&&n.el.parentElement?(n.el.classList.add(i.CLASSNAME),n):n}return e(i,t),i.new=function(t){return new i(document.querySelector(t))},i.is=function(t){var e=document.querySelector(t);return!!e&&e.classList.contains(i.CLASSNAME)},i.CLASSNAME="FixedWidget__stop_widget",i}(s),a=function(t){function i(e){var n=t.call(this,e)||this;return n.margins=0,n.borderBox=0,n.need_to_calc_el_offset=function(t){return t.classList.contains(i.CLASSNAME)||t.classList.contains(u.CLASSNAME)},n.el&&n.el.parentElement?(n.el.classList.add(i.CLASSNAME),n):n}return e(i,t),i.prototype.mount=function(e,i,n){t.prototype.mount.call(this,e,i,n),this.el&&this.el.parentElement&&(this.borderBox=this.el.clientHeight+this.top_margin+this.bottom_margin,this.margins=this.el.parentElement.clientHeight-this.borderBox,this.el.style.position="sticky",this.el.style.position="-webkit-sticky",this.el.style.transition="transform 0s",this.el.style.boxSizing="border-box",this.el.style.top=this.top_offset+"px")},i.prototype.onScroll=function(){if(this.el&&this.el.parentElement){var t=this.max_top_offset?Math.min(this.max_top_offset-this.el.offsetTop-this.borderBox,this.margins-this.el.offsetTop):this.margins-this.el.offsetTop;t>this.bottom_offset||(this.el.style.transform="translateY("+(t-this.bottom_offset)+"px)")}},i.new=function(t){return new i(document.querySelector(t))},i.is=function(t){var e=document.querySelector(t);return!!e&&e.classList.contains(i.CLASSNAME)},i}(l),p=function(t,e){return Array.from(new Set(t.map((function(t){return t.getSidebar()})))).filter((function(t){return null!==t})).map((function(t){return new _(t,e,void 0===e.use_sticky_position||e.use_sticky_position)}))},_=function(){function t(t,e,i){this.el=t,this.margins=e,this.use_sticky_position=i,this.not_widgets=[],this.widgets=[],this.stop_widgets=[],this.min_top_offset=0,this.stop_widgets=o(this.el,u.CLASSNAME).map((function(t){return new u(t)})),this.not_widgets=Array.from(this.el.querySelectorAll(".widget:not(."+a.CLASSNAME+",."+u.CLASSNAME+")"));var n=void 0===i||i?a:h;this.widgets=o(this.el,n.CLASSNAME).map((function(t){return new n(t)})),i&&(this.el.style.position="relative",0===this.stop_widgets.length&&(this.el.style.height="100%"))}return t.prototype.mount=function(){var t=this;this.stop_widgets.forEach((function(e,i){return e.mount(t.margins,0,0)})),this.min_top_offset=0!==this.stop_widgets.length?Math.min.apply(Math,this.stop_widgets.map(this.use_sticky_position?function(t){return t.top_offset}:function(t){return t.root_offset})):0,this.widgets.forEach((function(e,i){return e.mount(t.margins,i,t.min_top_offset)}))},t.prototype.render=function(){this.widgets.forEach((function(t){return t.render()}))},t}(),m=function(t){void 0===t&&(t=[]),function(t){var e=void 0===t.use_sticky_position||t.use_sticky_position?a:h,i=e.queryAll().concat((t.widgets||[]).filter(Boolean).map(e.new)),o=u.queryAll().concat((t.stop_elements_selectors||"").split("/n").filter(Boolean).map(u.new)),s=p(n(n([],i,!0),o,!0),t);s.forEach((function(t){t.mount()})),document.addEventListener("scroll",(function(){s.forEach((function(t){return t.render()}))}))}(t.reduce((function(t,e){return i(i(i({},t),e),{widgets:t.widgets.concat(e.widgets||[])})}),{widgets:[]}))};function d(){var t=document.querySelector("#wpadminbar"),e=(window.q2w3_sidebar_options||[{}]).map((function(e){return e.margin_top=(e.margin_top||0)+((null==t?void 0:t.clientHeight)||0),e}));e.some((function(t){return window.innerWidth<t.screen_max_width||window.innerHeight<t.screen_max_height}))||m(e)}window.addEventListener("load",d),"complete"===document.readyState&&d();
12
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14
  PERFORMANCE OF THIS SOFTWARE.
15
+ ***************************************************************************** */var extendStatics=function(d,b){return extendStatics=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(d,b){d.__proto__=b}||function(d,b){for(var p in b)Object.prototype.hasOwnProperty.call(b,p)&&(d[p]=b[p])},extendStatics(d,b)};function __extends(d,b){if("function"!=typeof b&&null!==b)throw new TypeError("Class extends value "+String(b)+" is not a constructor or null");function __(){this.constructor=d}extendStatics(d,b),d.prototype=null===b?Object.create(b):(__.prototype=b.prototype,new __)}var __assign=function(){return __assign=Object.assign||function(t){for(var s,i=1,n=arguments.length;i<n;i++)for(var p in s=arguments[i])Object.prototype.hasOwnProperty.call(s,p)&&(t[p]=s[p]);return t},__assign.apply(this,arguments)},StopWidgetClassName="FixedWidget__stop_widget",FixedWidgetClassName="FixedWidget__fixed_widget",Widget=function(){function Widget(el){this.el=el,this.top_offset=0,this.root_offset=0,this.need_to_calc_el_offset=function(_){return!1}}return Widget.prototype.render=function(){},Widget.prototype.mount=function(user_margins,layer,_max_top_offset){this.el&&this.el.parentElement&&(this.el.style.zIndex=""+layer,this.top_offset=this.get_total_top_offset(user_margins),this.root_offset=get_root_offset(this.el,document.body))},Widget.prototype.getElement=function(){return this.el},Widget.prototype.toString=function(){var _a;return""+(null===(_a=this.el)||void 0===_a?void 0:_a.innerHTML)},Widget.prototype.get_total_top_offset=function(margins){var next=function(el){return el&&el.previousElementSibling};return get_sibilings_offset(next,this.need_to_calc_el_offset,next(this.el),margins.margin_top)},Widget.queryAllWidgetsContainers=function(className){return[].concat(Array.from(document.querySelectorAll("."+className)),Array.from(document.querySelectorAll("[data-fixed_widget="+className))).map((function(el){el.classList.remove(className),el.removeAttribute("data-fixed_widget");var container=getWidgetContainer(el);return container.classList.remove(FixedWidgetClassName),container.classList.remove(StopWidgetClassName),container}))},Widget.from=function(root,className){var _this=this;return Array.from(root.querySelectorAll("."+className)).filter((function(el){return null!==el})).map((function(e){return new _this(e)}))},Widget}(),getWidgetContainer=function(el){return el.parentElement&&(1===el.parentElement.childElementCount||el.parentElement.classList.toString().includes("wp-block-group")||el.parentElement.classList.toString().includes("wp-block-column")||el.parentElement.classList.contains("widget"))?getWidgetContainer(el.parentElement):el},get_sibilings_offset=function(next,need_to_calc_el_offset,el,offset){if(void 0===offset&&(offset=0),!el)return offset;if(!need_to_calc_el_offset(el))return get_sibilings_offset(next,need_to_calc_el_offset,next(el),offset);var _a=getComputedStyle(el),marginTop=_a.marginTop,marginBottom=_a.marginBottom;return get_sibilings_offset(next,need_to_calc_el_offset,next(el),offset+el.offsetHeight+parseInt(marginTop||"0")+parseInt(marginBottom||"0"))},get_root_offset=function(el,top_parent,offset){return void 0===offset&&(offset=0),el&&el!==top_parent?offset+get_root_offset(el.offsetParent,top_parent,el.offsetTop):offset},PositionWidget=function(_super){function PositionWidget(){var _this=null!==_super&&_super.apply(this,arguments)||this;return _this.bottom_offset=0,_this.top_margin=0,_this.max_top_offset=0,_this.bottom_margin=0,_this.user_margins={},_this}return __extends(PositionWidget,_super),PositionWidget.prototype.mount=function(user_margins,layer,max_top_offset){if(_super.prototype.mount.call(this,user_margins,layer,max_top_offset),this.el&&this.el.parentElement){this.user_margins=user_margins;var _a=getComputedStyle(this.el),marginTop=_a.marginTop,marginBottom=_a.marginBottom;this.bottom_margin=parseInt(marginBottom),this.top_margin=parseInt(marginTop),this.bottom_offset=this.get_total_bottom_offset(user_margins),max_top_offset>this.el.offsetTop&&(this.max_top_offset=max_top_offset)}},PositionWidget.prototype.render=function(){if(this.el&&this.el.parentElement){var scrollTop=document.documentElement.scrollTop;this.onScroll(scrollTop)}},PositionWidget.from=function(root){return _super.from.call(this,root,FixedWidgetClassName)},PositionWidget.prototype.onScroll=function(_scrollTop){},PositionWidget.prototype.get_total_bottom_offset=function(margins){var next=function(el){return el&&!el.classList.contains(StopWidgetClassName)?el.nextElementSibling:null};return get_sibilings_offset(next,this.need_to_calc_el_offset,next(this.el),margins.margin_bottom)},PositionWidget}(Widget),FixedWidget=function(_super){function FixedWidget(el){var _this=_super.call(this,el)||this;return _this.is_pinned=!1,_this.relative_top=0,_this.init_style={position:"static",top:"",bottom:"",width:"",height:""},_this.need_to_calc_el_offset=function(el){return el.classList.contains(FixedWidgetClassName)},_this.el&&_this.el.parentElement?(_this.el.classList.add(FixedWidgetClassName),_this):_this}return __extends(FixedWidget,_super),FixedWidget.prototype.mount=function(margins,layer,max_top_offset){_super.prototype.mount.call(this,margins,layer,max_top_offset),this.el&&(this.relative_top=this.max_top_offset-this.top_offset-this.el.clientHeight-this.bottom_offset-this.bottom_margin-this.top_margin,this.clone(),this.store_style(getComputedStyle(this.el)))},FixedWidget.prototype.clone=function(){var _a,_this=this;this.el&&(this.clone_el=this.el.cloneNode(!1),this.clone_el.getAttributeNames().forEach((function(attr){_this.clone_el.removeAttribute(attr)})),this.clone_el.style.height=this.el.clientHeight+"px",this.clone_el.style.width=this.el.clientWidth+"px",this.clone_el.style.display="none",null===(_a=this.el.parentElement)||void 0===_a||_a.insertBefore(this.clone_el,this.el))},FixedWidget.prototype.store_style=function(style){this.init_style.position=style.position,this.init_style.top=style.top,this.init_style.width=style.width,this.init_style.height=style.top},FixedWidget.prototype.restore_style=function(style){this.is_pinned&&(this.is_pinned=!1,style.position=this.init_style.position,style.top=this.init_style.top,this.clone_el&&(this.clone_el.style.display="none"))},FixedWidget.prototype.onScroll=function(scrollTop){if(this.el){var need_to_fix=scrollTop>this.root_offset-this.top_offset,top=0!==this.max_top_offset&&scrollTop>this.relative_top?this.relative_top-scrollTop+this.top_offset:this.top_offset;need_to_fix?this.fix(top):this.restore_style(this.el.style)}},FixedWidget.prototype.fix=function(top){this.el&&(this.el.style.top=top+"px",this.is_pinned||(this.is_pinned=!0,this.el.style.position="fixed",this.el.style.transition="transform 0.5s",this.el.style.width=this.init_style.width,this.el.style.height=this.init_style.height,this.clone_el&&(this.clone_el.style.display="block")))},FixedWidget.new=function(selector){return new FixedWidget(document.querySelector(selector))},FixedWidget.is=function(selector){var el=document.querySelector(selector);return!!el&&el.classList.contains(FixedWidgetClassName)},FixedWidget}(PositionWidget),StickyWidget=function(_super){function StickyWidget(el){var _this=_super.call(this,el)||this;return _this.margins=0,_this.borderBox=0,_this.need_to_calc_el_offset=function(el){return el.classList.contains(FixedWidgetClassName)},_this.el&&_this.el.parentElement?(_this.el.classList.add(FixedWidgetClassName),_this):_this}return __extends(StickyWidget,_super),StickyWidget.prototype.mount=function(margins,layer,max_top_offset){_super.prototype.mount.call(this,margins,layer,max_top_offset),this.el&&this.el.parentElement&&(this.borderBox=this.el.clientHeight+this.top_margin+this.bottom_margin,this.margins=this.el.parentElement.clientHeight-this.borderBox,this.el.style.position="sticky",this.el.style.position="-webkit-sticky",this.el.style.transition="transform 0s",this.el.style.boxSizing="border-box",this.el.style.top=this.top_offset+"px")},StickyWidget.prototype.onScroll=function(){if(this.el&&this.el.parentElement){var bottom_margin=this.max_top_offset?Math.min(this.max_top_offset-this.el.offsetTop-this.borderBox,this.margins-this.el.offsetTop):this.margins-this.el.offsetTop;bottom_margin>this.bottom_offset||(this.el.style.transform="translateY("+(bottom_margin-this.bottom_offset)+"px)")}},StickyWidget.new=function(selector){return new StickyWidget(document.querySelector(selector))},StickyWidget.is=function(selector){var el=document.querySelector(selector);return!!el&&el.classList.contains(FixedWidgetClassName)},StickyWidget}(PositionWidget),StopWidget=function(_super){function StopWidget(el){var _this=_super.call(this,el)||this;return _this.need_to_calc_el_offset=function(){return!0},_this.el&&_this.el.parentElement?(_this.el.classList.add(StopWidgetClassName),_this):_this}return __extends(StopWidget,_super),StopWidget.new=function(selector){return new StopWidget(document.querySelector(selector))},StopWidget.is=function(selector){var el=document.querySelector(selector);return!!el&&el.classList.contains(StopWidgetClassName)},StopWidget.from=function(root){return _super.from.call(this,root,StopWidgetClassName)},StopWidget}(Widget),Sidebar=function(){function Sidebar(el,margins,use_sticky_position){this.el=el,this.margins=margins,this.use_sticky_position=use_sticky_position,this.widgets=[],this.stop_widgets=[],this.min_top_offset=0,this.stop_widgets=StopWidget.from(this.el);var WidgetContructor=void 0===use_sticky_position||use_sticky_position?StickyWidget:FixedWidget;this.widgets=WidgetContructor.from(this.el),use_sticky_position&&(this.el.style.position="relative",0===this.stop_widgets.length&&(this.el.style.height="100%"))}return Sidebar.prototype.mount=function(){var _this=this;this.stop_widgets.forEach((function(widget,i){return widget.mount(_this.margins,0,0)})),this.min_top_offset=0!==this.stop_widgets.length?Math.min.apply(Math,this.stop_widgets.map(this.use_sticky_position?function(w){return w.top_offset}:function(w){return w.root_offset})):0,this.widgets.forEach((function(widget,i){return widget.mount(_this.margins,i,_this.min_top_offset)}))},Sidebar.prototype.render=function(){this.widgets.forEach((function(widget){return widget.render()}))},Sidebar.create=function(elements,options){return Array.from(new Set(elements.map((function(widget){return widget.parentElement})))).filter((function(sidebar_el){return null!==sidebar_el})).map((function(sidebar_el){return new Sidebar(sidebar_el,options,void 0===options.use_sticky_position||options.use_sticky_position)}))},Sidebar}(),queryElements=function(selectors){return void 0===selectors&&(selectors=[]),Array.from(selectors.map((function(selector){return document.querySelector(selector)}))).filter((function(e){return e instanceof HTMLElement}))},initPlugin=function(options){void 0===options&&(options=[]),function(options){var arr1,arr2,fixedWidgetsContainers=Array.from(new Set(Widget.queryAllWidgetsContainers(FixedWidgetClassName).concat(queryElements(options.widgets)))),stopWidgetsContainers=Array.from(new Set(Widget.queryAllWidgetsContainers(StopWidgetClassName).concat(options.stop_elements_selectors?queryElements(options.stop_elements_selectors.split("/n")):[]))),_a=(arr1=fixedWidgetsContainers,[(arr2=stopWidgetsContainers).filter((function(e){return!arr1.includes(e)})),arr1.filter((function(e){return arr2.includes(e)}))]),stopWidgetsUniqContainers=_a[0];_a[1].forEach((function(w){console.error("The Widget is detected as fixed block and stop block!\n"+w.innerHTML)})),fixedWidgetsContainers.forEach((function(c){c.classList.add(FixedWidgetClassName)})),stopWidgetsUniqContainers.forEach((function(c){c.classList.add(StopWidgetClassName)}));var sidebars=Sidebar.create(fixedWidgetsContainers.concat(stopWidgetsUniqContainers),options);sidebars.forEach((function(sidebar){sidebar.mount()})),document.addEventListener("scroll",(function(){sidebars.forEach((function(sidebar){return sidebar.render()}))}))}(options.reduce((function(prev,cur){return __assign(__assign(__assign({},prev),cur),{widgets:prev.widgets.concat(cur.widgets||[])})}),{widgets:[]}))};function onDocumentLoaded(){var admin_panel=document.querySelector("#wpadminbar"),options=(window.q2w3_sidebar_options||[{}]).map((function(option){return option.margin_top=(option.margin_top||0)+((null==admin_panel?void 0:admin_panel.clientHeight)||0),option}));options.some((function(option){return window.innerWidth<option.screen_max_width||window.innerHeight<option.screen_max_height}))||initPlugin(options)}window.addEventListener("load",onDocumentLoaded),"complete"===document.readyState&&onDocumentLoaded();
q2w3-fixed-widget.php CHANGED
@@ -5,7 +5,7 @@ Plugin URI: https://wpadvancedads.com/fixed-widget-wordpress/
5
  Description: Use the fixed widget plugin to create sticky widgets that stay in the visible screen area when the page is scrolled up or down and boost your conversions.
6
  Text Domain: q2w3-fixed-widget
7
  Author: Thomas Maier, Max Bond
8
- Version: 6.0.0-beta-2
9
  Author URI: https://wpadvancedads.com/fixed-widget-wordpress/
10
  */
11
 
@@ -23,7 +23,7 @@ class q2w3_fixed_widget {
23
 
24
  const ID = 'q2w3_fixed_widget';
25
 
26
- const VERSION = '6.0.0-beta-2';
27
 
28
  protected static $sidebars_widgets;
29
 
5
  Description: Use the fixed widget plugin to create sticky widgets that stay in the visible screen area when the page is scrolled up or down and boost your conversions.
6
  Text Domain: q2w3-fixed-widget
7
  Author: Thomas Maier, Max Bond
8
+ Version: 6.0.0-beta-1
9
  Author URI: https://wpadvancedads.com/fixed-widget-wordpress/
10
  */
11
 
23
 
24
  const ID = 'q2w3_fixed_widget';
25
 
26
+ const VERSION = '6.0.0-beta-1';
27
 
28
  protected static $sidebars_widgets;
29
 
readme.txt CHANGED
@@ -17,18 +17,13 @@ That's why this option is worthwhile for ads or other elements that visitors sho
17
 
18
  * [Manual and demo](https://wpadvancedads.com/fixed-widget-wordpress/)
19
 
20
- = Changes in version 6.0.0 =
21
 
22
- Version 6.0 is a full rewrite of the frontend script. It fixes many edge cases like jumping, reloading, or resizing widgets.
23
- The rewrite also resolves bad Cumulative Layout Shifts.
24
 
25
- Enable "Test new version" under Appearance > Fixed Widget Options.
26
 
27
- - the frontend script does not need jQuery anymore
28
- - removed unneeded options that previously helped resolving edge cases
29
- - "Stop Elements" and "Custom Fixed Elements" now accept any selector, including IDs, Class, and Type selectors.
30
- - works with the widget block editor introduced in WordPress 5.8
31
- - added "stop" option to widget blocks
32
 
33
  Please test and [let us know](https://wordpress.org/support/plugin/q2w3-fixed-widget/) if you discover any issues.
34
 
@@ -36,12 +31,11 @@ Please test and [let us know](https://wordpress.org/support/plugin/q2w3-fixed-wi
36
 
37
  All the features are free.
38
 
39
- * **Sticky Widgets** Use the Fixed Widget option on any widget and blocks in the sidebar
40
  * **Sticky Elements** Choose any element on your site and make it sticky
41
  * **Margin Top** allows you to stop sticky elements to cover sticky menu bars
42
  * **Margin Bottom** pushes sticky elements up before they reach a certain distance towards the bottom window
43
  * **Stop Elements** push sticky elements up when they are scrolling into view
44
- * **Stop Blocks** defines blocks in your sidebar that push fixed blocks out of the page
45
  * **Minimum Screen Width** and **Minimum Screen Height** allow you to disable sticky behavior on small screens
46
 
47
  = Compatibility =
@@ -49,7 +43,11 @@ All the features are free.
49
  Theme requirements:
50
 
51
  * `wp_head()` and `wp_footer()` functions in `header.php` and `footer.php` files
 
52
  * JavaScript errors could break sticky widgets
 
 
 
53
 
54
  == Installation ==
55
 
@@ -58,6 +56,7 @@ Theme requirements:
58
  3. Go to Appearance -> Widgets, enable the "Fixed Widget" option on any active widget
59
  4. Fine tune plugin parameters on Appearance -> Fixed Widget Options page
60
 
 
61
  == Frequently Asked Questions ==
62
 
63
  = Why is the Fixed Widget plugin not working? =
@@ -73,6 +72,14 @@ There are several reasons:
73
 
74
  Yes, it is possible to fix more than one widget even if they are located in different sidebars.
75
 
 
 
 
 
 
 
 
 
76
  = How to prevent overlapping with the footer? =
77
 
78
  Go to WP admin area, Appearance -> Fixed Widget Options. Here you can define the top and bottom margins. Set bottom margin value >= footer height. Check the result, please.
@@ -85,17 +92,15 @@ Use the options `Minimum Screen Width` and `Minimum Screen Height` to disable st
85
  == Screenshots ==
86
 
87
  1. The Fixed Widget for WordPress plugin in action
88
- 2. Fixed Widget plugin options
89
- 3. Block options in the widget editor
90
 
91
  == Changelog ==
92
 
93
- = 6.0.0 =
94
 
95
- Version 6.0 is a full rewrite of the frontend script. It fixes many edge cases like jumping, reloading, or resizing widgets.
96
  The rewrite also resolves bad Cumulative Layout Shifts.
97
 
98
- Most changes are available when you enable "Test new version" under Appearance > Fixed Widget Options.
99
 
100
  Please test and [let us know](https://wordpress.org/support/plugin/q2w3-fixed-widget/) if you discover any issues.
101
 
@@ -103,8 +108,6 @@ Please test and [let us know](https://wordpress.org/support/plugin/q2w3-fixed-wi
103
  - the frontend script does not need jQuery anymore
104
  - removed unneeded options that previously helped resolving edge cases
105
  - "Stop Elements" and "Custom Fixed Elements" now accept any selector, including IDs, Class, and Type selectors.
106
- - fixed blocks in sidebars as introduced in WordPress 5.8
107
- - define stop blocks in sidebars that move up fixed blocks on scrolling
108
  - improved option descriptions on the admin page
109
  - improved behavior for elements higher than the screen – they first stick at the top and scroll to the bottom later
110
  - removed duplicating widget code
@@ -263,4 +266,4 @@ Please test and [let us know](https://wordpress.org/support/plugin/q2w3-fixed-wi
263
 
264
  = 6.0.0 =
265
 
266
- Major rewrite of the frontend JavaScript with fixes for a lot of edge cases. Does not need jQuery anymore. See more details in the Changelog.
17
 
18
  * [Manual and demo](https://wpadvancedads.com/fixed-widget-wordpress/)
19
 
20
+ = Test version 6.0.0 =
21
 
22
+ Please download and test [version 6.0.0, beta 3](https://downloads.wordpress.org/plugin/q2w3-fixed-widget.6.0.0-beta-3.zip).
 
23
 
24
+ It solves a lot of edge cases with various themes and improves PageSpeed scores.
25
 
26
+ Most changes are available when you switch on "Test new version" under Appearance > Fixed Widget Options.
 
 
 
 
27
 
28
  Please test and [let us know](https://wordpress.org/support/plugin/q2w3-fixed-widget/) if you discover any issues.
29
 
31
 
32
  All the features are free.
33
 
34
+ * **Sticky Widgets** Use the Fixed Widget option on any widget in any sidebar
35
  * **Sticky Elements** Choose any element on your site and make it sticky
36
  * **Margin Top** allows you to stop sticky elements to cover sticky menu bars
37
  * **Margin Bottom** pushes sticky elements up before they reach a certain distance towards the bottom window
38
  * **Stop Elements** push sticky elements up when they are scrolling into view
 
39
  * **Minimum Screen Width** and **Minimum Screen Height** allow you to disable sticky behavior on small screens
40
 
41
  = Compatibility =
43
  Theme requirements:
44
 
45
  * `wp_head()` and `wp_footer()` functions in `header.php` and `footer.php` files
46
+ * Sticky widgets must have an ID attribute
47
  * JavaScript errors could break sticky widgets
48
+ * jQuery is no longer required
49
+
50
+ In some themes, fixed widgets „jump“ during scrolling, etc. Some CSS changes at your theme will be required in this case.
51
 
52
  == Installation ==
53
 
56
  3. Go to Appearance -> Widgets, enable the "Fixed Widget" option on any active widget
57
  4. Fine tune plugin parameters on Appearance -> Fixed Widget Options page
58
 
59
+
60
  == Frequently Asked Questions ==
61
 
62
  = Why is the Fixed Widget plugin not working? =
72
 
73
  Yes, it is possible to fix more than one widget even if they are located in different sidebars.
74
 
75
+ = Why is the plugin not working in Chrome (and other Webkit based browsers)? =
76
+
77
+ Check your CSS files for these two instructions:
78
+ `-webkit-backface-visibility:hidden;
79
+ -webkit-transform: translate3d(0,0,0);`
80
+
81
+ If found, disable them and see the result.
82
+
83
  = How to prevent overlapping with the footer? =
84
 
85
  Go to WP admin area, Appearance -> Fixed Widget Options. Here you can define the top and bottom margins. Set bottom margin value >= footer height. Check the result, please.
92
  == Screenshots ==
93
 
94
  1. The Fixed Widget for WordPress plugin in action
 
 
95
 
96
  == Changelog ==
97
 
98
+ = 6.0.0-beta-3 =
99
 
100
+ Version 6.0.0 is a full rewrite of the frontend script. It fixes many edge cases like jumping, reloading, or resizing widgets.
101
  The rewrite also resolves bad Cumulative Layout Shifts.
102
 
103
+ Most changes are available when you switch on "Test new version" under Appearance > Fixed Widget Options.
104
 
105
  Please test and [let us know](https://wordpress.org/support/plugin/q2w3-fixed-widget/) if you discover any issues.
106
 
108
  - the frontend script does not need jQuery anymore
109
  - removed unneeded options that previously helped resolving edge cases
110
  - "Stop Elements" and "Custom Fixed Elements" now accept any selector, including IDs, Class, and Type selectors.
 
 
111
  - improved option descriptions on the admin page
112
  - improved behavior for elements higher than the screen – they first stick at the top and scroll to the bottom later
113
  - removed duplicating widget code
266
 
267
  = 6.0.0 =
268
 
269
+ Major rewrite of the frontend JavaScript with fixes for a lot of edge cases. Does not need jQuery anymore. See more details in the Changelog.