PluginProbe
Elementor Website Builder – more than just a page builder / 4.2.4
Elementor Website Builder – more than just a page builder v4.2.4
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / includes / widgets / text-editor.php

text-editor.php in Elementor Website Builder – more than just a page builder 4.2.4, at includes/widgets/text-editor.php

677 lines 15.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit; // Exit if accessed directly.
6 }
7
8 use Elementor\Core\Kits\Documents\Tabs\Global_Colors;
9 use Elementor\Core\Kits\Documents\Tabs\Global_Typography;
10
11 /**
12 * Elementor text editor widget.
13 *
14 * Elementor widget that displays a WYSIWYG text editor, just like the WordPress
15 * editor.
16 *
17 * @since 1.0.0
18 */
19 class Widget_Text_Editor extends Widget_Base {
20
21 /**
22 * Get widget name.
23 *
24 * Retrieve text editor widget name.
25 *
26 * @since 1.0.0
27 * @access public
28 *
29 * @return string Widget name.
30 */
31 public function get_name() {
32 return 'text-editor';
33 }
34
35 /**
36 * Get widget title.
37 *
38 * Retrieve text editor widget title.
39 *
40 * @since 1.0.0
41 * @access public
42 *
43 * @return string Widget title.
44 */
45 public function get_title() {
46 return esc_html__( 'Text Editor', 'elementor' );
47 }
48
49 /**
50 * Get widget icon.
51 *
52 * Retrieve text editor widget icon.
53 *
54 * @since 1.0.0
55 * @access public
56 *
57 * @return string Widget icon.
58 */
59 public function get_icon() {
60 return 'eicon-text';
61 }
62
63 /**
64 * Get widget categories.
65 *
66 * Retrieve the list of categories the text editor widget belongs to.
67 *
68 * Used to determine where to display the widget in the editor.
69 *
70 * @since 2.0.0
71 * @access public
72 *
73 * @return array Widget categories.
74 */
75 public function get_categories() {
76 return [ 'basic' ];
77 }
78
79 /**
80 * Get widget keywords.
81 *
82 * Retrieve the list of keywords the widget belongs to.
83 *
84 * @since 2.1.0
85 * @access public
86 *
87 * @return array Widget keywords.
88 */
89 public function get_keywords() {
90 return [ 'text', 'editor' ];
91 }
92
93 /**
94 * Get style dependencies.
95 *
96 * Retrieve the list of style dependencies the widget requires.
97 *
98 * The 'widget-text-editor' style is required only when the drop cap is used.
99 * Therefor, style should not be loaded on the widget level, rather only on
100 * control level when the drop cap is active.
101 *
102 * Only in the Editor, these style should be loaded on the widget level.
103 *
104 * @since 3.24.0
105 * @access public
106 *
107 * @return array Widget style dependencies.
108 */
109 public function get_style_depends(): array {
110 $style_dependencies = Plugin::$instance->editor->is_edit_mode() || Plugin::$instance->preview->is_preview_mode()
111 ? [ 'widget-text-editor' ]
112 : [];
113
114 return $style_dependencies;
115 }
116
117 public function has_widget_inner_wrapper(): bool {
118 return ! Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' );
119 }
120
121 /**
122 * Register text editor widget controls.
123 *
124 * Adds different input fields to allow the user to change and customize the widget settings.
125 *
126 * @since 3.1.0
127 * @access protected
128 */
129 protected function register_controls() {
130 $this->start_controls_section(
131 'section_editor',
132 [
133 'label' => esc_html__( 'Text Editor', 'elementor' ),
134 ]
135 );
136
137 $this->add_control(
138 'editor',
139 [
140 'label' => '',
141 'type' => Controls_Manager::WYSIWYG,
142 'default' => '<p>' . esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor' ) . '</p>',
143 ]
144 );
145
146 $this->add_control(
147 'drop_cap', [
148 'label' => esc_html__( 'Drop Cap', 'elementor' ),
149 'type' => Controls_Manager::SWITCHER,
150 'label_off' => esc_html__( 'Off', 'elementor' ),
151 'label_on' => esc_html__( 'On', 'elementor' ),
152 'prefix_class' => 'elementor-drop-cap-',
153 'frontend_available' => true,
154 'assets' => [
155 'styles' => [
156 [
157 'name' => 'widget-text-editor',
158 'conditions' => [
159 'terms' => [
160 [
161 'name' => 'drop_cap',
162 'operator' => '===',
163 'value' => 'yes',
164 ],
165 ],
166 ],
167 ],
168 ],
169
170 ],
171 ]
172 );
173
174 $this->add_responsive_control(
175 'text_columns',
176 [
177 'label' => esc_html__( 'Columns', 'elementor' ),
178 'type' => Controls_Manager::SELECT,
179 'separator' => 'before',
180 'options' => [
181 '' => esc_html__( 'Default', 'elementor' ),
182 '1' => esc_html__( '1', 'elementor' ),
183 '2' => esc_html__( '2', 'elementor' ),
184 '3' => esc_html__( '3', 'elementor' ),
185 '4' => esc_html__( '4', 'elementor' ),
186 '5' => esc_html__( '5', 'elementor' ),
187 '6' => esc_html__( '6', 'elementor' ),
188 '7' => esc_html__( '7', 'elementor' ),
189 '8' => esc_html__( '8', 'elementor' ),
190 '9' => esc_html__( '9', 'elementor' ),
191 '10' => esc_html__( '10', 'elementor' ),
192 ],
193 'selectors' => [
194 '{{WRAPPER}}' => 'columns: {{VALUE}};',
195 ],
196 ]
197 );
198
199 $this->add_responsive_control(
200 'column_gap',
201 [
202 'label' => esc_html__( 'Columns Gap', 'elementor' ),
203 'type' => Controls_Manager::SLIDER,
204 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
205 'range' => [
206 'px' => [
207 'max' => 100,
208 ],
209 '%' => [
210 'max' => 10,
211 'step' => 0.1,
212 ],
213 'vw' => [
214 'max' => 10,
215 'step' => 0.1,
216 ],
217 'em' => [
218 'max' => 10,
219 ],
220 'rem' => [
221 'max' => 10,
222 ],
223 ],
224 'selectors' => [
225 '{{WRAPPER}}' => 'column-gap: {{SIZE}}{{UNIT}};',
226 ],
227 'conditions' => [
228 'relation' => 'or',
229 'terms' => [
230 [
231 'name' => 'text_columns',
232 'operator' => '>',
233 'value' => 1,
234 ],
235 [
236 'name' => 'text_columns',
237 'operator' => '===',
238 'value' => '',
239 ],
240 ],
241 ],
242 ]
243 );
244
245 $this->end_controls_section();
246
247 $this->start_controls_section(
248 'section_style',
249 [
250 'label' => esc_html__( 'Text Editor', 'elementor' ),
251 'tab' => Controls_Manager::TAB_STYLE,
252 ]
253 );
254
255 $this->add_responsive_control(
256 'align',
257 [
258 'label' => esc_html__( 'Alignment', 'elementor' ),
259 'type' => Controls_Manager::CHOOSE,
260 'options' => [
261 'start' => [
262 'title' => esc_html__( 'Start', 'elementor' ),
263 'icon' => 'eicon-text-align-left',
264 ],
265 'center' => [
266 'title' => esc_html__( 'Center', 'elementor' ),
267 'icon' => 'eicon-text-align-center',
268 ],
269 'end' => [
270 'title' => esc_html__( 'End', 'elementor' ),
271 'icon' => 'eicon-text-align-right',
272 ],
273 'justify' => [
274 'title' => esc_html__( 'Justified', 'elementor' ),
275 'icon' => 'eicon-text-align-justify',
276 ],
277 ],
278 'classes' => 'elementor-control-start-end',
279 'selectors_dictionary' => [
280 'left' => is_rtl() ? 'end' : 'start',
281 'right' => is_rtl() ? 'start' : 'end',
282 ],
283 'selectors' => [
284 '{{WRAPPER}}' => 'text-align: {{VALUE}};',
285 ],
286 'separator' => 'after',
287 ]
288 );
289
290 $this->add_group_control(
291 Group_Control_Typography::get_type(),
292 [
293 'name' => 'typography',
294 'global' => [
295 'default' => Global_Typography::TYPOGRAPHY_TEXT,
296 ],
297 ]
298 );
299
300 $this->add_group_control(
301 Group_Control_Text_Shadow::get_type(),
302 [
303 'name' => 'text_shadow',
304 'selector' => '{{WRAPPER}}',
305 ]
306 );
307
308 $this->add_responsive_control(
309 'paragraph_spacing',
310 [
311 'label' => esc_html__( 'Paragraph Spacing', 'elementor' ),
312 'type' => Controls_Manager::SLIDER,
313 'size_units' => [ 'px', 'em', 'rem', 'vh', 'custom' ],
314 'range' => [
315 'px' => [
316 'max' => 100,
317 ],
318 'em' => [
319 'min' => 0.1,
320 'max' => 20,
321 ],
322 ],
323 'selectors' => [
324 '{{WRAPPER}} p' => 'margin-block-end: {{SIZE}}{{UNIT}}',
325 ],
326 ]
327 );
328
329 $this->add_control(
330 'separator',
331 [
332 'type' => Controls_Manager::DIVIDER,
333 ]
334 );
335
336 $this->start_controls_tabs( 'link_colors' );
337
338 $this->start_controls_tab(
339 'colors_normal',
340 [
341 'label' => esc_html__( 'Normal', 'elementor' ),
342 ]
343 );
344
345 $this->add_control(
346 'text_color',
347 [
348 'label' => esc_html__( 'Text Color', 'elementor' ),
349 'type' => Controls_Manager::COLOR,
350 'default' => '',
351 'selectors' => [
352 '{{WRAPPER}}' => 'color: {{VALUE}};',
353 ],
354 'global' => [
355 'default' => Global_Colors::COLOR_TEXT,
356 ],
357 ]
358 );
359
360 $this->add_control(
361 'link_color',
362 [
363 'label' => esc_html__( 'Link Color', 'elementor' ),
364 'type' => Controls_Manager::COLOR,
365 'selectors' => [
366 '{{WRAPPER}} a' => 'color: {{VALUE}};',
367 ],
368 ]
369 );
370
371 $this->end_controls_tab();
372
373 $this->start_controls_tab(
374 'colors_hover',
375 [
376 'label' => esc_html__( 'Hover', 'elementor' ),
377 ]
378 );
379
380 $this->add_control(
381 'link_hover_color',
382 [
383 'label' => esc_html__( 'Link Color', 'elementor' ),
384 'type' => Controls_Manager::COLOR,
385 'selectors' => [
386 '{{WRAPPER}} a:hover, {{WRAPPER}} a:focus' => 'color: {{VALUE}};',
387 ],
388 ]
389 );
390
391 $this->add_control(
392 'link_hover_color_transition_duration',
393 [
394 'label' => esc_html__( 'Transition Duration', 'elementor' ),
395 'type' => Controls_Manager::SLIDER,
396 'size_units' => [ 's', 'ms', 'custom' ],
397 'default' => [
398 'unit' => 's',
399 ],
400 'selectors' => [
401 '{{WRAPPER}} a' => 'transition-duration: {{SIZE}}{{UNIT}};',
402 ],
403 ]
404 );
405
406 $this->end_controls_tab();
407
408 $this->end_controls_tabs();
409
410 $this->end_controls_section();
411
412 $this->start_controls_section(
413 'section_drop_cap',
414 [
415 'label' => esc_html__( 'Drop Cap', 'elementor' ),
416 'tab' => Controls_Manager::TAB_STYLE,
417 'condition' => [
418 'drop_cap' => 'yes',
419 ],
420 ]
421 );
422
423 $this->add_control(
424 'drop_cap_view',
425 [
426 'label' => esc_html__( 'View', 'elementor' ),
427 'type' => Controls_Manager::SELECT,
428 'options' => [
429 'default' => esc_html__( 'Default', 'elementor' ),
430 'stacked' => esc_html__( 'Stacked', 'elementor' ),
431 'framed' => esc_html__( 'Framed', 'elementor' ),
432 ],
433 'default' => 'default',
434 'prefix_class' => 'elementor-drop-cap-view-',
435 ]
436 );
437
438 $this->add_control(
439 'drop_cap_primary_color',
440 [
441 'label' => esc_html__( 'Primary Color', 'elementor' ),
442 'type' => Controls_Manager::COLOR,
443 'selectors' => [
444 '{{WRAPPER}}.elementor-drop-cap-view-stacked .elementor-drop-cap' => 'background-color: {{VALUE}};',
445 '{{WRAPPER}}.elementor-drop-cap-view-framed .elementor-drop-cap, {{WRAPPER}}.elementor-drop-cap-view-default .elementor-drop-cap' => 'color: {{VALUE}}; border-color: {{VALUE}};',
446 ],
447 'global' => [
448 'default' => Global_Colors::COLOR_PRIMARY,
449 ],
450 ]
451 );
452
453 $this->add_control(
454 'drop_cap_secondary_color',
455 [
456 'label' => esc_html__( 'Secondary Color', 'elementor' ),
457 'type' => Controls_Manager::COLOR,
458 'selectors' => [
459 '{{WRAPPER}}.elementor-drop-cap-view-framed .elementor-drop-cap' => 'background-color: {{VALUE}};',
460 '{{WRAPPER}}.elementor-drop-cap-view-stacked .elementor-drop-cap' => 'color: {{VALUE}};',
461 ],
462 'condition' => [
463 'drop_cap_view!' => 'default',
464 ],
465 ]
466 );
467
468 $this->add_group_control(
469 Group_Control_Text_Shadow::get_type(),
470 [
471 'name' => 'drop_cap_shadow',
472 'selector' => '{{WRAPPER}} .elementor-drop-cap',
473 ]
474 );
475
476 $this->add_control(
477 'drop_cap_size',
478 [
479 'label' => esc_html__( 'Size', 'elementor' ),
480 'type' => Controls_Manager::SLIDER,
481 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
482 'default' => [
483 'size' => 5,
484 ],
485 'range' => [
486 'px' => [
487 'max' => 30,
488 ],
489 'em' => [
490 'max' => 3,
491 ],
492 'rem' => [
493 'max' => 3,
494 ],
495 ],
496 'selectors' => [
497 '{{WRAPPER}} .elementor-drop-cap' => 'padding: {{SIZE}}{{UNIT}};',
498 ],
499 'condition' => [
500 'drop_cap_view!' => 'default',
501 ],
502 ]
503 );
504
505 $this->add_control(
506 'drop_cap_space',
507 [
508 'label' => esc_html__( 'Space', 'elementor' ),
509 'type' => Controls_Manager::SLIDER,
510 'size_units' => [ 'px', 'em', 'rem', 'custom' ],
511 'default' => [
512 'size' => 10,
513 ],
514 'range' => [
515 'px' => [
516 'max' => 50,
517 ],
518 'em' => [
519 'max' => 5,
520 ],
521 'rem' => [
522 'max' => 5,
523 ],
524 ],
525 'selectors' => [
526 '{{WRAPPER}} .elementor-drop-cap' => 'margin-inline-end: {{SIZE}}{{UNIT}};',
527 ],
528 ]
529 );
530
531 $this->add_control(
532 'drop_cap_border_radius',
533 [
534 'label' => esc_html__( 'Border Radius', 'elementor' ),
535 'type' => Controls_Manager::SLIDER,
536 'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
537 'default' => [
538 'unit' => '%',
539 ],
540 'range' => [
541 '%' => [
542 'max' => 50,
543 ],
544 ],
545 'selectors' => [
546 '{{WRAPPER}} .elementor-drop-cap' => 'border-radius: {{SIZE}}{{UNIT}};',
547 ],
548 'condition' => [
549 'drop_cap_view!' => 'default',
550 ],
551 ]
552 );
553
554 $this->add_control(
555 'drop_cap_border_width', [
556 'label' => esc_html__( 'Border Width', 'elementor' ),
557 'type' => Controls_Manager::DIMENSIONS,
558 'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
559 'selectors' => [
560 '{{WRAPPER}} .elementor-drop-cap' => 'border-width: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
561 ],
562 'condition' => [
563 'drop_cap_view' => 'framed',
564 ],
565 ]
566 );
567
568 $this->add_group_control(
569 Group_Control_Typography::get_type(),
570 [
571 'name' => 'drop_cap_typography',
572 'selector' => '{{WRAPPER}} .elementor-drop-cap-letter',
573 'exclude' => [
574 'letter_spacing',
575 ],
576 ]
577 );
578
579 $this->end_controls_section();
580 }
581
582 /**
583 * Render text editor widget output on the frontend.
584 *
585 * Written in PHP and used to generate the final HTML.
586 *
587 * @since 1.0.0
588 * @access protected
589 */
590 protected function render() {
591 $should_render_inline_editing = Plugin::$instance->editor->is_edit_mode();
592
593 $editor_content = $this->get_settings_for_display( 'editor' );
594 $editor_content = $this->parse_text_editor( $editor_content );
595
596 if ( empty( $editor_content ) ) {
597 return;
598 }
599
600 if ( $should_render_inline_editing ) {
601 $this->add_render_attribute( 'editor', 'class', [ 'elementor-text-editor', 'elementor-clearfix' ] );
602 }
603
604 $this->add_inline_editing_attributes( 'editor', 'advanced' );
605 ?>
606 <?php if ( $should_render_inline_editing ) { ?>
607 <div <?php $this->print_render_attribute_string( 'editor' ); ?>>
608 <?php } ?>
609 <?php // PHPCS - DO NOT REMOVE THIS ECHO - THE MAIN TEXT OF A WIDGET SHOULD NOT BE ESCAPED!
610 echo $editor_content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
611 ?>
612 <?php if ( $should_render_inline_editing ) { ?>
613 </div>
614 <?php } ?>
615 <?php
616 }
617
618 /**
619 * Render text editor widget as plain content.
620 *
621 * Override the default behavior by printing the content without rendering it.
622 *
623 * @since 1.0.0
624 * @access public
625 */
626 public function render_plain_content() {
627 // In plain mode, render without shortcode
628 $this->print_unescaped_setting( 'editor' );
629 }
630
631 /**
632 * Render text editor widget output in the editor.
633 *
634 * Written as a Backbone JavaScript template and used to generate the live preview.
635 *
636 * @since 2.9.0
637 * @access protected
638 */
639 public function render_markdown(): string {
640 $editor_content = $this->get_settings_for_display( 'editor' );
641 $editor_content = $this->parse_text_editor( $editor_content );
642
643 if ( empty( $editor_content ) ) {
644 return '';
645 }
646
647 return \Elementor\Modules\MarkdownRender\Html_To_Markdown::convert( $editor_content );
648 }
649
650 protected function content_template() {
651 ?>
652 <#
653 if ( '' === settings.editor ) {
654 return;
655 }
656
657 const shouldRenderInlineEditing = elementorFrontend.isEditMode();
658
659 if ( shouldRenderInlineEditing ) {
660 view.addRenderAttribute( 'editor', 'class', [ 'elementor-text-editor', 'elementor-clearfix' ] );
661 }
662
663 view.addInlineEditingAttributes( 'editor', 'advanced' );
664
665 if ( shouldRenderInlineEditing ) { #>
666 <div {{{ view.getRenderAttributeString( 'editor' ) }}}>
667 <# } #>
668
669 {{{ settings.editor }}}
670
671 <# if ( shouldRenderInlineEditing ) { #>
672 </div>
673 <# } #>
674 <?php
675 }
676 }
677