text-editor.php (11392B)
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 * Register text editor widget controls. 95 * 96 * Adds different input fields to allow the user to change and customize the widget settings. 97 * 98 * @since 3.1.0 99 * @access protected 100 */ 101 protected function register_controls() { 102 $this->start_controls_section( 103 'section_editor', 104 [ 105 'label' => esc_html__( 'Text Editor', 'elementor' ), 106 ] 107 ); 108 109 $this->add_control( 110 'editor', 111 [ 112 'label' => '', 113 'type' => Controls_Manager::WYSIWYG, 114 'default' => '<p>' . esc_html__( 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.', 'elementor' ) . '</p>', 115 ] 116 ); 117 118 $this->add_control( 119 'drop_cap', [ 120 'label' => esc_html__( 'Drop Cap', 'elementor' ), 121 'type' => Controls_Manager::SWITCHER, 122 'label_off' => esc_html__( 'Off', 'elementor' ), 123 'label_on' => esc_html__( 'On', 'elementor' ), 124 'prefix_class' => 'elementor-drop-cap-', 125 'frontend_available' => true, 126 ] 127 ); 128 129 $text_columns = range( 1, 10 ); 130 $text_columns = array_combine( $text_columns, $text_columns ); 131 $text_columns[''] = esc_html__( 'Default', 'elementor' ); 132 133 $this->add_responsive_control( 134 'text_columns', 135 [ 136 'label' => esc_html__( 'Columns', 'elementor' ), 137 'type' => Controls_Manager::SELECT, 138 'separator' => 'before', 139 'options' => $text_columns, 140 'selectors' => [ 141 '{{WRAPPER}}' => 'columns: {{VALUE}};', 142 ], 143 ] 144 ); 145 146 $this->add_responsive_control( 147 'column_gap', 148 [ 149 'label' => esc_html__( 'Columns Gap', 'elementor' ), 150 'type' => Controls_Manager::SLIDER, 151 'size_units' => [ 'px', '%', 'em', 'vw' ], 152 'range' => [ 153 'px' => [ 154 'max' => 100, 155 ], 156 '%' => [ 157 'max' => 10, 158 'step' => 0.1, 159 ], 160 'vw' => [ 161 'max' => 10, 162 'step' => 0.1, 163 ], 164 'em' => [ 165 'max' => 10, 166 'step' => 0.1, 167 ], 168 ], 169 'selectors' => [ 170 '{{WRAPPER}}' => 'column-gap: {{SIZE}}{{UNIT}};', 171 ], 172 ] 173 ); 174 175 $this->end_controls_section(); 176 177 $this->start_controls_section( 178 'section_style', 179 [ 180 'label' => esc_html__( 'Text Editor', 'elementor' ), 181 'tab' => Controls_Manager::TAB_STYLE, 182 ] 183 ); 184 185 $this->add_responsive_control( 186 'align', 187 [ 188 'label' => esc_html__( 'Alignment', 'elementor' ), 189 'type' => Controls_Manager::CHOOSE, 190 'options' => [ 191 'left' => [ 192 'title' => esc_html__( 'Left', 'elementor' ), 193 'icon' => 'eicon-text-align-left', 194 ], 195 'center' => [ 196 'title' => esc_html__( 'Center', 'elementor' ), 197 'icon' => 'eicon-text-align-center', 198 ], 199 'right' => [ 200 'title' => esc_html__( 'Right', 'elementor' ), 201 'icon' => 'eicon-text-align-right', 202 ], 203 'justify' => [ 204 'title' => esc_html__( 'Justified', 'elementor' ), 205 'icon' => 'eicon-text-align-justify', 206 ], 207 ], 208 'selectors' => [ 209 '{{WRAPPER}}' => 'text-align: {{VALUE}};', 210 ], 211 ] 212 ); 213 214 $this->add_control( 215 'text_color', 216 [ 217 'label' => esc_html__( 'Text Color', 'elementor' ), 218 'type' => Controls_Manager::COLOR, 219 'default' => '', 220 'selectors' => [ 221 '{{WRAPPER}}' => 'color: {{VALUE}};', 222 ], 223 'global' => [ 224 'default' => Global_Colors::COLOR_TEXT, 225 ], 226 ] 227 ); 228 229 $this->add_group_control( 230 Group_Control_Typography::get_type(), 231 [ 232 'name' => 'typography', 233 'global' => [ 234 'default' => Global_Typography::TYPOGRAPHY_TEXT, 235 ], 236 ] 237 ); 238 239 $this->add_group_control( 240 Group_Control_Text_Shadow::get_type(), 241 [ 242 'name' => 'text_shadow', 243 'selector' => '{{WRAPPER}}', 244 ] 245 ); 246 247 $this->end_controls_section(); 248 249 $this->start_controls_section( 250 'section_drop_cap', 251 [ 252 'label' => esc_html__( 'Drop Cap', 'elementor' ), 253 'tab' => Controls_Manager::TAB_STYLE, 254 'condition' => [ 255 'drop_cap' => 'yes', 256 ], 257 ] 258 ); 259 260 $this->add_control( 261 'drop_cap_view', 262 [ 263 'label' => esc_html__( 'View', 'elementor' ), 264 'type' => Controls_Manager::SELECT, 265 'options' => [ 266 'default' => esc_html__( 'Default', 'elementor' ), 267 'stacked' => esc_html__( 'Stacked', 'elementor' ), 268 'framed' => esc_html__( 'Framed', 'elementor' ), 269 ], 270 'default' => 'default', 271 'prefix_class' => 'elementor-drop-cap-view-', 272 ] 273 ); 274 275 $this->add_control( 276 'drop_cap_primary_color', 277 [ 278 'label' => esc_html__( 'Primary Color', 'elementor' ), 279 'type' => Controls_Manager::COLOR, 280 'selectors' => [ 281 '{{WRAPPER}}.elementor-drop-cap-view-stacked .elementor-drop-cap' => 'background-color: {{VALUE}};', 282 '{{WRAPPER}}.elementor-drop-cap-view-framed .elementor-drop-cap, {{WRAPPER}}.elementor-drop-cap-view-default .elementor-drop-cap' => 'color: {{VALUE}}; border-color: {{VALUE}};', 283 ], 284 'global' => [ 285 'default' => Global_Colors::COLOR_PRIMARY, 286 ], 287 ] 288 ); 289 290 $this->add_control( 291 'drop_cap_secondary_color', 292 [ 293 'label' => esc_html__( 'Secondary Color', 'elementor' ), 294 'type' => Controls_Manager::COLOR, 295 'selectors' => [ 296 '{{WRAPPER}}.elementor-drop-cap-view-framed .elementor-drop-cap' => 'background-color: {{VALUE}};', 297 '{{WRAPPER}}.elementor-drop-cap-view-stacked .elementor-drop-cap' => 'color: {{VALUE}};', 298 ], 299 'condition' => [ 300 'drop_cap_view!' => 'default', 301 ], 302 ] 303 ); 304 305 $this->add_group_control( 306 Group_Control_Text_Shadow::get_type(), 307 [ 308 'name' => 'drop_cap_shadow', 309 'selector' => '{{WRAPPER}} .elementor-drop-cap', 310 ] 311 ); 312 313 $this->add_control( 314 'drop_cap_size', 315 [ 316 'label' => esc_html__( 'Size', 'elementor' ), 317 'type' => Controls_Manager::SLIDER, 318 'default' => [ 319 'size' => 5, 320 ], 321 'range' => [ 322 'px' => [ 323 'max' => 30, 324 ], 325 ], 326 'selectors' => [ 327 '{{WRAPPER}} .elementor-drop-cap' => 'padding: {{SIZE}}{{UNIT}};', 328 ], 329 'condition' => [ 330 'drop_cap_view!' => 'default', 331 ], 332 ] 333 ); 334 335 $this->add_control( 336 'drop_cap_space', 337 [ 338 'label' => esc_html__( 'Space', 'elementor' ), 339 'type' => Controls_Manager::SLIDER, 340 'default' => [ 341 'size' => 10, 342 ], 343 'range' => [ 344 'px' => [ 345 'max' => 50, 346 ], 347 ], 348 'selectors' => [ 349 'body:not(.rtl) {{WRAPPER}} .elementor-drop-cap' => 'margin-right: {{SIZE}}{{UNIT}};', 350 'body.rtl {{WRAPPER}} .elementor-drop-cap' => 'margin-left: {{SIZE}}{{UNIT}};', 351 ], 352 ] 353 ); 354 355 $this->add_control( 356 'drop_cap_border_radius', 357 [ 358 'label' => esc_html__( 'Border Radius', 'elementor' ), 359 'type' => Controls_Manager::SLIDER, 360 'size_units' => [ '%', 'px' ], 361 'default' => [ 362 'unit' => '%', 363 ], 364 'range' => [ 365 '%' => [ 366 'max' => 50, 367 ], 368 ], 369 'selectors' => [ 370 '{{WRAPPER}} .elementor-drop-cap' => 'border-radius: {{SIZE}}{{UNIT}};', 371 ], 372 ] 373 ); 374 375 $this->add_control( 376 'drop_cap_border_width', [ 377 'label' => esc_html__( 'Border Width', 'elementor' ), 378 'type' => Controls_Manager::DIMENSIONS, 379 'selectors' => [ 380 '{{WRAPPER}} .elementor-drop-cap' => 'border-width: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', 381 ], 382 'condition' => [ 383 'drop_cap_view' => 'framed', 384 ], 385 ] 386 ); 387 388 $this->add_group_control( 389 Group_Control_Typography::get_type(), 390 [ 391 'name' => 'drop_cap_typography', 392 'selector' => '{{WRAPPER}} .elementor-drop-cap-letter', 393 'exclude' => [ 394 'letter_spacing', 395 ], 396 ] 397 ); 398 399 $this->end_controls_section(); 400 } 401 402 /** 403 * Render text editor widget output on the frontend. 404 * 405 * Written in PHP and used to generate the final HTML. 406 * 407 * @since 1.0.0 408 * @access protected 409 */ 410 protected function render() { 411 $is_dom_optimized = Plugin::$instance->experiments->is_feature_active( 'e_dom_optimization' ); 412 $is_edit_mode = Plugin::$instance->editor->is_edit_mode(); 413 $should_render_inline_editing = ( ! $is_dom_optimized || $is_edit_mode ); 414 415 $editor_content = $this->get_settings_for_display( 'editor' ); 416 $editor_content = $this->parse_text_editor( $editor_content ); 417 418 if ( $should_render_inline_editing ) { 419 $this->add_render_attribute( 'editor', 'class', [ 'elementor-text-editor', 'elementor-clearfix' ] ); 420 } 421 422 $this->add_inline_editing_attributes( 'editor', 'advanced' ); 423 ?> 424 <?php if ( $should_render_inline_editing ) { ?> 425 <div <?php $this->print_render_attribute_string( 'editor' ); ?>> 426 <?php } ?> 427 <?php // PHPCS - the main text of a widget should not be escaped. 428 echo $editor_content; // phpcs:ignore WordPress.Security.EscapeOutput ?> 429 <?php if ( $should_render_inline_editing ) { ?> 430 </div> 431 <?php } ?> 432 <?php 433 } 434 435 /** 436 * Render text editor widget as plain content. 437 * 438 * Override the default behavior by printing the content without rendering it. 439 * 440 * @since 1.0.0 441 * @access public 442 */ 443 public function render_plain_content() { 444 // In plain mode, render without shortcode 445 $this->print_unescaped_setting( 'editor' ); 446 } 447 448 /** 449 * Render text editor widget output in the editor. 450 * 451 * Written as a Backbone JavaScript template and used to generate the live preview. 452 * 453 * @since 2.9.0 454 * @access protected 455 */ 456 protected function content_template() { 457 ?> 458 <# 459 const isDomOptimized = ! ! elementorFrontend.config.experimentalFeatures.e_dom_optimization, 460 isEditMode = elementorFrontend.isEditMode(), 461 shouldRenderInlineEditing = ( ! isDomOptimized || isEditMode ); 462 463 if ( shouldRenderInlineEditing ) { 464 view.addRenderAttribute( 'editor', 'class', [ 'elementor-text-editor', 'elementor-clearfix' ] ); 465 } 466 467 view.addInlineEditingAttributes( 'editor', 'advanced' ); 468 469 if ( shouldRenderInlineEditing ) { #> 470 <div {{{ view.getRenderAttributeString( 'editor' ) }}}> 471 <# } #> 472 473 {{{ settings.editor }}} 474 475 <# if ( shouldRenderInlineEditing ) { #> 476 </div> 477 <# } #> 478 <?php 479 } 480 }