PluginProbe
UiCore Elements – Free widgets and templates for Elementor / 1.3.17
UiCore Elements – Free widgets and templates for Elementor v1.3.17
1.3.17 1.3.16 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 All 41 releases
← All changes | includes/widgets/custom-table.php +267 -132 1.0.161.3.17 View file →
@@ -1,5 +1,6 @@
1 1 <?php
2 +
2 3 namespace UiCoreElements;
3 4
4 5 use Elementor\Plugin;
5 6 use Elementor\Controls_Manager;
@@ -8,9 +9,10 @@
8 9 use UiCoreElements\Utils\Animation_Trait;
9 10
10 11 defined('ABSPATH') || exit();
11 12
12 -class CustomTable extends UiCoreNestedWidget {
13 +class CustomTable extends UiCoreNestedWidget
14 +{
13 15
14 16 use Animation_Trait;
15 17
16 18 public function get_name()
@@ -40,47 +42,61 @@
40 42 public function get_scripts()
41 43 {
42 44 return [];
43 45 }
46 + public function has_widget_inner_wrapper(): bool
47 + {
48 + // TODO: remove after Optmized Markup experiment is merged to the core
49 + return ! \Elementor\Plugin::$instance->experiments->is_feature_active('e_optimized_markup');
50 + }
44 51
45 - protected function carousel_content_container( int $index ) {
46 - return [
47 - 'elType' => 'container',
48 - 'settings' => [
49 - '_title' => sprintf( __( 'Cel #%s', 'uicore-elements' ), $index ),
50 - 'content_width' => 'full',
51 - // 'flex_justify_content' => 'center',
52 - // 'flex_align_items' => 'center',
53 - // the settings work only ofr first default items
54 - ],
52 + protected function carousel_content_container(int $index)
53 + {
54 + return [
55 + 'elType' => 'container',
56 + 'settings' => [
57 + /* translators: %s: Item index */
58 + '_title' => sprintf(__('Cel #%s', 'uicore-elements'), $index),
59 + 'content_width' => 'full',
60 + ],
55 61 ];
56 - }
62 + }
57 63
58 - protected function get_default_children_elements() {
59 - return [
60 - $this->carousel_content_container( 1 ),
61 - $this->carousel_content_container( 2 ),
62 - $this->carousel_content_container( 3 ),
63 - ];
64 - }
64 + protected function get_default_children_elements()
65 + {
66 + return [
67 + $this->carousel_content_container(1),
68 + $this->carousel_content_container(2),
69 + $this->carousel_content_container(3),
70 + ];
71 + }
65 72
66 - protected function get_default_repeater_title_setting_key() {
67 - return 'table_cels';
68 - }
73 + protected function get_default_repeater_title_setting_key()
74 + {
75 + return 'item';
76 + }
69 77
70 - protected function get_default_children_title() {
71 - return esc_html__( 'Cell #%d', 'uicore-elements' );
72 - }
73 - protected function get_default_children_placeholder_selector() {
74 - return '.ui-e-table';
75 - }
78 + protected function get_default_children_title()
79 + {
80 + /* translators: %d: Item index */
81 + return esc_html__('Cel #%d', 'uicore-elements');
82 + }
83 + protected function get_default_children_placeholder_selector()
84 + {
85 + return '.ui-e-table';
86 + }
76 87
88 + protected function get_default_children_container_placeholder_selector()
89 + {
90 + return '.ui-e-table-editor-placeholder';
91 + }
92 +
77 93 protected function register_controls()
78 94 {
79 - if( !Plugin::$instance->experiments->is_feature_active('nested-elements') ) {
80 - $this->nesting_fallback('controls');
81 - return;
82 - }
95 + if (!Plugin::$instance->experiments->is_feature_active('nested-elements')) {
96 + $this->nesting_fallback('controls');
97 + return;
98 + }
83 99
84 100 $this->start_controls_section(
85 101 'section_content',
86 102 [
@@ -88,8 +104,18 @@
88 104 'tab' => Controls_Manager::TAB_CONTENT,
89 105 ]
90 106 );
91 107
108 + $this->add_control(
109 + 'rerender_table',
110 + [
111 + 'label' => esc_html__('Preview', 'uicore-elements'),
112 + 'type' => Controls_Manager::BUTTON,
113 + 'text' => esc_html__('Refresh Table', 'uicore-elements'),
114 + 'separator' => 'before',
115 + 'event' => 'ui-e-custom-table-rerender',
116 + ]
117 + );
92 118
93 119 //Columns
94 120 $columns = new Repeater();
95 121 $columns->add_responsive_control(
@@ -96,9 +122,9 @@
96 122 'col_size',
97 123 [
98 124 'label' => __('Column Size', 'uicore-elements'),
99 125 'type' => Controls_Manager::SLIDER,
100 - 'size_units' => ['px', 'fr','custom'],
126 + 'size_units' => ['px', 'fr', 'custom'],
101 127 'default' => [
102 128 'size' => 300,
103 129 'unit' => 'px',
104 130 ],
@@ -111,8 +137,9 @@
111 137 'min' => 1,
112 138 'max' => 12,
113 139 ],
114 140 ],
141 + 'render_type' => 'ui',
115 142 'selectors' => [
116 143 '{{WRAPPER}}' => '--ui-e-last:{{SIZE}}{{UNIT}};',
117 144 ],
118 145 ]
@@ -123,13 +150,13 @@
123 150 [
124 151 'type' => Controls_Manager::REPEATER,
125 152 'fields' => $columns->get_controls(),
126 153 'title_field' => 'Column',
127 - 'render_type' => 'template',
154 + 'render_type' => 'ui',
128 155 'default' => [
129 - [ 'col_size' => [ 'size' => 1, 'unit' => 'fr' ] ],
130 - [ 'col_size' => [ 'size' => 1, 'unit' => 'fr' ] ],
131 - [ 'col_size' => [ 'size' => 1, 'unit' => 'fr' ] ],
156 + ['col_size' => ['size' => 1, 'unit' => 'fr']],
157 + ['col_size' => ['size' => 1, 'unit' => 'fr']],
158 + ['col_size' => ['size' => 1, 'unit' => 'fr']],
132 159 ],
133 160 ]
134 161 );
135 162
@@ -141,8 +168,9 @@
141 168 'item',
142 169 [
143 170 'label' => __('Title', 'uicore-elements'),
144 171 'type' => Controls_Manager::TEXT,
172 + 'render_type' => 'ui'
145 173 ]
146 174 );
147 175
148 176 $this->add_control(
@@ -149,13 +177,14 @@
149 177 'cells',
150 178 [
151 179 'type' => Control_Nested_Repeater::CONTROL_TYPE,
152 180 'fields' => $repeater->get_controls(),
181 + 'title_field' => '{{{ item }}}',
153 182 'allow_empty' => false,
154 183 'default' => [
155 - [ 'item' => __( 'Cel #1', 'uicore-elements' ) ],
156 - [ 'item' => __( 'Cel #2', 'uicore-elements' ) ],
157 - [ 'item' => __( 'Cel #3', 'uicore-elements' ) ],
184 + ['item' => __('Cel #1', 'uicore-elements')],
185 + ['item' => __('Cel #2', 'uicore-elements')],
186 + ['item' => __('Cel #3', 'uicore-elements')],
158 187 ],
159 188 ]
160 189 );
161 190
@@ -170,60 +199,131 @@
170 199 'tab' => Controls_Manager::TAB_STYLE,
171 200 ]
172 201 );
173 202
174 - //even rows background color
203 + $this->start_controls_tabs(
204 + 'row_tabs'
205 + );
206 +
207 + $this->start_controls_tab(
208 + 'odd_row',
209 + [
210 + 'label' => esc_html__('Odd row', 'textdomain'),
211 + ]
212 + );
213 +
175 214 $this->add_control(
215 + 'odd_row_bg_color',
216 + [
217 + 'label' => __('Row background', 'uicore-elements'),
218 + 'type' => Controls_Manager::COLOR,
219 + 'selectors' => [
220 + '{{WRAPPER}} .ui-e-table > .ui-e-odd' => 'background-color: {{VALUE}};',
221 + ],
222 + ]
223 + );
224 +
225 + $this->add_control(
226 + 'odd_row_padding',
227 + [
228 + 'label' => esc_html__('Row Padding', 'uicore-elements'),
229 + 'type' => Controls_Manager::DIMENSIONS,
230 + 'size_units' => ['px', 'em', 'rem', 'custom'],
231 + 'selectors' => [
232 + "{{WRAPPER}} .ui-e-table > .ui-e-odd" => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
233 + ],
234 + ]
235 + );
236 +
237 + $this->add_control(
238 + 'odd_row_radius',
239 + [
240 + 'label' => esc_html__('Row Border Radius', 'uicore-elements'),
241 + 'type' => Controls_Manager::DIMENSIONS,
242 + 'size_units' => ['px', 'em', 'rem', 'custom'],
243 + 'selectors' => [
244 + "{{WRAPPER}} .ui-e-table > .ui-e-odd.ui-e-first-row-cel" => 'border-radius: {{TOP}}{{UNIT}} 0 0 {{LEFT}}{{UNIT}};',
245 + "{{WRAPPER}} .ui-e-table > .ui-e-odd.ui-e-last-row-cel" => 'border-radius: 0 {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} 0;'
246 + ],
247 + ]
248 + );
249 +
250 + $this->end_controls_tab();
251 +
252 + $this->start_controls_tab(
253 + 'even_row',
254 + [
255 + 'label' => esc_html__('Even row', 'textdomain'),
256 + ]
257 + );
258 +
259 + $this->add_control(
176 260 'even_row_bg_color',
177 261 [
178 - 'label' => __('Even Rows Background', 'uicore-elements'),
262 + 'label' => __('Row background', 'uicore-elements'),
179 263 'type' => Controls_Manager::COLOR,
180 264 'selectors' => [
181 - '{{WRAPPER}} .ui-e-table .ui-e-even' => 'background-color: {{VALUE}};',
265 + '{{WRAPPER}} .ui-e-table > .ui-e-even' => 'background-color: {{VALUE}};',
182 266 ],
183 267 ]
184 268 );
185 269
270 + $this->add_control(
271 + 'even_row_padding',
272 + [
273 + 'label' => esc_html__('Row Padding', 'uicore-elements'),
274 + 'type' => Controls_Manager::DIMENSIONS,
275 + 'size_units' => ['px', 'em', 'rem', 'custom'],
276 + 'selectors' => [
277 + "{{WRAPPER}} .ui-e-table > .ui-e-even" => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
278 + ],
279 + ]
280 + );
186 281
282 + $this->add_control(
283 + 'even_row_radius',
284 + [
285 + 'label' => esc_html__('Row Border Radius', 'uicore-elements'),
286 + 'type' => Controls_Manager::DIMENSIONS,
287 + 'size_units' => ['px', 'em', 'rem', 'custom'],
288 + 'selectors' => [
289 + "{{WRAPPER}} .ui-e-table > .ui-e-even.ui-e-first-row-cel" => 'border-radius: {{TOP}}{{UNIT}} 0 0 {{LEFT}}{{UNIT}};',
290 + "{{WRAPPER}} .ui-e-table > .ui-e-even.ui-e-last-row-cel" => 'border-radius: 0 {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} 0;'
291 + ],
292 + ]
293 + );
294 +
295 + $this->end_controls_tab();
296 +
297 + $this->end_controls_tabs();
298 +
299 +
187 300 $this->end_controls_section();
188 301 }
189 302
190 - public function render()
303 + protected function build_grid_css($cols)
191 304 {
192 - if(!Plugin::$instance->experiments->is_feature_active('nested-elements')) {
193 - $this->nesting_fallback();
194 - return;
195 - }
196 -
197 - $cells = $this->get_settings_for_display('cells');
198 - $cols = $this->get_settings_for_display('columns');
199 -
200 305 // Build the grid columns css
201 306 if ($cols) {
202 -
203 307 $grid_css = '';
204 308 $grid_columns = [];
205 309 $breakpoints = Plugin::$instance->breakpoints->get_active_breakpoints();
206 310
207 - // Columns loop
208 311 foreach ($cols as $index => $item) {
209 312
210 - // Register default desktop size
211 - $grid_columns['desktop'][] = $item['col_size']['size'] . $item['col_size']['unit'];
313 + // Set desktop column size
314 + $grid_columns['desktop'][] = isset($item['col_size']['size']) && isset($item['col_size']['unit'])
315 + ? $item['col_size']['size'] . $item['col_size']['unit']
316 + : '1fr'; // fallback
212 317
213 - // Check for the current column responsive sizes
214 318 foreach ($breakpoints as $breakpoint => $object) {
215 319 $size_slug = 'col_size_' . $breakpoint;
216 320
217 - // Register the current column responsive size if it exists and
218 - // the value is not empty, because empty values will break the table design
219 - if ( isset($item[$size_slug]) && !empty($item[$size_slug]['size']) ) {
220 - $grid_columns[$breakpoint][] = $item[$size_slug]['size'] . $item[$size_slug]['unit'];
221 -
222 - // Use the default size from desktop otherwhise
223 - } else {
224 - $grid_columns[$breakpoint][] = $item['col_size']['size'] . $item['col_size']['unit'];
225 - }
321 + // Register the current column responsive size if exists and the
322 + // value is not empty, because empty values breaks the table design
323 + $grid_columns[$breakpoint][] = isset($item[$size_slug]['size']) && isset($item[$size_slug]['unit'])
324 + ? $item[$size_slug]['size'] . $item[$size_slug]['unit']
325 + : $grid_columns['desktop'][$index];
226 326 }
227 327 }
228 328
229 329 // Generate the css variables
@@ -228,102 +328,137 @@
228 328
229 329 // Generate the css variables
230 330 foreach ($grid_columns as $device => $values) {
231 331 $breakpoint = $device === 'desktop' ? '' : '-' . $device;
232 - $grid_css .= '--ui-e-table-cols' . $breakpoint . ':' . implode(' ', $values) . ';';
332 + $grid_css .= '--ui-e-table-cols' . $breakpoint . ':' . implode(' ', $values) . ';';
233 333 }
234 334
235 - // Add it to the widget wrapper
236 - $this->add_render_attribute('_wrapper', [
237 - 'style' => $grid_css,
238 - ]);
335 + return $grid_css;
239 336 }
337 + }
240 338
241 - ?>
339 + public function render()
340 + {
341 + if (!Plugin::$instance->experiments->is_feature_active('nested-elements')) {
342 + $this->nesting_fallback();
343 + return;
344 + }
345 +
346 + $cells = $this->get_settings_for_display('cells');
347 + $cols = $this->get_settings_for_display('columns');
348 + $grid_css = $this->build_grid_css($cols);
349 +
350 + // Add it to the widget wrapper
351 + $this->add_render_attribute('_wrapper', ['style' => $grid_css]);
352 +
353 +?>
242 354 <div class="ui-e-table">
243 355 <?php
244 356
245 - $columns = count($cols);
357 + $columns = count($cols);
246 358
247 - foreach ($cells as $index => $item) {
248 - $is_even = floor($index / $columns) % 2 !== 0;
359 + foreach ($cells as $index => $item) {
360 + $row_class = floor($index / $columns) % 2 !== 0
361 + ? 'ui-e-even'
362 + : 'ui-e-odd';
249 363
250 - // TODO: maybe there's a way of adding the class to the child wrapper instead of printing an extra element
251 - if ($is_even) {
252 - ?>
253 - <div class="ui-e-even">
254 - <?php $this->print_child($index); ?>
255 - </div>
256 - <?php
257 - } else {
258 - $this->print_child($index);
259 - }
364 + // TODO: in the future experiment a nth-child approach so we don't need this first/last classes
365 + // Add classes to the first and last items of each row
366 + if ($index % $columns === 0) {
367 + $row_class .= ' ui-e-first-row-cel';
368 + } else if (($index + 1) % $columns === 0) {
369 + $row_class .= ' ui-e-last-row-cel';
260 370 }
371 +
372 + $this->print_child($index, ['class' => $row_class]);
373 + }
261 374 ?>
262 375 </div>
263 - <?php
376 + <?php
264 377 }
265 378
379 + public function print_child($index, array $atts = [])
380 + {
381 + $children = $this->get_children();
266 382
267 - protected function get_initial_config(): array {
268 - if (Plugin::$instance->experiments->is_feature_active('e_nested_atomic_repeaters')) {
269 - return array_merge(parent::get_initial_config(), [
270 - 'support_improved_repeaters' => true,
271 - 'node' => '.ui-e-table'
272 - ]);
273 - }
383 + if (! empty($children[$index])) {
274 384
275 - return parent::get_initial_config();
276 - }
385 + // Add custom attributes to each child container.
386 + if (!empty($atts)) {
387 + //$child_settings = $children[ $index ]->get_settings_for_display();
388 + foreach ($atts as $key => $value) {
389 + $children[$index]->add_render_attribute('_wrapper', $key, $value);
390 + }
391 + }
277 392
393 + $children[$index]->print_element();
394 + }
395 + }
278 396
279 - protected function content_template() {
280 - ?>
397 + protected function get_initial_config(): array
398 + {
399 + if (Plugin::$instance->experiments->is_feature_active('e_nested_atomic_repeaters')) {
400 + return array_merge(parent::get_initial_config(), [
401 + 'support_improved_repeaters' => true,
402 + 'node' => '.ui-e-table'
403 + ]);
404 + }
405 +
406 + return parent::get_initial_config();
407 + }
408 +
409 +
410 + protected function content_template()
411 + {
412 + ?>
281 413 <#
282 - const cols = settings.columns;
283 - const cols_qty = '--ui-e-cols-qty:' + settings.columns.length;
414 + const cols=settings.columns || [];
415 + const cells=settings.cells || [];
416 + const cols_qty='--ui-e-cols-qty:' + cols.length;
284 417
285 418 if ( cols ) {
286 - let gridCss = '';
287 - const gridColumns = {};
288 - const breakpoints = elementorFrontend.config.breakpoints.activeBreakpoints;
419 + let gridCss='' ;
420 + const gridColumns={};
421 + const breakpoints=elementorFrontend.config.responsive.activeBreakpoints;
289 422
290 - _.each( cols, function( item, index ) {
423 + _.each( cols, function( item, index ) {
291 424
292 - if ( ! gridColumns.desktop ) {
293 - gridColumns.desktop = [];
294 - }
425 + if ( ! gridColumns.desktop ) {
426 + gridColumns.desktop=[];
427 + }
295 428
296 - gridColumns.desktop.push( item.col_size.size + item.col_size.unit );
429 + gridColumns.desktop.push( item.col_size.size + item.col_size.unit );
297 430
298 - _.each( breakpoints, function( object, breakpoint ) {
299 - const sizeSlug = 'col_size_' + breakpoint;
431 + _.each( breakpoints, function( object, breakpoint ) {
432 + const sizeSlug='col_size_' + breakpoint;
300 433
301 - if ( item[sizeSlug] && item[sizeSlug].size ) {
302 - if ( ! gridColumns[breakpoint] ) {
303 - gridColumns[breakpoint] = [];
304 - }
305 - gridColumns[breakpoint].push( item[sizeSlug].size + item[sizeSlug].unit );
306 - } else {
307 - if ( ! gridColumns[breakpoint] ) {
308 - gridColumns[breakpoint] = [];
309 - }
310 - gridColumns[breakpoint].push( item.col_size.size + item.col_size.unit );
311 - }
312 - });
313 - });
434 + if ( item[sizeSlug] && item[sizeSlug].size ) {
435 + if ( ! gridColumns[breakpoint] ) {
436 + gridColumns[breakpoint]=[];
437 + }
438 + gridColumns[breakpoint].push( item[sizeSlug].size + item[sizeSlug].unit );
439 + } else {
440 + if ( ! gridColumns[breakpoint] ) {
441 + gridColumns[breakpoint]=[];
442 + }
443 + gridColumns[breakpoint].push( item.col_size.size + item.col_size.unit );
444 + }
445 + });
446 + });
314 447
315 - _.each( gridColumns, function( values, device ) {
316 - const breakpoint = device === 'desktop' ? '' : '-' + device;
317 - gridCss += '--ui-e-table-cols' + breakpoint + ':' + values.join(' ') + ';';
318 - });
448 + _.each( gridColumns, function( values, device ) {
449 + const breakpoint=device==='desktop' ? '' : '-' + device;
450 + gridCss +='--ui-e-table-cols' + breakpoint + ':' + values.join(' ') + ' ;';
451 + });
319 452
320 - view.addRenderAttribute('table', 'style', [gridCss, cols_qty].join(' '));
453 + view.addRenderAttribute('table', 'data-cell-count' , cells.length);
454 + view.addRenderAttribute('table', 'style' , [gridCss, cols_qty].join(' '));
321 455 }
322 - #>
323 - <div class="ui-e-table" {{{ view.getRenderAttributeString('table') }}}>
456 + #>
457 + <div class="ui-e-table" {{{ view.getRenderAttributeString('table') }}}>
324 458
325 - </div>
326 - <?php
459 + </div>
460 + <div class="ui-e-table-editor-placeholder"></div>
461 + <?php
327 462 }
328 463 }
329 -\Elementor\Plugin::instance()->widgets_manager->register(new CustomTable());
464 +\Elementor\Plugin::instance()->widgets_manager->register(new CustomTable());