~canonical-sysadmins/wordpress/4.9.1

« back to all changes in this revision

Viewing changes to wp-includes/class-wp-editor.php

  • Committer: Barry Price
  • Date: 2017-06-09 02:09:58 UTC
  • mfrom: (1.1.26 upstream)
  • Revision ID: barry.price@canonical.com-20170609020958-838whhwt2196f2vk
Merge WP4.8 from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
        private static $drag_drop_upload = false;
28
28
        private static $old_dfw_compat = false;
29
29
        private static $translation;
 
30
        private static $tinymce_scripts_printed = false;
 
31
        private static $link_dialog_printed = false;
30
32
 
31
33
        private function __construct() {}
32
34
 
350
352
                if ( self::$this_tinymce ) {
351
353
 
352
354
                        if ( empty( self::$first_init ) ) {
353
 
                                self::$baseurl = includes_url( 'js/tinymce' );
354
 
 
355
 
                                $mce_locale = get_user_locale();
356
 
                                self::$mce_locale = $mce_locale = empty( $mce_locale ) ? 'en' : strtolower( substr( $mce_locale, 0, 2 ) ); // ISO 639-1
357
 
 
358
 
                                /** This filter is documented in wp-admin/includes/media.php */
359
 
                                $no_captions = (bool) apply_filters( 'disable_captions', '' );
 
355
                                $baseurl = self::get_baseurl();
 
356
                                $mce_locale = self::get_mce_locale();
360
357
                                $ext_plugins = '';
361
 
                                $shortcut_labels = array();
362
 
 
363
 
                                foreach ( self::get_translation() as $name => $value ) {
364
 
                                        if ( is_array( $value ) ) {
365
 
                                                $shortcut_labels[$name] = $value[1];
366
 
                                        }
367
 
                                }
368
358
 
369
359
                                if ( $set['teeny'] ) {
370
360
 
376
366
                                         * @param array  $plugins   An array of teenyMCE plugins.
377
367
                                         * @param string $editor_id Unique editor identifier, e.g. 'content'.
378
368
                                         */
379
 
                                        self::$plugins = $plugins = apply_filters( 'teeny_mce_plugins', array( 'colorpicker', 'lists', 'fullscreen', 'image', 'wordpress', 'wpeditimage', 'wplink' ), $editor_id );
 
369
                                        $plugins = apply_filters( 'teeny_mce_plugins', array( 'colorpicker', 'lists', 'fullscreen', 'image', 'wordpress', 'wpeditimage', 'wplink' ), $editor_id );
380
370
                                } else {
381
371
 
382
372
                                        /**
417
407
                                                'wpdialogs',
418
408
                                                'wptextpattern',
419
409
                                                'wpview',
420
 
                                                'wpembed',
421
410
                                        );
422
411
 
423
412
                                        if ( ! self::$has_medialib ) {
522
511
                                self::$plugins = $plugins;
523
512
                                self::$ext_plugins = $ext_plugins;
524
513
 
525
 
                                self::$first_init = array(
526
 
                                        'theme' => 'modern',
527
 
                                        'skin' => 'lightgray',
528
 
                                        'language' => self::$mce_locale,
529
 
                                        'formats' => '{' .
530
 
                                                'alignleft: [' .
531
 
                                                        '{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"left"}},' .
532
 
                                                        '{selector: "img,table,dl.wp-caption", classes: "alignleft"}' .
533
 
                                                '],' .
534
 
                                                'aligncenter: [' .
535
 
                                                        '{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"center"}},' .
536
 
                                                        '{selector: "img,table,dl.wp-caption", classes: "aligncenter"}' .
537
 
                                                '],' .
538
 
                                                'alignright: [' .
539
 
                                                        '{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"right"}},' .
540
 
                                                        '{selector: "img,table,dl.wp-caption", classes: "alignright"}' .
541
 
                                                '],' .
542
 
                                                'strikethrough: {inline: "del"}' .
543
 
                                        '}',
544
 
                                        'relative_urls' => false,
545
 
                                        'remove_script_host' => false,
546
 
                                        'convert_urls' => false,
547
 
                                        'browser_spellcheck' => true,
548
 
                                        'fix_list_elements' => true,
549
 
                                        'entities' => '38,amp,60,lt,62,gt',
550
 
                                        'entity_encoding' => 'raw',
551
 
                                        'keep_styles' => false,
552
 
                                        'cache_suffix' => 'wp-mce-' . $tinymce_version,
553
 
 
554
 
                                        // Limit the preview styles in the menu/toolbar
555
 
                                        'preview_styles' => 'font-family font-size font-weight font-style text-decoration text-transform',
556
 
 
557
 
                                        'end_container_on_empty_block' => true,
558
 
                                        'wpeditimage_disable_captions' => $no_captions,
559
 
                                        'wpeditimage_html5_captions' => current_theme_supports( 'html5', 'caption' ),
560
 
                                        'plugins' => implode( ',', $plugins ),
561
 
                                        'wp_lang_attr' => get_bloginfo( 'language' ),
562
 
                                        'wp_shortcut_labels' => wp_json_encode( $shortcut_labels ),
563
 
                                );
 
514
                                $settings = self::default_settings();
 
515
                                $settings['plugins'] = implode( ',', $plugins );
564
516
 
565
517
                                if ( ! empty( $mce_external_plugins ) ) {
566
 
                                        self::$first_init['external_plugins'] = wp_json_encode( $mce_external_plugins );
567
 
                                }
568
 
 
569
 
                                $suffix = SCRIPT_DEBUG ? '' : '.min';
570
 
                                $version = 'ver=' . get_bloginfo( 'version' );
571
 
                                $dashicons = includes_url( "css/dashicons$suffix.css?$version" );
572
 
 
573
 
                                // WordPress default stylesheet and dashicons
574
 
                                $mce_css = array(
575
 
                                        $dashicons,
576
 
                                        self::$baseurl . '/skins/wordpress/wp-content.css?' . $version
577
 
                                );
578
 
 
 
518
                                        $settings['external_plugins'] = wp_json_encode( $mce_external_plugins );
 
519
                                }
 
520
 
 
521
                                /** This filter is documented in wp-admin/includes/media.php */
 
522
                                if ( apply_filters( 'disable_captions', '' ) ) {
 
523
                                        $settings['wpeditimage_disable_captions'] = true;
 
524
                                }
 
525
 
 
526
                                $mce_css = $settings['content_css'];
579
527
                                $editor_styles = get_editor_stylesheets();
 
528
 
580
529
                                if ( ! empty( $editor_styles ) ) {
581
 
                                        foreach ( $editor_styles as $style ) {
582
 
                                                $mce_css[] = $style;
 
530
                                        // Force urlencoding of commas.
 
531
                                        foreach ( $editor_styles as $key => $url ) {
 
532
                                                if ( strpos( $url, ',' ) !== false ) {
 
533
                                                        $editor_styles[ $key ] = str_replace( ',', '%2C', $url );
 
534
                                                }
583
535
                                        }
 
536
 
 
537
                                        $mce_css .= ',' . implode( ',', $editor_styles );
584
538
                                }
585
539
 
586
540
                                /**
590
544
                                 *
591
545
                                 * @param string $stylesheets Comma-delimited list of stylesheets.
592
546
                                 */
593
 
                                $mce_css = trim( apply_filters( 'mce_css', implode( ',', $mce_css ) ), ' ,' );
594
 
 
595
 
                                if ( ! empty($mce_css) )
596
 
                                        self::$first_init['content_css'] = $mce_css;
 
547
                                $mce_css = trim( apply_filters( 'mce_css', $mce_css ), ' ,' );
 
548
 
 
549
                                if ( ! empty( $mce_css ) ) {
 
550
                                        $settings['content_css'] = $mce_css;
 
551
                                } else {
 
552
                                        unset( $settings['content_css'] );
 
553
                                }
 
554
 
 
555
                                self::$first_init = $settings;
597
556
                        }
598
557
 
599
558
                        if ( $set['teeny'] ) {
691
650
 
692
651
                        $body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_user_locale() ) ) );
693
652
 
694
 
                        if ( !empty($set['tinymce']['body_class']) ) {
 
653
                        if ( ! empty( $set['tinymce']['body_class'] ) ) {
695
654
                                $body_class .= ' ' . $set['tinymce']['body_class'];
696
 
                                unset($set['tinymce']['body_class']);
 
655
                                unset( $set['tinymce']['body_class'] );
697
656
                        }
698
657
 
699
658
                        $mceInit = array (
700
659
                                'selector' => "#$editor_id",
701
 
                                'resize' => 'vertical',
702
 
                                'menubar' => false,
703
660
                                'wpautop' => (bool) $set['wpautop'],
704
661
                                'indent' => ! $set['wpautop'],
705
 
                                'toolbar1' => implode($mce_buttons, ','),
706
 
                                'toolbar2' => implode($mce_buttons_2, ','),
707
 
                                'toolbar3' => implode($mce_buttons_3, ','),
708
 
                                'toolbar4' => implode($mce_buttons_4, ','),
 
662
                                'toolbar1' => implode( ',', $mce_buttons ),
 
663
                                'toolbar2' => implode( ',', $mce_buttons_2 ),
 
664
                                'toolbar3' => implode( ',', $mce_buttons_3 ),
 
665
                                'toolbar4' => implode( ',', $mce_buttons_4 ),
709
666
                                'tabfocus_elements' => $set['tabfocus_elements'],
710
667
                                'body_class' => $body_class
711
668
                        );
763
720
         * @param array $init
764
721
         * @return string
765
722
         */
766
 
        private static function _parse_init($init) {
 
723
        private static function _parse_init( $init ) {
767
724
                $options = '';
768
725
 
769
 
                foreach ( $init as $k => $v ) {
770
 
                        if ( is_bool($v) ) {
771
 
                                $val = $v ? 'true' : 'false';
772
 
                                $options .= $k . ':' . $val . ',';
 
726
                foreach ( $init as $key => $value ) {
 
727
                        if ( is_bool( $value ) ) {
 
728
                                $val = $value ? 'true' : 'false';
 
729
                                $options .= $key . ':' . $val . ',';
773
730
                                continue;
774
 
                        } elseif ( !empty($v) && is_string($v) && ( ('{' == $v{0} && '}' == $v{strlen($v) - 1}) || ('[' == $v{0} && ']' == $v{strlen($v) - 1}) || preg_match('/^\(?function ?\(/', $v) ) ) {
775
 
                                $options .= $k . ':' . $v . ',';
 
731
                        } elseif ( ! empty( $value ) && is_string( $value ) && (
 
732
                                ( '{' == $value{0} && '}' == $value{strlen( $value ) - 1} ) ||
 
733
                                ( '[' == $value{0} && ']' == $value{strlen( $value ) - 1} ) ||
 
734
                                preg_match( '/^\(?function ?\(/', $value ) ) ) {
 
735
 
 
736
                                $options .= $key . ':' . $value . ',';
776
737
                                continue;
777
738
                        }
778
 
                        $options .= $k . ':"' . $v . '",';
 
739
                        $options .= $key . ':"' . $value . '",';
779
740
                }
780
741
 
781
742
                return '{' . trim( $options, ' ,' ) . '}';
785
746
         *
786
747
         * @static
787
748
         */
788
 
        public static function enqueue_scripts() {
789
 
                if ( self::$has_tinymce )
790
 
                        wp_enqueue_script('editor');
 
749
        public static function enqueue_scripts( $default_scripts = false ) {
 
750
                if ( $default_scripts || self::$has_tinymce ) {
 
751
                        wp_enqueue_script( 'editor' );
 
752
                }
791
753
 
792
 
                if ( self::$has_quicktags ) {
 
754
                if ( $default_scripts || self::$has_quicktags ) {
793
755
                        wp_enqueue_script( 'quicktags' );
794
756
                        wp_enqueue_style( 'buttons' );
795
757
                }
796
758
 
797
 
                if ( in_array('wplink', self::$plugins, true) || in_array('link', self::$qt_buttons, true) ) {
798
 
                        wp_enqueue_script('wplink');
 
759
                if ( $default_scripts || in_array( 'wplink', self::$plugins, true ) || in_array( 'link', self::$qt_buttons, true ) ) {
 
760
                        wp_enqueue_script( 'wplink' );
799
761
                        wp_enqueue_script( 'jquery-ui-autocomplete' );
800
762
                }
801
763
 
802
764
                if ( self::$old_dfw_compat ) {
803
 
                        wp_enqueue_script('wp-fullscreen-stub');
 
765
                        wp_enqueue_script( 'wp-fullscreen-stub' );
804
766
                }
805
767
 
806
768
                if ( self::$has_medialib ) {
807
769
                        add_thickbox();
808
770
                        wp_enqueue_script( 'media-upload' );
809
771
                        wp_enqueue_script( 'wp-embed' );
 
772
                } elseif ( $default_scripts ) {
 
773
                        wp_enqueue_script( 'media-upload' );
810
774
                }
811
775
 
812
776
                /**
818
782
                 *                       and Quicktags are being loaded.
819
783
                 */
820
784
                do_action( 'wp_enqueue_editor', array(
821
 
                        'tinymce'   => self::$has_tinymce,
822
 
                        'quicktags' => self::$has_quicktags,
823
 
                ) );
 
785
                        'tinymce'   => ( $default_scripts || self::$has_tinymce ),
 
786
                        'quicktags' => ( $default_scripts || self::$has_quicktags ),
 
787
                ) );
 
788
        }
 
789
 
 
790
        /**
 
791
         * Enqueue all editor scripts.
 
792
         * For use when the editor is going to be initialized after page load.
 
793
         *
 
794
         * @since 4.8.0
 
795
         */
 
796
        public static function enqueue_default_editor() {
 
797
                // We are past the point where scripts can be enqueued properly.
 
798
                if ( did_action( 'wp_enqueue_editor' ) ) {
 
799
                        return;
 
800
                }
 
801
 
 
802
                self::enqueue_scripts( true );
 
803
 
 
804
                // Also add wp-includes/css/editor.css
 
805
                wp_enqueue_style( 'editor-buttons' );
 
806
 
 
807
                if ( is_admin() ) {
 
808
                        add_action( 'admin_print_footer_scripts', array( __CLASS__, 'print_default_editor_scripts' ), 45 );
 
809
                } else {
 
810
                        add_action( 'wp_print_footer_scripts', array( __CLASS__, 'print_default_editor_scripts' ), 45 );
 
811
                }
 
812
        }
 
813
 
 
814
        /**
 
815
         * Print (output) all editor scripts and default settings.
 
816
         * For use when the editor is going to be initialized after page load.
 
817
         *
 
818
         * @since 4.8.0
 
819
         *
 
820
         */
 
821
        public static function print_default_editor_scripts() {
 
822
                $settings = self::default_settings();
 
823
 
 
824
                $settings['toolbar1'] = 'bold,italic,bullist,numlist,link';
 
825
                $settings['wpautop'] = false;
 
826
                $settings['indent'] = true;
 
827
                $settings['elementpath'] = false;
 
828
 
 
829
                // In production all plugins are loaded (they are in wp-editor.js.gz)
 
830
                // but only these will be initialized by default.
 
831
                $settings['plugins'] = implode( ',', array(
 
832
                        'charmap',
 
833
                        'colorpicker',
 
834
                        'hr',
 
835
                        'lists',
 
836
        //              'media',
 
837
                        'paste',
 
838
                        'tabfocus',
 
839
                        'textcolor',
 
840
                        'fullscreen',
 
841
                        'wordpress',
 
842
                        'wpautoresize',
 
843
                        'wpeditimage',
 
844
                        'wpemoji',
 
845
                        'wpgallery',
 
846
                        'wplink',
 
847
        //              'wpdialogs',
 
848
                        'wptextpattern',
 
849
        //              'wpview',
 
850
                ) );
 
851
 
 
852
                $settings = self::_parse_init( $settings );
 
853
 
 
854
                $suffix = SCRIPT_DEBUG ? '' : '.min';
 
855
                $baseurl = self::get_baseurl();
 
856
 
 
857
                ?>
 
858
                <script type="text/javascript">
 
859
                window.wp = window.wp || {};
 
860
                window.wp.editor = window.wp.editor || {};
 
861
                window.wp.editor.getDefaultSettings = function() {
 
862
                        return {
 
863
                                tinymce: <?php echo $settings; ?>,
 
864
                                quicktags: {
 
865
                                        buttons: 'strong,em,link,ul,ol,li,code'
 
866
                                }
 
867
                        };
 
868
                };
 
869
 
 
870
                var tinyMCEPreInit = {
 
871
                        baseURL: "<?php echo $baseurl; ?>",
 
872
                        suffix: "<?php echo $suffix; ?>",
 
873
                        mceInit: {},
 
874
                        qtInit: {},
 
875
                        load_ext: function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
 
876
                };
 
877
                </script>
 
878
                <?php
 
879
 
 
880
                self::print_tinymce_scripts();
 
881
 
 
882
                /**
 
883
                 * Fires when the editor scripts are loaded for later initialization,
 
884
                 * after all scripts and settings are printed.
 
885
                 *
 
886
                 * @since 4.8.0
 
887
                 */
 
888
                do_action( 'print_default_editor_scripts' );
 
889
 
 
890
                self::wp_link_dialog();
 
891
        }
 
892
 
 
893
        public static function get_mce_locale() {
 
894
                if ( empty( self::$mce_locale ) ) {
 
895
                        $mce_locale = get_user_locale();
 
896
                        self::$mce_locale = empty( $mce_locale ) ? 'en' : strtolower( substr( $mce_locale, 0, 2 ) ); // ISO 639-1
 
897
                }
 
898
 
 
899
                return self::$mce_locale;
 
900
        }
 
901
 
 
902
        public static function get_baseurl() {
 
903
                if ( empty( self::$baseurl ) ) {
 
904
                        self::$baseurl = includes_url( 'js/tinymce' );
 
905
                }
 
906
 
 
907
                return self::$baseurl;
 
908
        }
 
909
 
 
910
        /**
 
911
         * Returns the default TinyMCE settings.
 
912
         * Doesn't include plugins, buttons, editor selector.
 
913
         *
 
914
         * @return array
 
915
         */
 
916
        private static function default_settings() {
 
917
                global $tinymce_version;
 
918
 
 
919
                $shortcut_labels = array();
 
920
 
 
921
                foreach ( self::get_translation() as $name => $value ) {
 
922
                        if ( is_array( $value ) ) {
 
923
                                $shortcut_labels[$name] = $value[1];
 
924
                        }
 
925
                }
 
926
 
 
927
                $settings = array(
 
928
                        'theme' => 'modern',
 
929
                        'skin' => 'lightgray',
 
930
                        'language' => self::get_mce_locale(),
 
931
                        'formats' => '{' .
 
932
                                'alignleft: [' .
 
933
                                        '{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"left"}},' .
 
934
                                        '{selector: "img,table,dl.wp-caption", classes: "alignleft"}' .
 
935
                                '],' .
 
936
                                'aligncenter: [' .
 
937
                                        '{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"center"}},' .
 
938
                                        '{selector: "img,table,dl.wp-caption", classes: "aligncenter"}' .
 
939
                                '],' .
 
940
                                'alignright: [' .
 
941
                                        '{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"right"}},' .
 
942
                                        '{selector: "img,table,dl.wp-caption", classes: "alignright"}' .
 
943
                                '],' .
 
944
                                'strikethrough: {inline: "del"}' .
 
945
                        '}',
 
946
                        'relative_urls' => false,
 
947
                        'remove_script_host' => false,
 
948
                        'convert_urls' => false,
 
949
                        'browser_spellcheck' => true,
 
950
                        'fix_list_elements' => true,
 
951
                        'entities' => '38,amp,60,lt,62,gt',
 
952
                        'entity_encoding' => 'raw',
 
953
                        'keep_styles' => false,
 
954
                        'cache_suffix' => 'wp-mce-' . $tinymce_version,
 
955
                        'resize' => 'vertical',
 
956
                        'menubar' => false,
 
957
                        'branding' => false,
 
958
 
 
959
                        // Limit the preview styles in the menu/toolbar
 
960
                        'preview_styles' => 'font-family font-size font-weight font-style text-decoration text-transform',
 
961
 
 
962
                        'end_container_on_empty_block' => true,
 
963
                        'wpeditimage_html5_captions' => true,
 
964
                        'wp_lang_attr' => get_bloginfo( 'language' ),
 
965
                        'wp_shortcut_labels' => wp_json_encode( $shortcut_labels ),
 
966
                );
 
967
 
 
968
                $suffix = SCRIPT_DEBUG ? '' : '.min';
 
969
                $version = 'ver=' . get_bloginfo( 'version' );
 
970
 
 
971
                // Default stylesheets
 
972
                $settings['content_css'] = includes_url( "css/dashicons$suffix.css?$version" ) . ',' .
 
973
                        includes_url( "js/tinymce/skins/wordpress/wp-content.css?$version" );
 
974
 
 
975
                return $settings;
824
976
        }
825
977
 
826
978
        private static function get_translation() {
895
1047
                        'Name' => _x( 'Name', 'Name of link anchor (TinyMCE)' ),
896
1048
                        'Anchor' => _x( 'Anchor', 'Link anchor (TinyMCE)' ),
897
1049
                        'Anchors' => _x( 'Anchors', 'Link anchors (TinyMCE)' ),
 
1050
                        'Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.' =>
 
1051
                                __( 'Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.' ),
 
1052
                        'Id' => _x( 'Id', 'Id for link anchor (TinyMCE)' ),
898
1053
 
899
1054
                        // Fullpage plugin
900
1055
                        'Document properties' => __( 'Document properties' ),
906
1061
                        'Author' => __( 'Author' ),
907
1062
 
908
1063
                        // Media, image plugins
 
1064
                        'Image' => __( 'Image' ),
909
1065
                        'Insert/edit image' => array( __( 'Insert/edit image' ), 'accessM' ),
910
1066
                        'General' => __( 'General' ),
911
1067
                        'Advanced' => __( 'Advanced' ),
917
1073
                        'Style' => __( 'Style' ),
918
1074
                        'Dimensions' => __( 'Dimensions' ),
919
1075
                        'Insert image' => __( 'Insert image' ),
 
1076
                        'Date/time' => __( 'Date/time' ),
920
1077
                        'Insert date/time' => __( 'Insert date/time' ),
921
 
                        'Insert/edit video' => __( 'Insert/edit video' ),
 
1078
                        'Table of Contents' => __( 'Table of Contents' ),
 
1079
                        'Insert/Edit code sample' => __( 'Insert/edit code sample' ),
 
1080
                        'Language' => __( 'Language' ),
 
1081
                        'Media' => __( 'Media' ),
 
1082
                        'Insert/edit media' => __( 'Insert/edit media' ),
922
1083
                        'Poster' => __( 'Poster' ),
923
1084
                        'Alternative source' => __( 'Alternative source' ),
924
1085
                        'Paste your embed code below:' => __( 'Paste your embed code below:' ),
943
1104
                        'Insert/edit link' => array( __( 'Insert/edit link' ), 'metaK' ),
944
1105
                        'Remove link' => array( __( 'Remove link' ), 'accessS' ),
945
1106
 
 
1107
                        // Link plugin
 
1108
                        'Link' => __( 'Link' ),
 
1109
                        'Insert link' => __( 'Insert link' ),
 
1110
                        'Insert/edit link' => __( 'Insert/edit link' ),
 
1111
                        'Target' => __( 'Target' ),
 
1112
                        'New window' => __( 'New window' ),
 
1113
                        'Text to display' => __( 'Text to display' ),
 
1114
                        'Url' => __( 'URL' ),
 
1115
                        'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?' =>
 
1116
                                __( 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?' ),
 
1117
                        'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?' =>
 
1118
                                __( 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?' ),
 
1119
 
946
1120
                        'Color' => __( 'Color' ),
947
1121
                        'Custom color' => __( 'Custom color' ),
948
1122
                        'Custom...' => _x( 'Custom...', 'label for custom color' ), // no ellipsis
949
1123
                        'No color' => __( 'No color' ),
 
1124
                        'R' => _x( 'R', 'Short for red in RGB' ),
 
1125
                        'G' => _x( 'G', 'Short for green in RGB' ),
 
1126
                        'B' => _x( 'B', 'Short for blue in RGB' ),
950
1127
 
951
1128
                        // Spelling, search/replace plugins
952
1129
                        'Could not find the specified string.' => __( 'Could not find the specified string.' ),
1029
1206
 
1030
1207
                        /* translators: word count */
1031
1208
                        'Words: {0}' => sprintf( __( 'Words: %s' ), '{0}' ),
1032
 
                        'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' => __( 'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' ) . "\n\n" . __( 'If you&#8217;re looking to paste rich content from Microsoft Word, try turning this option off. The editor will clean up text pasted from Word automatically.' ),
1033
 
                        'Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help' => __( 'Rich Text Area. Press Alt-Shift-H for help.' ),
 
1209
                        'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' =>
 
1210
                                __( 'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' ) . "\n\n" .
 
1211
                                __( 'If you&#8217;re looking to paste rich content from Microsoft Word, try turning this option off. The editor will clean up text pasted from Word automatically.' ),
 
1212
                        'Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help' =>
 
1213
                                __( 'Rich Text Area. Press Alt-Shift-H for help.' ),
1034
1214
                        'Rich Text Area. Press Control-Option-H for help.' => __( 'Rich Text Area. Press Control-Option-H for help.' ),
1035
 
                        'You have unsaved changes are you sure you want to navigate away?' => __( 'The changes you made will be lost if you navigate away from this page.' ),
1036
 
                        'Your browser doesn\'t support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.' => __( 'Your browser does not support direct access to the clipboard. Please use keyboard shortcuts or your browser&#8217;s edit menu instead.' ),
 
1215
                        'You have unsaved changes are you sure you want to navigate away?' =>
 
1216
                                __( 'The changes you made will be lost if you navigate away from this page.' ),
 
1217
                        'Your browser doesn\'t support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.' =>
 
1218
                                __( 'Your browser does not support direct access to the clipboard. Please use keyboard shortcuts or your browser&#8217;s edit menu instead.' ),
1037
1219
 
1038
1220
                        // TinyMCE menus
1039
1221
                        'Insert' => _x( 'Insert', 'TinyMCE menu' ),
1056
1238
                        'Paste URL or type to search' => __( 'Paste URL or type to search' ), // Placeholder for the inline link dialog
1057
1239
                        'Apply'  => __( 'Apply' ), // Tooltip for the 'apply' button in the inline link dialog
1058
1240
                        'Link options'  => __( 'Link options' ), // Tooltip for the 'link options' button in the inline link dialog
 
1241
                        'Visual' => __( 'Visual' ), // Editor switch tab label
 
1242
                        'Text' => __( 'Text' ), // Editor switch tab label
1059
1243
 
1060
1244
                        // Shortcuts help modal
1061
1245
                        'Keyboard Shortcuts' => array( __( 'Keyboard Shortcuts' ), 'accessH' ),
1084
1268
                        );
1085
1269
                }
1086
1270
 
1087
 
                /**
1088
 
                 * Link plugin (not included):
1089
 
                 *      Insert link
1090
 
                 *      Target
1091
 
                 *      New window
1092
 
                 *      Text to display
1093
 
                 *      The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?
1094
 
                 *      The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?
1095
 
                 *      Url
1096
 
                 */
 
1271
                /*
 
1272
                Imagetools plugin (not included):
 
1273
                        'Edit image' => __( 'Edit image' ),
 
1274
                        'Image options' => __( 'Image options' ),
 
1275
                        'Back' => __( 'Back' ),
 
1276
                        'Invert' => __( 'Invert' ),
 
1277
                        'Flip horizontally' => __( 'Flip horizontally' ),
 
1278
                        'Flip vertically' => __( 'Flip vertically' ),
 
1279
                        'Crop' => __( 'Crop' ),
 
1280
                        'Orientation' => __( 'Orientation' ),
 
1281
                        'Resize' => __( 'Resize' ),
 
1282
                        'Rotate clockwise' => __( 'Rotate clockwise' ),
 
1283
                        'Rotate counterclockwise' => __( 'Rotate counterclockwise' ),
 
1284
                        'Sharpen' => __( 'Sharpen' ),
 
1285
                        'Brightness' => __( 'Brightness' ),
 
1286
                        'Color levels' => __( 'Color levels' ),
 
1287
                        'Contrast' => __( 'Contrast' ),
 
1288
                        'Gamma' => __( 'Gamma' ),
 
1289
                        'Zoom in' => __( 'Zoom in' ),
 
1290
                        'Zoom out' => __( 'Zoom out' ),
 
1291
                */
1097
1292
 
1098
1293
                return self::$translation;
1099
1294
        }
1100
1295
 
1101
1296
        /**
1102
 
         * Translates the default TinyMCE strings and returns them as JSON encoded object ready to be loaded with tinymce.addI18n().
1103
 
         * Can be used directly (_WP_Editors::wp_mce_translation()) by passing the same locale as set in the TinyMCE init object.
 
1297
         * Translates the default TinyMCE strings and returns them as JSON encoded object ready to be loaded with tinymce.addI18n(),
 
1298
         * or as JS snippet that should run after tinymce.js is loaded.
1104
1299
         *
1105
1300
         * @static
1106
1301
         * @param string $mce_locale The locale used for the editor.
1109
1304
         */
1110
1305
        public static function wp_mce_translation( $mce_locale = '', $json_only = false ) {
1111
1306
                if ( ! $mce_locale ) {
1112
 
                        $mce_locale = self::$mce_locale;
 
1307
                        $mce_locale = self::get_mce_locale();
1113
1308
                }
1114
1309
 
1115
1310
                $mce_translation = self::get_translation();
1116
 
                
 
1311
 
1117
1312
                foreach ( $mce_translation as $name => $value ) {
1118
1313
                        if ( is_array( $value ) ) {
1119
1314
                                $mce_translation[$name] = $value[0];
1151
1346
                        return wp_json_encode( $mce_translation );
1152
1347
                }
1153
1348
 
1154
 
                $baseurl = self::$baseurl ? self::$baseurl : includes_url( 'js/tinymce' );
 
1349
                $baseurl = self::get_baseurl();
1155
1350
 
1156
1351
                return "tinymce.addI18n( '$mce_locale', " . wp_json_encode( $mce_translation ) . ");\n" .
1157
1352
                        "tinymce.ScriptLoader.markDone( '$baseurl/langs/$mce_locale.js' );\n";
1158
1353
        }
1159
1354
 
1160
1355
        /**
 
1356
         * Print (output) the main TinyMCE scripts.
 
1357
         *
 
1358
         * @since 4.8
1161
1359
         *
1162
1360
         * @static
1163
1361
         * @global string $tinymce_version
1164
1362
         * @global bool   $concatenate_scripts
1165
1363
         * @global bool   $compress_scripts
1166
1364
         */
1167
 
        public static function editor_js() {
 
1365
        public static function print_tinymce_scripts() {
1168
1366
                global $tinymce_version, $concatenate_scripts, $compress_scripts;
1169
1367
 
1170
 
                /**
1171
 
                 * Filters "tiny_mce_version" is deprecated
1172
 
                 *
1173
 
                 * The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
1174
 
                 * These plugins can be refreshed by appending query string to the URL passed to "mce_external_plugins" filter.
1175
 
                 * If the plugin has a popup dialog, a query string can be added to the button action that opens it (in the plugin's code).
1176
 
                 */
1177
 
                $version = 'ver=' . $tinymce_version;
1178
 
                $tmce_on = !empty(self::$mce_settings);
1179
 
 
1180
 
                if ( ! isset($concatenate_scripts) )
 
1368
                if ( self::$tinymce_scripts_printed ) {
 
1369
                        return;
 
1370
                }
 
1371
 
 
1372
                self::$tinymce_scripts_printed = true;
 
1373
 
 
1374
                if ( ! isset( $concatenate_scripts ) ) {
1181
1375
                        script_concat_settings();
 
1376
                }
 
1377
 
 
1378
                $suffix = SCRIPT_DEBUG ? '' : '.min';
 
1379
                $version = 'ver=' . $tinymce_version;
 
1380
                $baseurl = self::get_baseurl();
1182
1381
 
1183
1382
                $compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
1184
1383
                        && false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
1185
1384
 
 
1385
                // Load tinymce.js when running from /src, else load wp-tinymce.js.gz (production) or tinymce.min.js (SCRIPT_DEBUG)
 
1386
                $mce_suffix = false !== strpos( get_bloginfo( 'version' ), '-src' ) ? '' : '.min';
 
1387
 
 
1388
                if ( $compressed ) {
 
1389
                        echo "<script type='text/javascript' src='{$baseurl}/wp-tinymce.php?c=1&amp;$version'></script>\n";
 
1390
                } else {
 
1391
                        echo "<script type='text/javascript' src='{$baseurl}/tinymce{$mce_suffix}.js?$version'></script>\n";
 
1392
                        echo "<script type='text/javascript' src='{$baseurl}/plugins/compat3x/plugin{$suffix}.js?$version'></script>\n";
 
1393
                }
 
1394
 
 
1395
                echo "<script type='text/javascript'>\n" . self::wp_mce_translation() . "</script>\n";
 
1396
        }
 
1397
 
 
1398
        /**
 
1399
         * Print (output) the TinyMCE configuration and initialization scripts.
 
1400
         *
 
1401
         * @static
 
1402
         */
 
1403
        public static function editor_js() {
 
1404
                global $tinymce_version;
 
1405
 
 
1406
                $tmce_on = ! empty( self::$mce_settings );
1186
1407
                $mceInit = $qtInit = '';
 
1408
 
1187
1409
                if ( $tmce_on ) {
1188
1410
                        foreach ( self::$mce_settings as $editor_id => $init ) {
1189
1411
                                $options = self::_parse_init( $init );
1190
1412
                                $mceInit .= "'$editor_id':{$options},";
1191
1413
                        }
1192
 
                        $mceInit = '{' . trim($mceInit, ',') . '}';
 
1414
                        $mceInit = '{' . trim( $mceInit, ',' ) . '}';
1193
1415
                } else {
1194
1416
                        $mceInit = '{}';
1195
1417
                }
1196
1418
 
1197
 
                if ( !empty(self::$qt_settings) ) {
 
1419
                if ( ! empty( self::$qt_settings ) ) {
1198
1420
                        foreach ( self::$qt_settings as $editor_id => $init ) {
1199
1421
                                $options = self::_parse_init( $init );
1200
1422
                                $qtInit .= "'$editor_id':{$options},";
1201
1423
                        }
1202
 
                        $qtInit = '{' . trim($qtInit, ',') . '}';
 
1424
                        $qtInit = '{' . trim( $qtInit, ',' ) . '}';
1203
1425
                } else {
1204
1426
                        $qtInit = '{}';
1205
1427
                }
1211
1433
                );
1212
1434
 
1213
1435
                $suffix = SCRIPT_DEBUG ? '' : '.min';
 
1436
                $baseurl = self::get_baseurl();
 
1437
                $version = 'ver=' . $tinymce_version;
1214
1438
 
1215
1439
                /**
1216
1440
                 * Fires immediately before the TinyMCE settings are printed.
1224
1448
 
1225
1449
                <script type="text/javascript">
1226
1450
                tinyMCEPreInit = {
1227
 
                        baseURL: "<?php echo self::$baseurl; ?>",
 
1451
                        baseURL: "<?php echo $baseurl; ?>",
1228
1452
                        suffix: "<?php echo $suffix; ?>",
1229
1453
                        <?php
1230
1454
 
1241
1465
                </script>
1242
1466
                <?php
1243
1467
 
1244
 
                $baseurl = self::$baseurl;
1245
 
                // Load tinymce.js when running from /src, else load wp-tinymce.js.gz (production) or tinymce.min.js (SCRIPT_DEBUG)
1246
 
                $mce_suffix = false !== strpos( get_bloginfo( 'version' ), '-src' ) ? '' : '.min';
1247
 
 
1248
1468
                if ( $tmce_on ) {
1249
 
                        if ( $compressed ) {
1250
 
                                echo "<script type='text/javascript' src='{$baseurl}/wp-tinymce.php?c=1&amp;$version'></script>\n";
1251
 
                        } else {
1252
 
                                echo "<script type='text/javascript' src='{$baseurl}/tinymce{$mce_suffix}.js?$version'></script>\n";
1253
 
                                echo "<script type='text/javascript' src='{$baseurl}/plugins/compat3x/plugin{$suffix}.js?$version'></script>\n";
1254
 
                        }
1255
 
 
1256
 
                        echo "<script type='text/javascript'>\n" . self::wp_mce_translation() . "</script>\n";
 
1469
                        self::print_tinymce_scripts();
1257
1470
 
1258
1471
                        if ( self::$ext_plugins ) {
1259
1472
                                // Load the old-format English strings to prevent unsightly labels in old style popups
1287
1500
                        var init, id, $wrap;
1288
1501
 
1289
1502
                        if ( typeof tinymce !== 'undefined' ) {
 
1503
                                if ( tinymce.Env.ie && tinymce.Env.ie < 11 ) {
 
1504
                                        tinymce.$( '.wp-editor-wrap ' ).removeClass( 'tmce-active' ).addClass( 'html-active' );
 
1505
                                        return;
 
1506
                                }
 
1507
 
1290
1508
                                for ( id in tinyMCEPreInit.mceInit ) {
1291
1509
                                        init = tinyMCEPreInit.mceInit[id];
1292
1510
                                        $wrap = tinymce.$( '#wp-' + id + '-wrap' );
1435
1653
         * @static
1436
1654
         */
1437
1655
        public static function wp_link_dialog() {
 
1656
                // Run once
 
1657
                if ( self::$link_dialog_printed ) {
 
1658
                        return;
 
1659
                }
 
1660
 
 
1661
                self::$link_dialog_printed = true;
 
1662
 
1438
1663
                // display: none is required here, see #WP27605
1439
1664
                ?>
1440
1665
                <div id="wp-link-backdrop" style="display: none"></div>