From 40ebb188cd5cd0f085673648a284b1194a9bc03b Mon Sep 17 00:00:00 2001
From: Weston Ruter
Date: Thu, 11 May 2017 18:55:43 +0000
Subject: [PATCH] Widgets: Extend the Text widget with TinyMCE.
Introduces rich text formatting: bold, italic, lists, links.
Props westonruter, azaozz, timmydcrawford, obenland, melchoyce.
See #35760.
Fixes #35243.
Built from https://develop.svn.wordpress.org/trunk@40631
git-svn-id: http://core.svn.wordpress.org/trunk@40492 1a063a9b-81f0-0310-95a4-ce76da25c4cd
---
wp-admin/css/customize-widgets-rtl.css | 15 +
wp-admin/css/customize-widgets-rtl.min.css | 2 +-
wp-admin/css/customize-widgets.css | 15 +
wp-admin/css/customize-widgets.min.css | 2 +-
wp-admin/js/widgets/text-widgets.js | 326 +++++++++++++++++++
wp-admin/js/widgets/text-widgets.min.js | 1 +
wp-includes/default-filters.php | 6 +-
wp-includes/script-loader.php | 2 +
wp-includes/version.php | 2 +-
wp-includes/widgets/class-wp-widget-text.php | 112 ++++++-
10 files changed, 466 insertions(+), 17 deletions(-)
create mode 100644 wp-admin/js/widgets/text-widgets.js
create mode 100644 wp-admin/js/widgets/text-widgets.min.js
diff --git a/wp-admin/css/customize-widgets-rtl.css b/wp-admin/css/customize-widgets-rtl.css
index cc7cf8443b..7bb4b2ec6e 100644
--- a/wp-admin/css/customize-widgets-rtl.css
+++ b/wp-admin/css/customize-widgets-rtl.css
@@ -213,6 +213,21 @@
display: block;
}
+/* Text Widget */
+.wp-customizer div.mce-inline-toolbar-grp,
+.wp-customizer div.mce-tooltip {
+ z-index: 500100 !important;
+}
+.wp-customizer .ui-autocomplete.wplink-autocomplete {
+ z-index: 500110; /* originally 100110, but z-index of .wp-full-overlay is 500000 */
+}
+.wp-customizer #wp-link-backdrop {
+ z-index: 500100; /* originally 100100, but z-index of .wp-full-overlay is 500000 */
+}
+.wp-customizer #wp-link-wrap {
+ z-index: 500105; /* originally 100105, but z-index of .wp-full-overlay is 500000 */
+}
+
/**
* Styles for new widget addition panel
*/
diff --git a/wp-admin/css/customize-widgets-rtl.min.css b/wp-admin/css/customize-widgets-rtl.min.css
index 21e798c4b7..192b59c4c3 100644
--- a/wp-admin/css/customize-widgets-rtl.min.css
+++ b/wp-admin/css/customize-widgets-rtl.min.css
@@ -1 +1 @@
-.control-section.control-section-sidebar .accordion-section-content.ui-sortable,.wp-full-overlay-sidebar{overflow:visible}.control-section.control-section-sidebar,.customize-control-sidebar_widgets .hide-if-js,.customize-control-sidebar_widgets label{display:none}.customize-control-widget_form .widget-top{background:#fff;-webkit-transition:opacity .5s;transition:opacity .5s}.customize-control .widget-action{color:#72777c}.customize-control .widget-action:focus,.customize-control .widget-top:hover .widget-action{color:#23282d}.customize-control-widget_form:not(.widget-rendered) .widget-top{opacity:.5}.customize-control-widget_form .widget-control-save{display:none}.customize-control-widget_form .spinner{visibility:hidden;margin-top:0}.customize-control-widget_form.previewer-loading .spinner{visibility:visible}.customize-control-widget_form.widget-form-disabled .widget-content{opacity:.7;pointer-events:none;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.customize-control-widget_form .widget{margin-bottom:0}.customize-control-widget_form.wide-widget-control .widget-inside{position:fixed;right:299px;top:25%;border:1px solid #e5e5e5;overflow:auto}.customize-control-widget_form.wide-widget-control .widget-inside>.form{padding:20px}.customize-control-widget_form.wide-widget-control .widget-top{-webkit-transition:background-color .4s;transition:background-color .4s}.customize-control-widget_form.wide-widget-control.expanded:not(.collapsing) .widget-top,.customize-control-widget_form.wide-widget-control.expanding .widget-top{background-color:#e3e3e3}.widget-inside{padding:1px 10px 10px;border-top:none;line-height:16px}.customize-control-widget_form.expanded .widget-action .toggle-indicator:before{content:"\f142"}.customize-control-widget_form.wide-widget-control .widget-action .toggle-indicator:before{content:"\f141"}.customize-control-widget_form.wide-widget-control.expanded .widget-action .toggle-indicator:before{content:"\f139"}.widget-title-action{cursor:pointer}.customize-control-widget_form .widget .customize-control-title,.widget-top{cursor:move}.control-section.accordion-section.highlighted>.accordion-section-title,.customize-control-widget_form.highlighted{outline:0;-webkit-box-shadow:0 0 2px rgba(30,140,190,.8);box-shadow:0 0 2px rgba(30,140,190,.8);position:relative;z-index:1}#widget-customizer-control-templates{display:none}#customize-theme-controls .widget-reorder-nav{display:none;float:left;background-color:#fafafa}.move-widget:before{content:"\f504"}#customize-theme-controls .move-widget-area{display:none;background:#fff;border:1px solid #ddd;border-top:none;cursor:auto}#customize-theme-controls .reordering .move-widget-area.active{display:block}#customize-theme-controls .move-widget-area .description{margin:0;padding:15px 20px;font-weight:400}#customize-theme-controls .widget-area-select{margin:0;padding:0;list-style:none}#customize-theme-controls .widget-area-select li{position:relative;margin:0;padding:13px 42px 15px 15px;color:#555;border-top:1px solid #eee;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#customize-theme-controls .widget-area-select li:before{display:none;content:"\f147";position:absolute;top:12px;right:10px;font:400 20px/1 dashicons;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#customize-theme-controls .widget-area-select li:last-child{border-bottom:1px solid #eee}#customize-theme-controls .widget-area-select .selected{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.4);background:#00a0d2}#customize-theme-controls .widget-area-select .selected:before{display:block}#customize-theme-controls .move-widget-actions{text-align:left;padding:12px}#customize-theme-controls .reordering .widget-title-action{display:none}#customize-theme-controls .reordering .widget-reorder-nav{display:block}#widgets-left #available-widgets .widget{float:none!important;width:auto!important}.ios #available-widgets{-webkit-transition:right 0s;transition:right 0s}#available-widgets .widget-tpl.selected,#available-widgets .widget-tpl:hover{background:#f3f3f5;border-bottom-color:#ccc;color:#0073aa;border-right:4px solid #0073aa}#customize-controls .widget-title h3{font-size:1em}#available-widgets .widget-title h3{padding:0 0 5px;font-size:14px}#available-widgets .widget .widget-description{padding:0;color:#72777c}#customize-preview{-webkit-transition:all .2s;transition:all .2s}body.adding-widget #available-widgets{right:0;visibility:visible}body.adding-widget .wp-full-overlay-main{right:300px}body.adding-widget #customize-preview{opacity:.4}#available-widgets .widget-title{position:relative}#available-widgets .widget-title:before{content:"\f132";position:absolute;top:-3px;left:100%;margin-left:20px;width:20px;height:20px;color:#32373c;font:400 20px/1 dashicons;text-align:center;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#available-widgets [class*=easy] .widget-title:before{content:"\f328";top:-4px}#available-widgets [class*=super] .widget-title:before,#available-widgets [class*=like] .widget-title:before{content:"\f155";top:-4px}#available-widgets [class*=meta] .widget-title:before{content:"\f120"}#available-widgets [class*=archives] .widget-title:before{content:"\f480";top:-4px}#available-widgets [class*=categor] .widget-title:before{content:"\f318";top:-4px}#available-widgets [class*=comment] .widget-title:before,#available-widgets [class*=testimonial] .widget-title:before,#available-widgets [class*=chat] .widget-title:before{content:"\f101"}#available-widgets [class*=post] .widget-title:before{content:"\f109"}#available-widgets [class*=page] .widget-title:before{content:"\f105"}#available-widgets [class*=text] .widget-title:before{content:"\f478"}#available-widgets [class*=link] .widget-title:before{content:"\f103"}#available-widgets [class*=search] .widget-title:before{content:"\f179"}#available-widgets [class*=menu] .widget-title:before,#available-widgets [class*=nav] .widget-title:before{content:"\f333"}#available-widgets [class*=tag] .widget-title:before{content:"\f479"}#available-widgets [class*=rss] .widget-title:before{content:"\f303";top:-6px}#available-widgets [class*=event] .widget-title:before,#available-widgets [class*=calendar] .widget-title:before{content:"\f145";top:-4px}#available-widgets [class*=image] .widget-title:before,#available-widgets [class*=photo] .widget-title:before,#available-widgets [class*=slide] .widget-title:before,#available-widgets [class*=instagram] .widget-title:before{content:"\f128"}#available-widgets [class*=album] .widget-title:before,#available-widgets [class*=galler] .widget-title:before{content:"\f161"}#available-widgets [class*=video] .widget-title:before,#available-widgets [class*=tube] .widget-title:before{content:"\f126"}#available-widgets [class*=music] .widget-title:before,#available-widgets [class*=radio] .widget-title:before,#available-widgets [class*=audio] .widget-title:before{content:"\f127"}#available-widgets [class*=login] .widget-title:before,#available-widgets [class*=user] .widget-title:before,#available-widgets [class*=member] .widget-title:before,#available-widgets [class*=avatar] .widget-title:before,#available-widgets [class*=subscriber] .widget-title:before,#available-widgets [class*=profile] .widget-title:before,#available-widgets [class*=grofile] .widget-title:before{content:"\f110"}#available-widgets [class*=commerce] .widget-title:before,#available-widgets [class*=shop] .widget-title:before,#available-widgets [class*=cart] .widget-title:before{content:"\f174";top:-4px}#available-widgets [class*=secur] .widget-title:before,#available-widgets [class*=firewall] .widget-title:before{content:"\f332"}#available-widgets [class*=analytic] .widget-title:before,#available-widgets [class*=stat] .widget-title:before,#available-widgets [class*=poll] .widget-title:before{content:"\f185"}#available-widgets [class*=form] .widget-title:before{content:"\f175"}#available-widgets [class*=subscribe] .widget-title:before,#available-widgets [class*=news] .widget-title:before,#available-widgets [class*=contact] .widget-title:before,#available-widgets [class*=mail] .widget-title:before{content:"\f466"}#available-widgets [class*=share] .widget-title:before,#available-widgets [class*=socia] .widget-title:before{content:"\f237"}#available-widgets [class*=lang] .widget-title:before,#available-widgets [class*=translat] .widget-title:before{content:"\f326"}#available-widgets [class*=locat] .widget-title:before,#available-widgets [class*=map] .widget-title:before{content:"\f231"}#available-widgets [class*=download] .widget-title:before{content:"\f316"}#available-widgets [class*=weather] .widget-title:before{content:"\f176";top:-4px}#available-widgets [class*=facebook] .widget-title:before{content:"\f304"}#available-widgets [class*=tweet] .widget-title:before,#available-widgets [class*=twitter] .widget-title:before{content:"\f301"}@media screen and (max-height:700px) and (min-width:981px){.customize-control-widget_form{margin-bottom:0}.widget-top{-webkit-box-shadow:none;box-shadow:none;margin-top:-1px}.widget-top:hover{position:relative;z-index:1}.last-widget{margin-bottom:15px}.widget-title h3{padding:13px 15px}.widget-top .widget-action{padding:8px 10px}.widget-reorder-nav span{height:39px}.widget-reorder-nav span:before{line-height:39px}#customize-theme-controls .widget-area-select li{padding:9px 42px 11px 15px}#customize-theme-controls .widget-area-select li:before{top:8px}}
\ No newline at end of file
+.control-section.control-section-sidebar .accordion-section-content.ui-sortable,.wp-full-overlay-sidebar{overflow:visible}.control-section.control-section-sidebar,.customize-control-sidebar_widgets .hide-if-js,.customize-control-sidebar_widgets label{display:none}.customize-control-widget_form .widget-top{background:#fff;-webkit-transition:opacity .5s;transition:opacity .5s}.customize-control .widget-action{color:#72777c}.customize-control .widget-action:focus,.customize-control .widget-top:hover .widget-action{color:#23282d}.customize-control-widget_form:not(.widget-rendered) .widget-top{opacity:.5}.customize-control-widget_form .widget-control-save{display:none}.customize-control-widget_form .spinner{visibility:hidden;margin-top:0}.customize-control-widget_form.previewer-loading .spinner{visibility:visible}.customize-control-widget_form.widget-form-disabled .widget-content{opacity:.7;pointer-events:none;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.customize-control-widget_form .widget{margin-bottom:0}.customize-control-widget_form.wide-widget-control .widget-inside{position:fixed;right:299px;top:25%;border:1px solid #e5e5e5;overflow:auto}.customize-control-widget_form.wide-widget-control .widget-inside>.form{padding:20px}.customize-control-widget_form.wide-widget-control .widget-top{-webkit-transition:background-color .4s;transition:background-color .4s}.customize-control-widget_form.wide-widget-control.expanded:not(.collapsing) .widget-top,.customize-control-widget_form.wide-widget-control.expanding .widget-top{background-color:#e3e3e3}.widget-inside{padding:1px 10px 10px;border-top:none;line-height:16px}.customize-control-widget_form.expanded .widget-action .toggle-indicator:before{content:"\f142"}.customize-control-widget_form.wide-widget-control .widget-action .toggle-indicator:before{content:"\f141"}.customize-control-widget_form.wide-widget-control.expanded .widget-action .toggle-indicator:before{content:"\f139"}.widget-title-action{cursor:pointer}.customize-control-widget_form .widget .customize-control-title,.widget-top{cursor:move}.control-section.accordion-section.highlighted>.accordion-section-title,.customize-control-widget_form.highlighted{outline:0;-webkit-box-shadow:0 0 2px rgba(30,140,190,.8);box-shadow:0 0 2px rgba(30,140,190,.8);position:relative;z-index:1}#widget-customizer-control-templates{display:none}#customize-theme-controls .widget-reorder-nav{display:none;float:left;background-color:#fafafa}.move-widget:before{content:"\f504"}#customize-theme-controls .move-widget-area{display:none;background:#fff;border:1px solid #ddd;border-top:none;cursor:auto}#customize-theme-controls .reordering .move-widget-area.active{display:block}#customize-theme-controls .move-widget-area .description{margin:0;padding:15px 20px;font-weight:400}#customize-theme-controls .widget-area-select{margin:0;padding:0;list-style:none}#customize-theme-controls .widget-area-select li{position:relative;margin:0;padding:13px 42px 15px 15px;color:#555;border-top:1px solid #eee;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#customize-theme-controls .widget-area-select li:before{display:none;content:"\f147";position:absolute;top:12px;right:10px;font:400 20px/1 dashicons;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#customize-theme-controls .widget-area-select li:last-child{border-bottom:1px solid #eee}#customize-theme-controls .widget-area-select .selected{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.4);background:#00a0d2}#customize-theme-controls .widget-area-select .selected:before{display:block}#customize-theme-controls .move-widget-actions{text-align:left;padding:12px}#customize-theme-controls .reordering .widget-title-action{display:none}#customize-theme-controls .reordering .widget-reorder-nav{display:block}.wp-customizer div.mce-inline-toolbar-grp,.wp-customizer div.mce-tooltip{z-index:500100!important}.wp-customizer .ui-autocomplete.wplink-autocomplete{z-index:500110}.wp-customizer #wp-link-backdrop{z-index:500100}.wp-customizer #wp-link-wrap{z-index:500105}#widgets-left #available-widgets .widget{float:none!important;width:auto!important}.ios #available-widgets{-webkit-transition:right 0s;transition:right 0s}#available-widgets .widget-tpl.selected,#available-widgets .widget-tpl:hover{background:#f3f3f5;border-bottom-color:#ccc;color:#0073aa;border-right:4px solid #0073aa}#customize-controls .widget-title h3{font-size:1em}#available-widgets .widget-title h3{padding:0 0 5px;font-size:14px}#available-widgets .widget .widget-description{padding:0;color:#72777c}#customize-preview{-webkit-transition:all .2s;transition:all .2s}body.adding-widget #available-widgets{right:0;visibility:visible}body.adding-widget .wp-full-overlay-main{right:300px}body.adding-widget #customize-preview{opacity:.4}#available-widgets .widget-title{position:relative}#available-widgets .widget-title:before{content:"\f132";position:absolute;top:-3px;left:100%;margin-left:20px;width:20px;height:20px;color:#32373c;font:400 20px/1 dashicons;text-align:center;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#available-widgets [class*=easy] .widget-title:before{content:"\f328";top:-4px}#available-widgets [class*=super] .widget-title:before,#available-widgets [class*=like] .widget-title:before{content:"\f155";top:-4px}#available-widgets [class*=meta] .widget-title:before{content:"\f120"}#available-widgets [class*=archives] .widget-title:before{content:"\f480";top:-4px}#available-widgets [class*=categor] .widget-title:before{content:"\f318";top:-4px}#available-widgets [class*=comment] .widget-title:before,#available-widgets [class*=testimonial] .widget-title:before,#available-widgets [class*=chat] .widget-title:before{content:"\f101"}#available-widgets [class*=post] .widget-title:before{content:"\f109"}#available-widgets [class*=page] .widget-title:before{content:"\f105"}#available-widgets [class*=text] .widget-title:before{content:"\f478"}#available-widgets [class*=link] .widget-title:before{content:"\f103"}#available-widgets [class*=search] .widget-title:before{content:"\f179"}#available-widgets [class*=menu] .widget-title:before,#available-widgets [class*=nav] .widget-title:before{content:"\f333"}#available-widgets [class*=tag] .widget-title:before{content:"\f479"}#available-widgets [class*=rss] .widget-title:before{content:"\f303";top:-6px}#available-widgets [class*=event] .widget-title:before,#available-widgets [class*=calendar] .widget-title:before{content:"\f145";top:-4px}#available-widgets [class*=image] .widget-title:before,#available-widgets [class*=photo] .widget-title:before,#available-widgets [class*=slide] .widget-title:before,#available-widgets [class*=instagram] .widget-title:before{content:"\f128"}#available-widgets [class*=album] .widget-title:before,#available-widgets [class*=galler] .widget-title:before{content:"\f161"}#available-widgets [class*=video] .widget-title:before,#available-widgets [class*=tube] .widget-title:before{content:"\f126"}#available-widgets [class*=music] .widget-title:before,#available-widgets [class*=radio] .widget-title:before,#available-widgets [class*=audio] .widget-title:before{content:"\f127"}#available-widgets [class*=login] .widget-title:before,#available-widgets [class*=user] .widget-title:before,#available-widgets [class*=member] .widget-title:before,#available-widgets [class*=avatar] .widget-title:before,#available-widgets [class*=subscriber] .widget-title:before,#available-widgets [class*=profile] .widget-title:before,#available-widgets [class*=grofile] .widget-title:before{content:"\f110"}#available-widgets [class*=commerce] .widget-title:before,#available-widgets [class*=shop] .widget-title:before,#available-widgets [class*=cart] .widget-title:before{content:"\f174";top:-4px}#available-widgets [class*=secur] .widget-title:before,#available-widgets [class*=firewall] .widget-title:before{content:"\f332"}#available-widgets [class*=analytic] .widget-title:before,#available-widgets [class*=stat] .widget-title:before,#available-widgets [class*=poll] .widget-title:before{content:"\f185"}#available-widgets [class*=form] .widget-title:before{content:"\f175"}#available-widgets [class*=subscribe] .widget-title:before,#available-widgets [class*=news] .widget-title:before,#available-widgets [class*=contact] .widget-title:before,#available-widgets [class*=mail] .widget-title:before{content:"\f466"}#available-widgets [class*=share] .widget-title:before,#available-widgets [class*=socia] .widget-title:before{content:"\f237"}#available-widgets [class*=lang] .widget-title:before,#available-widgets [class*=translat] .widget-title:before{content:"\f326"}#available-widgets [class*=locat] .widget-title:before,#available-widgets [class*=map] .widget-title:before{content:"\f231"}#available-widgets [class*=download] .widget-title:before{content:"\f316"}#available-widgets [class*=weather] .widget-title:before{content:"\f176";top:-4px}#available-widgets [class*=facebook] .widget-title:before{content:"\f304"}#available-widgets [class*=tweet] .widget-title:before,#available-widgets [class*=twitter] .widget-title:before{content:"\f301"}@media screen and (max-height:700px) and (min-width:981px){.customize-control-widget_form{margin-bottom:0}.widget-top{-webkit-box-shadow:none;box-shadow:none;margin-top:-1px}.widget-top:hover{position:relative;z-index:1}.last-widget{margin-bottom:15px}.widget-title h3{padding:13px 15px}.widget-top .widget-action{padding:8px 10px}.widget-reorder-nav span{height:39px}.widget-reorder-nav span:before{line-height:39px}#customize-theme-controls .widget-area-select li{padding:9px 42px 11px 15px}#customize-theme-controls .widget-area-select li:before{top:8px}}
\ No newline at end of file
diff --git a/wp-admin/css/customize-widgets.css b/wp-admin/css/customize-widgets.css
index bdb58982fe..0a9fbf5869 100644
--- a/wp-admin/css/customize-widgets.css
+++ b/wp-admin/css/customize-widgets.css
@@ -213,6 +213,21 @@
display: block;
}
+/* Text Widget */
+.wp-customizer div.mce-inline-toolbar-grp,
+.wp-customizer div.mce-tooltip {
+ z-index: 500100 !important;
+}
+.wp-customizer .ui-autocomplete.wplink-autocomplete {
+ z-index: 500110; /* originally 100110, but z-index of .wp-full-overlay is 500000 */
+}
+.wp-customizer #wp-link-backdrop {
+ z-index: 500100; /* originally 100100, but z-index of .wp-full-overlay is 500000 */
+}
+.wp-customizer #wp-link-wrap {
+ z-index: 500105; /* originally 100105, but z-index of .wp-full-overlay is 500000 */
+}
+
/**
* Styles for new widget addition panel
*/
diff --git a/wp-admin/css/customize-widgets.min.css b/wp-admin/css/customize-widgets.min.css
index d531ab4a07..22c611ebb0 100644
--- a/wp-admin/css/customize-widgets.min.css
+++ b/wp-admin/css/customize-widgets.min.css
@@ -1 +1 @@
-.control-section.control-section-sidebar .accordion-section-content.ui-sortable,.wp-full-overlay-sidebar{overflow:visible}.control-section.control-section-sidebar,.customize-control-sidebar_widgets .hide-if-js,.customize-control-sidebar_widgets label{display:none}.customize-control-widget_form .widget-top{background:#fff;-webkit-transition:opacity .5s;transition:opacity .5s}.customize-control .widget-action{color:#72777c}.customize-control .widget-action:focus,.customize-control .widget-top:hover .widget-action{color:#23282d}.customize-control-widget_form:not(.widget-rendered) .widget-top{opacity:.5}.customize-control-widget_form .widget-control-save{display:none}.customize-control-widget_form .spinner{visibility:hidden;margin-top:0}.customize-control-widget_form.previewer-loading .spinner{visibility:visible}.customize-control-widget_form.widget-form-disabled .widget-content{opacity:.7;pointer-events:none;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.customize-control-widget_form .widget{margin-bottom:0}.customize-control-widget_form.wide-widget-control .widget-inside{position:fixed;left:299px;top:25%;border:1px solid #e5e5e5;overflow:auto}.customize-control-widget_form.wide-widget-control .widget-inside>.form{padding:20px}.customize-control-widget_form.wide-widget-control .widget-top{-webkit-transition:background-color .4s;transition:background-color .4s}.customize-control-widget_form.wide-widget-control.expanded:not(.collapsing) .widget-top,.customize-control-widget_form.wide-widget-control.expanding .widget-top{background-color:#e3e3e3}.widget-inside{padding:1px 10px 10px;border-top:none;line-height:16px}.customize-control-widget_form.expanded .widget-action .toggle-indicator:before{content:"\f142"}.customize-control-widget_form.wide-widget-control .widget-action .toggle-indicator:before{content:"\f139"}.customize-control-widget_form.wide-widget-control.expanded .widget-action .toggle-indicator:before{content:"\f141"}.widget-title-action{cursor:pointer}.customize-control-widget_form .widget .customize-control-title,.widget-top{cursor:move}.control-section.accordion-section.highlighted>.accordion-section-title,.customize-control-widget_form.highlighted{outline:0;-webkit-box-shadow:0 0 2px rgba(30,140,190,.8);box-shadow:0 0 2px rgba(30,140,190,.8);position:relative;z-index:1}#widget-customizer-control-templates{display:none}#customize-theme-controls .widget-reorder-nav{display:none;float:right;background-color:#fafafa}.move-widget:before{content:"\f504"}#customize-theme-controls .move-widget-area{display:none;background:#fff;border:1px solid #ddd;border-top:none;cursor:auto}#customize-theme-controls .reordering .move-widget-area.active{display:block}#customize-theme-controls .move-widget-area .description{margin:0;padding:15px 20px;font-weight:400}#customize-theme-controls .widget-area-select{margin:0;padding:0;list-style:none}#customize-theme-controls .widget-area-select li{position:relative;margin:0;padding:13px 15px 15px 42px;color:#555;border-top:1px solid #eee;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#customize-theme-controls .widget-area-select li:before{display:none;content:"\f147";position:absolute;top:12px;left:10px;font:400 20px/1 dashicons;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#customize-theme-controls .widget-area-select li:last-child{border-bottom:1px solid #eee}#customize-theme-controls .widget-area-select .selected{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.4);background:#00a0d2}#customize-theme-controls .widget-area-select .selected:before{display:block}#customize-theme-controls .move-widget-actions{text-align:right;padding:12px}#customize-theme-controls .reordering .widget-title-action{display:none}#customize-theme-controls .reordering .widget-reorder-nav{display:block}#widgets-left #available-widgets .widget{float:none!important;width:auto!important}.ios #available-widgets{-webkit-transition:left 0s;transition:left 0s}#available-widgets .widget-tpl.selected,#available-widgets .widget-tpl:hover{background:#f3f3f5;border-bottom-color:#ccc;color:#0073aa;border-left:4px solid #0073aa}#customize-controls .widget-title h3{font-size:1em}#available-widgets .widget-title h3{padding:0 0 5px;font-size:14px}#available-widgets .widget .widget-description{padding:0;color:#72777c}#customize-preview{-webkit-transition:all .2s;transition:all .2s}body.adding-widget #available-widgets{left:0;visibility:visible}body.adding-widget .wp-full-overlay-main{left:300px}body.adding-widget #customize-preview{opacity:.4}#available-widgets .widget-title{position:relative}#available-widgets .widget-title:before{content:"\f132";position:absolute;top:-3px;right:100%;margin-right:20px;width:20px;height:20px;color:#32373c;font:400 20px/1 dashicons;text-align:center;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#available-widgets [class*=easy] .widget-title:before{content:"\f328";top:-4px}#available-widgets [class*=super] .widget-title:before,#available-widgets [class*=like] .widget-title:before{content:"\f155";top:-4px}#available-widgets [class*=meta] .widget-title:before{content:"\f120"}#available-widgets [class*=archives] .widget-title:before{content:"\f480";top:-4px}#available-widgets [class*=categor] .widget-title:before{content:"\f318";top:-4px}#available-widgets [class*=comment] .widget-title:before,#available-widgets [class*=testimonial] .widget-title:before,#available-widgets [class*=chat] .widget-title:before{content:"\f101"}#available-widgets [class*=post] .widget-title:before{content:"\f109"}#available-widgets [class*=page] .widget-title:before{content:"\f105"}#available-widgets [class*=text] .widget-title:before{content:"\f478"}#available-widgets [class*=link] .widget-title:before{content:"\f103"}#available-widgets [class*=search] .widget-title:before{content:"\f179"}#available-widgets [class*=menu] .widget-title:before,#available-widgets [class*=nav] .widget-title:before{content:"\f333"}#available-widgets [class*=tag] .widget-title:before{content:"\f479"}#available-widgets [class*=rss] .widget-title:before{content:"\f303";top:-6px}#available-widgets [class*=event] .widget-title:before,#available-widgets [class*=calendar] .widget-title:before{content:"\f145";top:-4px}#available-widgets [class*=image] .widget-title:before,#available-widgets [class*=photo] .widget-title:before,#available-widgets [class*=slide] .widget-title:before,#available-widgets [class*=instagram] .widget-title:before{content:"\f128"}#available-widgets [class*=album] .widget-title:before,#available-widgets [class*=galler] .widget-title:before{content:"\f161"}#available-widgets [class*=video] .widget-title:before,#available-widgets [class*=tube] .widget-title:before{content:"\f126"}#available-widgets [class*=music] .widget-title:before,#available-widgets [class*=radio] .widget-title:before,#available-widgets [class*=audio] .widget-title:before{content:"\f127"}#available-widgets [class*=login] .widget-title:before,#available-widgets [class*=user] .widget-title:before,#available-widgets [class*=member] .widget-title:before,#available-widgets [class*=avatar] .widget-title:before,#available-widgets [class*=subscriber] .widget-title:before,#available-widgets [class*=profile] .widget-title:before,#available-widgets [class*=grofile] .widget-title:before{content:"\f110"}#available-widgets [class*=commerce] .widget-title:before,#available-widgets [class*=shop] .widget-title:before,#available-widgets [class*=cart] .widget-title:before{content:"\f174";top:-4px}#available-widgets [class*=secur] .widget-title:before,#available-widgets [class*=firewall] .widget-title:before{content:"\f332"}#available-widgets [class*=analytic] .widget-title:before,#available-widgets [class*=stat] .widget-title:before,#available-widgets [class*=poll] .widget-title:before{content:"\f185"}#available-widgets [class*=form] .widget-title:before{content:"\f175"}#available-widgets [class*=subscribe] .widget-title:before,#available-widgets [class*=news] .widget-title:before,#available-widgets [class*=contact] .widget-title:before,#available-widgets [class*=mail] .widget-title:before{content:"\f466"}#available-widgets [class*=share] .widget-title:before,#available-widgets [class*=socia] .widget-title:before{content:"\f237"}#available-widgets [class*=lang] .widget-title:before,#available-widgets [class*=translat] .widget-title:before{content:"\f326"}#available-widgets [class*=locat] .widget-title:before,#available-widgets [class*=map] .widget-title:before{content:"\f231"}#available-widgets [class*=download] .widget-title:before{content:"\f316"}#available-widgets [class*=weather] .widget-title:before{content:"\f176";top:-4px}#available-widgets [class*=facebook] .widget-title:before{content:"\f304"}#available-widgets [class*=tweet] .widget-title:before,#available-widgets [class*=twitter] .widget-title:before{content:"\f301"}@media screen and (max-height:700px) and (min-width:981px){.customize-control-widget_form{margin-bottom:0}.widget-top{-webkit-box-shadow:none;box-shadow:none;margin-top:-1px}.widget-top:hover{position:relative;z-index:1}.last-widget{margin-bottom:15px}.widget-title h3{padding:13px 15px}.widget-top .widget-action{padding:8px 10px}.widget-reorder-nav span{height:39px}.widget-reorder-nav span:before{line-height:39px}#customize-theme-controls .widget-area-select li{padding:9px 15px 11px 42px}#customize-theme-controls .widget-area-select li:before{top:8px}}
\ No newline at end of file
+.control-section.control-section-sidebar .accordion-section-content.ui-sortable,.wp-full-overlay-sidebar{overflow:visible}.control-section.control-section-sidebar,.customize-control-sidebar_widgets .hide-if-js,.customize-control-sidebar_widgets label{display:none}.customize-control-widget_form .widget-top{background:#fff;-webkit-transition:opacity .5s;transition:opacity .5s}.customize-control .widget-action{color:#72777c}.customize-control .widget-action:focus,.customize-control .widget-top:hover .widget-action{color:#23282d}.customize-control-widget_form:not(.widget-rendered) .widget-top{opacity:.5}.customize-control-widget_form .widget-control-save{display:none}.customize-control-widget_form .spinner{visibility:hidden;margin-top:0}.customize-control-widget_form.previewer-loading .spinner{visibility:visible}.customize-control-widget_form.widget-form-disabled .widget-content{opacity:.7;pointer-events:none;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.customize-control-widget_form .widget{margin-bottom:0}.customize-control-widget_form.wide-widget-control .widget-inside{position:fixed;left:299px;top:25%;border:1px solid #e5e5e5;overflow:auto}.customize-control-widget_form.wide-widget-control .widget-inside>.form{padding:20px}.customize-control-widget_form.wide-widget-control .widget-top{-webkit-transition:background-color .4s;transition:background-color .4s}.customize-control-widget_form.wide-widget-control.expanded:not(.collapsing) .widget-top,.customize-control-widget_form.wide-widget-control.expanding .widget-top{background-color:#e3e3e3}.widget-inside{padding:1px 10px 10px;border-top:none;line-height:16px}.customize-control-widget_form.expanded .widget-action .toggle-indicator:before{content:"\f142"}.customize-control-widget_form.wide-widget-control .widget-action .toggle-indicator:before{content:"\f139"}.customize-control-widget_form.wide-widget-control.expanded .widget-action .toggle-indicator:before{content:"\f141"}.widget-title-action{cursor:pointer}.customize-control-widget_form .widget .customize-control-title,.widget-top{cursor:move}.control-section.accordion-section.highlighted>.accordion-section-title,.customize-control-widget_form.highlighted{outline:0;-webkit-box-shadow:0 0 2px rgba(30,140,190,.8);box-shadow:0 0 2px rgba(30,140,190,.8);position:relative;z-index:1}#widget-customizer-control-templates{display:none}#customize-theme-controls .widget-reorder-nav{display:none;float:right;background-color:#fafafa}.move-widget:before{content:"\f504"}#customize-theme-controls .move-widget-area{display:none;background:#fff;border:1px solid #ddd;border-top:none;cursor:auto}#customize-theme-controls .reordering .move-widget-area.active{display:block}#customize-theme-controls .move-widget-area .description{margin:0;padding:15px 20px;font-weight:400}#customize-theme-controls .widget-area-select{margin:0;padding:0;list-style:none}#customize-theme-controls .widget-area-select li{position:relative;margin:0;padding:13px 15px 15px 42px;color:#555;border-top:1px solid #eee;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#customize-theme-controls .widget-area-select li:before{display:none;content:"\f147";position:absolute;top:12px;left:10px;font:400 20px/1 dashicons;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#customize-theme-controls .widget-area-select li:last-child{border-bottom:1px solid #eee}#customize-theme-controls .widget-area-select .selected{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.4);background:#00a0d2}#customize-theme-controls .widget-area-select .selected:before{display:block}#customize-theme-controls .move-widget-actions{text-align:right;padding:12px}#customize-theme-controls .reordering .widget-title-action{display:none}#customize-theme-controls .reordering .widget-reorder-nav{display:block}.wp-customizer div.mce-inline-toolbar-grp,.wp-customizer div.mce-tooltip{z-index:500100!important}.wp-customizer .ui-autocomplete.wplink-autocomplete{z-index:500110}.wp-customizer #wp-link-backdrop{z-index:500100}.wp-customizer #wp-link-wrap{z-index:500105}#widgets-left #available-widgets .widget{float:none!important;width:auto!important}.ios #available-widgets{-webkit-transition:left 0s;transition:left 0s}#available-widgets .widget-tpl.selected,#available-widgets .widget-tpl:hover{background:#f3f3f5;border-bottom-color:#ccc;color:#0073aa;border-left:4px solid #0073aa}#customize-controls .widget-title h3{font-size:1em}#available-widgets .widget-title h3{padding:0 0 5px;font-size:14px}#available-widgets .widget .widget-description{padding:0;color:#72777c}#customize-preview{-webkit-transition:all .2s;transition:all .2s}body.adding-widget #available-widgets{left:0;visibility:visible}body.adding-widget .wp-full-overlay-main{left:300px}body.adding-widget #customize-preview{opacity:.4}#available-widgets .widget-title{position:relative}#available-widgets .widget-title:before{content:"\f132";position:absolute;top:-3px;right:100%;margin-right:20px;width:20px;height:20px;color:#32373c;font:400 20px/1 dashicons;text-align:center;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#available-widgets [class*=easy] .widget-title:before{content:"\f328";top:-4px}#available-widgets [class*=super] .widget-title:before,#available-widgets [class*=like] .widget-title:before{content:"\f155";top:-4px}#available-widgets [class*=meta] .widget-title:before{content:"\f120"}#available-widgets [class*=archives] .widget-title:before{content:"\f480";top:-4px}#available-widgets [class*=categor] .widget-title:before{content:"\f318";top:-4px}#available-widgets [class*=comment] .widget-title:before,#available-widgets [class*=testimonial] .widget-title:before,#available-widgets [class*=chat] .widget-title:before{content:"\f101"}#available-widgets [class*=post] .widget-title:before{content:"\f109"}#available-widgets [class*=page] .widget-title:before{content:"\f105"}#available-widgets [class*=text] .widget-title:before{content:"\f478"}#available-widgets [class*=link] .widget-title:before{content:"\f103"}#available-widgets [class*=search] .widget-title:before{content:"\f179"}#available-widgets [class*=menu] .widget-title:before,#available-widgets [class*=nav] .widget-title:before{content:"\f333"}#available-widgets [class*=tag] .widget-title:before{content:"\f479"}#available-widgets [class*=rss] .widget-title:before{content:"\f303";top:-6px}#available-widgets [class*=event] .widget-title:before,#available-widgets [class*=calendar] .widget-title:before{content:"\f145";top:-4px}#available-widgets [class*=image] .widget-title:before,#available-widgets [class*=photo] .widget-title:before,#available-widgets [class*=slide] .widget-title:before,#available-widgets [class*=instagram] .widget-title:before{content:"\f128"}#available-widgets [class*=album] .widget-title:before,#available-widgets [class*=galler] .widget-title:before{content:"\f161"}#available-widgets [class*=video] .widget-title:before,#available-widgets [class*=tube] .widget-title:before{content:"\f126"}#available-widgets [class*=music] .widget-title:before,#available-widgets [class*=radio] .widget-title:before,#available-widgets [class*=audio] .widget-title:before{content:"\f127"}#available-widgets [class*=login] .widget-title:before,#available-widgets [class*=user] .widget-title:before,#available-widgets [class*=member] .widget-title:before,#available-widgets [class*=avatar] .widget-title:before,#available-widgets [class*=subscriber] .widget-title:before,#available-widgets [class*=profile] .widget-title:before,#available-widgets [class*=grofile] .widget-title:before{content:"\f110"}#available-widgets [class*=commerce] .widget-title:before,#available-widgets [class*=shop] .widget-title:before,#available-widgets [class*=cart] .widget-title:before{content:"\f174";top:-4px}#available-widgets [class*=secur] .widget-title:before,#available-widgets [class*=firewall] .widget-title:before{content:"\f332"}#available-widgets [class*=analytic] .widget-title:before,#available-widgets [class*=stat] .widget-title:before,#available-widgets [class*=poll] .widget-title:before{content:"\f185"}#available-widgets [class*=form] .widget-title:before{content:"\f175"}#available-widgets [class*=subscribe] .widget-title:before,#available-widgets [class*=news] .widget-title:before,#available-widgets [class*=contact] .widget-title:before,#available-widgets [class*=mail] .widget-title:before{content:"\f466"}#available-widgets [class*=share] .widget-title:before,#available-widgets [class*=socia] .widget-title:before{content:"\f237"}#available-widgets [class*=lang] .widget-title:before,#available-widgets [class*=translat] .widget-title:before{content:"\f326"}#available-widgets [class*=locat] .widget-title:before,#available-widgets [class*=map] .widget-title:before{content:"\f231"}#available-widgets [class*=download] .widget-title:before{content:"\f316"}#available-widgets [class*=weather] .widget-title:before{content:"\f176";top:-4px}#available-widgets [class*=facebook] .widget-title:before{content:"\f304"}#available-widgets [class*=tweet] .widget-title:before,#available-widgets [class*=twitter] .widget-title:before{content:"\f301"}@media screen and (max-height:700px) and (min-width:981px){.customize-control-widget_form{margin-bottom:0}.widget-top{-webkit-box-shadow:none;box-shadow:none;margin-top:-1px}.widget-top:hover{position:relative;z-index:1}.last-widget{margin-bottom:15px}.widget-title h3{padding:13px 15px}.widget-top .widget-action{padding:8px 10px}.widget-reorder-nav span{height:39px}.widget-reorder-nav span:before{line-height:39px}#customize-theme-controls .widget-area-select li{padding:9px 15px 11px 42px}#customize-theme-controls .widget-area-select li:before{top:8px}}
\ No newline at end of file
diff --git a/wp-admin/js/widgets/text-widgets.js b/wp-admin/js/widgets/text-widgets.js
new file mode 100644
index 0000000000..2d3a5b812c
--- /dev/null
+++ b/wp-admin/js/widgets/text-widgets.js
@@ -0,0 +1,326 @@
+/* global tinymce, switchEditors */
+/* eslint consistent-this: [ "error", "control" ] */
+wp.textWidgets = ( function( $ ) {
+ 'use strict';
+
+ var component = {};
+
+ /**
+ * Text widget control.
+ *
+ * @class TextWidgetControl
+ * @constructor
+ * @abstract
+ */
+ component.TextWidgetControl = Backbone.View.extend({
+
+ /**
+ * View events.
+ *
+ * @type {Object}
+ */
+ events: {},
+
+ /**
+ * Initialize.
+ *
+ * @param {Object} options - Options.
+ * @param {Backbone.Model} options.model - Model.
+ * @param {jQuery} options.el - Control container element.
+ * @returns {void}
+ */
+ initialize: function initialize( options ) {
+ var control = this;
+
+ if ( ! options.el ) {
+ throw new Error( 'Missing options.el' );
+ }
+
+ Backbone.View.prototype.initialize.call( control, options );
+
+ /*
+ * Create a container element for the widget control fields.
+ * This is inserted into the DOM immediately before the the .widget-content
+ * element because the contents of this element are essentially "managed"
+ * by PHP, where each widget update cause the entire element to be emptied
+ * and replaced with the rendered output of WP_Widget::form() which is
+ * sent back in Ajax request made to save/update the widget instance.
+ * To prevent a "flash of replaced DOM elements and re-initialized JS
+ * components", the JS template is rendered outside of the normal form
+ * container.
+ */
+ control.fieldContainer = $( '' );
+ control.fieldContainer.html( wp.template( 'widget-text-control-fields' ) );
+ control.widgetContentContainer = control.$el.find( '.widget-content:first' );
+ control.widgetContentContainer.before( control.fieldContainer );
+
+ control.fields = {
+ title: control.fieldContainer.find( '.title' ),
+ text: control.fieldContainer.find( '.text' )
+ };
+
+ // Sync input fields to hidden sync fields which actually get sent to the server.
+ _.each( control.fields, function( fieldInput, fieldName ) {
+ fieldInput.on( 'input change', function updateSyncField() {
+ var syncInput = control.widgetContentContainer.find( 'input[type=hidden].' + fieldName );
+ if ( syncInput.val() !== $( this ).val() ) {
+ syncInput.val( $( this ).val() );
+ syncInput.trigger( 'change' );
+ }
+ });
+
+ // Note that syncInput cannot be re-used because it will be destroyed with each widget-updated event.
+ fieldInput.val( control.widgetContentContainer.find( 'input[type=hidden].' + fieldName ).val() );
+ });
+ },
+
+ /**
+ * Update input fields from the sync fields.
+ *
+ * This function is called at the widget-updated and widget-synced events.
+ * A field will only be updated if it is not currently focused, to avoid
+ * overwriting content that the user is entering.
+ *
+ * @returns {void}
+ */
+ updateFields: function updateFields() {
+ var control = this, syncInput;
+
+ if ( ! control.fields.title.is( document.activeElement ) ) {
+ syncInput = control.widgetContentContainer.find( 'input[type=hidden].title' );
+ control.fields.title.val( syncInput.val() );
+ }
+
+ syncInput = control.widgetContentContainer.find( 'input[type=hidden].text' );
+ if ( control.fields.text.is( ':visible' ) ) {
+ if ( ! control.fields.text.is( document.activeElement ) ) {
+ control.fields.text.val( syncInput.val() );
+ }
+ } else if ( control.editor && ! control.editorFocused && syncInput.val() !== control.fields.text.val() ) {
+ control.editor.setContent( wp.editor.autop( syncInput.val() ) );
+ }
+ },
+
+ /**
+ * Initialize editor.
+ *
+ * @returns {void}
+ */
+ initializeEditor: function initializeEditor() {
+ var control = this, changeDebounceDelay = 1000, id, textarea, restoreTextMode = false;
+ textarea = control.fields.text;
+ id = textarea.attr( 'id' );
+
+ /**
+ * Build (or re-build) the visual editor.
+ *
+ * @returns {void}
+ */
+ function buildEditor() {
+ var editor, triggerChangeIfDirty, onInit;
+
+ // Abort building if the textarea is gone, likely due to the widget having been deleted entirely.
+ if ( ! document.getElementById( id ) ) {
+ return;
+ }
+
+ // Destroy any existing editor so that it can be re-initialized after a widget-updated event.
+ if ( tinymce.get( id ) ) {
+ restoreTextMode = tinymce.get( id ).isHidden();
+ wp.editor.remove( id );
+ }
+
+ wp.editor.initialize( id, {
+ tinymce: {
+ wpautop: true
+ },
+ quicktags: true
+ } );
+
+ editor = window.tinymce.get( id );
+ if ( ! editor ) {
+ throw new Error( 'Failed to initialize editor' );
+ }
+ onInit = function() {
+
+ // When a widget is moved in the DOM the dynamically-created TinyMCE iframe will be destroyed and has to be re-built.
+ $( editor.getWin() ).on( 'unload', function() {
+ _.defer( buildEditor );
+ });
+
+ // If a prior mce instance was replaced, and it was in text mode, toggle to text mode.
+ if ( restoreTextMode ) {
+ switchEditors.go( id, 'toggle' );
+ }
+ };
+
+ if ( editor.initialized ) {
+ onInit();
+ } else {
+ editor.on( 'init', onInit );
+ }
+
+ control.editorFocused = false;
+ triggerChangeIfDirty = function() {
+ var updateWidgetBuffer = 300; // See wp.customize.Widgets.WidgetControl._setupUpdateUI() which uses 250ms for updateWidgetDebounced.
+ if ( editor.isDirty() ) {
+
+ /*
+ * Account for race condition in customizer where user clicks Save & Publish while
+ * focus was just previously given to to the editor. Since updates to the editor
+ * are debounced at 1 second and since widget input changes are only synced to
+ * settings after 250ms, the customizer needs to be put into the processing
+ * state during the time between the change event is triggered and updateWidget
+ * logic starts. Note that the debounced update-widget request should be able
+ * to be removed with the removal of the update-widget request entirely once
+ * widgets are able to mutate their own instance props directly in JS without
+ * having to make server round-trips to call the respective WP_Widget::update()
+ * callbacks. See .
+ */
+ if ( wp.customize ) {
+ wp.customize.state( 'processing' ).set( wp.customize.state( 'processing' ).get() + 1 );
+ _.delay( function() {
+ wp.customize.state( 'processing' ).set( wp.customize.state( 'processing' ).get() - 1 );
+ }, updateWidgetBuffer );
+ }
+
+ editor.save();
+ textarea.trigger( 'change' );
+ }
+ };
+ editor.on( 'focus', function() {
+ control.editorFocused = true;
+ } );
+ editor.on( 'NodeChange', _.debounce( triggerChangeIfDirty, changeDebounceDelay ) );
+ editor.on( 'blur', function() {
+ control.editorFocused = false;
+ triggerChangeIfDirty();
+ } );
+
+ control.editor = editor;
+ }
+
+ buildEditor();
+ }
+ });
+
+ /**
+ * Mapping of widget ID to instances of TextWidgetControl subclasses.
+ *
+ * @type {Object.}
+ */
+ component.widgetControls = {};
+
+ /**
+ * Handle widget being added or initialized for the first time at the widget-added event.
+ *
+ * @param {jQuery.Event} event - Event.
+ * @param {jQuery} widgetContainer - Widget container element.
+ * @returns {void}
+ */
+ component.handleWidgetAdded = function handleWidgetAdded( event, widgetContainer ) {
+ var widgetForm, idBase, widgetControl, widgetId, animatedCheckDelay = 50, widgetInside, renderWhenAnimationDone;
+ widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' ); // Note: '.form' appears in the customizer, whereas 'form' on the widgets admin screen.
+
+ idBase = widgetForm.find( '> .id_base' ).val();
+ if ( 'text' !== idBase ) {
+ return;
+ }
+
+ // Prevent initializing already-added widgets.
+ widgetId = widgetForm.find( '> .widget-id' ).val();
+ if ( component.widgetControls[ widgetId ] ) {
+ return;
+ }
+
+ widgetControl = new component.TextWidgetControl({
+ el: widgetContainer
+ });
+
+ component.widgetControls[ widgetId ] = widgetControl;
+
+ /*
+ * Render the widget once the widget parent's container finishes animating,
+ * as the widget-added event fires with a slideDown of the container.
+ * This ensures that the textarea is visible and an iframe can be embedded
+ * with TinyMCE being able to set contenteditable on it.
+ */
+ widgetInside = widgetContainer.parent();
+ renderWhenAnimationDone = function() {
+ if ( widgetInside.is( ':animated' ) ) {
+ setTimeout( renderWhenAnimationDone, animatedCheckDelay );
+ } else {
+ widgetControl.initializeEditor();
+ }
+ };
+ renderWhenAnimationDone();
+ };
+
+ /**
+ * Sync widget instance data sanitized from server back onto widget model.
+ *
+ * This gets called via the 'widget-updated' event when saving a widget from
+ * the widgets admin screen and also via the 'widget-synced' event when making
+ * a change to a widget in the customizer.
+ *
+ * @param {jQuery.Event} event - Event.
+ * @param {jQuery} widgetContainer - Widget container element.
+ * @returns {void}
+ */
+ component.handleWidgetUpdated = function handleWidgetUpdated( event, widgetContainer ) {
+ var widgetForm, widgetId, widgetControl, idBase;
+ widgetForm = widgetContainer.find( '> .widget-inside > .form, > .widget-inside > form' );
+
+ idBase = widgetForm.find( '> .id_base' ).val();
+ if ( 'text' !== idBase ) {
+ return;
+ }
+
+ widgetId = widgetForm.find( '> .widget-id' ).val();
+ widgetControl = component.widgetControls[ widgetId ];
+ if ( ! widgetControl ) {
+ return;
+ }
+
+ widgetControl.updateFields();
+ };
+
+ /**
+ * Initialize functionality.
+ *
+ * This function exists to prevent the JS file from having to boot itself.
+ * When WordPress enqueues this script, it should have an inline script
+ * attached which calls wp.textWidgets.init().
+ *
+ * @returns {void}
+ */
+ component.init = function init() {
+ var $document = $( document );
+ $document.on( 'widget-added', component.handleWidgetAdded );
+ $document.on( 'widget-synced widget-updated', component.handleWidgetUpdated );
+
+ /*
+ * Manually trigger widget-added events for media widgets on the admin
+ * screen once they are expanded. The widget-added event is not triggered
+ * for each pre-existing widget on the widgets admin screen like it is
+ * on the customizer. Likewise, the customizer only triggers widget-added
+ * when the widget is expanded to just-in-time construct the widget form
+ * when it is actually going to be displayed. So the following implements
+ * the same for the widgets admin screen, to invoke the widget-added
+ * handler when a pre-existing media widget is expanded.
+ */
+ $( function initializeExistingWidgetContainers() {
+ var widgetContainers;
+ if ( 'widgets' !== window.pagenow ) {
+ return;
+ }
+ widgetContainers = $( '.widgets-holder-wrap:not(#available-widgets)' ).find( 'div.widget' );
+ widgetContainers.one( 'click.toggle-widget-expanded', function toggleWidgetExpanded() {
+ var widgetContainer = $( this );
+ component.handleWidgetAdded( new jQuery.Event( 'widget-added' ), widgetContainer );
+ });
+ });
+ };
+
+ return component;
+})( jQuery );
diff --git a/wp-admin/js/widgets/text-widgets.min.js b/wp-admin/js/widgets/text-widgets.min.js
new file mode 100644
index 0000000000..d94472407b
--- /dev/null
+++ b/wp-admin/js/widgets/text-widgets.min.js
@@ -0,0 +1 @@
+wp.textWidgets=function(a){"use strict";var b={};return b.TextWidgetControl=Backbone.View.extend({events:{},initialize:function(b){var c=this;if(!b.el)throw new Error("Missing options.el");Backbone.View.prototype.initialize.call(c,b),c.fieldContainer=a(''),c.fieldContainer.html(wp.template("widget-text-control-fields")),c.widgetContentContainer=c.$el.find(".widget-content:first"),c.widgetContentContainer.before(c.fieldContainer),c.fields={title:c.fieldContainer.find(".title"),text:c.fieldContainer.find(".text")},_.each(c.fields,function(b,d){b.on("input change",function(){var b=c.widgetContentContainer.find("input[type=hidden]."+d);b.val()!==a(this).val()&&(b.val(a(this).val()),b.trigger("change"))}),b.val(c.widgetContentContainer.find("input[type=hidden]."+d).val())})},updateFields:function(){var a,b=this;b.fields.title.is(document.activeElement)||(a=b.widgetContentContainer.find("input[type=hidden].title"),b.fields.title.val(a.val())),a=b.widgetContentContainer.find("input[type=hidden].text"),b.fields.text.is(":visible")?b.fields.text.is(document.activeElement)||b.fields.text.val(a.val()):b.editor&&!b.editorFocused&&a.val()!==b.fields.text.val()&&b.editor.setContent(wp.editor.autop(a.val()))},initializeEditor:function(){function b(){var h,i,j;if(document.getElementById(c)){if(tinymce.get(c)&&(g=tinymce.get(c).isHidden(),wp.editor.remove(c)),wp.editor.initialize(c,{tinymce:{wpautop:!0},quicktags:!0}),h=window.tinymce.get(c),!h)throw new Error("Failed to initialize editor");j=function(){a(h.getWin()).on("unload",function(){_.defer(b)}),g&&switchEditors.go(c,"toggle")},h.initialized?j():h.on("init",j),e.editorFocused=!1,i=function(){var a=300;h.isDirty()&&(wp.customize&&(wp.customize.state("processing").set(wp.customize.state("processing").get()+1),_.delay(function(){wp.customize.state("processing").set(wp.customize.state("processing").get()-1)},a)),h.save(),d.trigger("change"))},h.on("focus",function(){e.editorFocused=!0}),h.on("NodeChange",_.debounce(i,f)),h.on("blur",function(){e.editorFocused=!1,i()}),e.editor=h}}var c,d,e=this,f=1e3,g=!1;d=e.fields.text,c=d.attr("id"),b()}}),b.widgetControls={},b.handleWidgetAdded=function(a,c){var d,e,f,g,h,i,j=50;d=c.find("> .widget-inside > .form, > .widget-inside > form"),e=d.find("> .id_base").val(),"text"===e&&(g=d.find("> .widget-id").val(),b.widgetControls[g]||(f=new b.TextWidgetControl({el:c}),b.widgetControls[g]=f,h=c.parent(),(i=function(){h.is(":animated")?setTimeout(i,j):f.initializeEditor()})()))},b.handleWidgetUpdated=function(a,c){var d,e,f,g;d=c.find("> .widget-inside > .form, > .widget-inside > form"),g=d.find("> .id_base").val(),"text"===g&&(e=d.find("> .widget-id").val(),f=b.widgetControls[e],f&&f.updateFields())},b.init=function(){var c=a(document);c.on("widget-added",b.handleWidgetAdded),c.on("widget-synced widget-updated",b.handleWidgetUpdated),a(function(){var c;"widgets"===window.pagenow&&(c=a(".widgets-holder-wrap:not(#available-widgets)").find("div.widget"),c.one("click.toggle-widget-expanded",function(){var c=a(this);b.handleWidgetAdded(new jQuery.Event("widget-added"),c)}))})},b}(jQuery);
\ No newline at end of file
diff --git a/wp-includes/default-filters.php b/wp-includes/default-filters.php
index e6050774c6..ef412e9e6a 100644
--- a/wp-includes/default-filters.php
+++ b/wp-includes/default-filters.php
@@ -164,7 +164,11 @@ add_filter( 'list_cats', 'wptexturize' );
add_filter( 'wp_sprintf', 'wp_sprintf_l', 10, 2 );
-add_filter( 'widget_text', 'balanceTags' );
+add_filter( 'widget_text', 'balanceTags' );
+add_filter( 'widget_text_content', 'capital_P_dangit', 11 );
+add_filter( 'widget_text_content', 'wptexturize' );
+add_filter( 'widget_text_content', 'convert_smilies', 20 );
+add_filter( 'widget_text_content', 'wpautop' );
add_filter( 'date_i18n', 'wp_maybe_decline_date' );
diff --git a/wp-includes/script-loader.php b/wp-includes/script-loader.php
index 43209721f5..344bc4559b 100644
--- a/wp-includes/script-loader.php
+++ b/wp-includes/script-loader.php
@@ -602,6 +602,8 @@ function wp_default_scripts( &$scripts ) {
$scripts->add( 'admin-gallery', "/wp-admin/js/gallery$suffix.js", array( 'jquery-ui-sortable' ) );
$scripts->add( 'admin-widgets', "/wp-admin/js/widgets$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable' ), false, 1 );
+ $scripts->add( 'text-widgets', "/wp-admin/js/widgets/text-widgets$suffix.js", array( 'jquery', 'backbone', 'editor', 'wp-util' ) );
+ $scripts->add_inline_script( 'text-widgets', 'wp.textWidgets.init();', 'after' );
$scripts->add( 'theme', "/wp-admin/js/theme$suffix.js", array( 'wp-backbone', 'wp-a11y' ), false, 1 );
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 29ca78eb81..ff7c02a8aa 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -4,7 +4,7 @@
*
* @global string $wp_version
*/
-$wp_version = '4.8-alpha-40630';
+$wp_version = '4.8-alpha-40631';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
diff --git a/wp-includes/widgets/class-wp-widget-text.php b/wp-includes/widgets/class-wp-widget-text.php
index a379fd719d..434a123f90 100644
--- a/wp-includes/widgets/class-wp-widget-text.php
+++ b/wp-includes/widgets/class-wp-widget-text.php
@@ -28,10 +28,30 @@ class WP_Widget_Text extends WP_Widget {
'description' => __( 'Arbitrary text or HTML.' ),
'customize_selective_refresh' => true,
);
- $control_ops = array( 'width' => 400, 'height' => 350 );
+ $control_ops = array(
+ 'width' => 400,
+ 'height' => 350,
+ );
parent::__construct( 'text', __( 'Text' ), $widget_ops, $control_ops );
}
+ /**
+ * Add hooks for enqueueing assets when registering all widget instances of this widget class.
+ *
+ * @since 4.8.0
+ * @access public
+ */
+ public function _register() {
+
+ // Note that the widgets component in the customizer will also do the 'admin_print_scripts-widgets.php' action in WP_Customize_Widgets::print_scripts().
+ add_action( 'admin_print_scripts-widgets.php', array( $this, 'enqueue_admin_scripts' ) );
+
+ // Note that the widgets component in the customizer will also do the 'admin_footer-widgets.php' action in WP_Customize_Widgets::print_footer_scripts().
+ add_action( 'admin_footer-widgets.php', array( $this, 'render_control_template_scripts' ) );
+
+ parent::_register();
+ }
+
/**
* Outputs the content for the current Text widget instance.
*
@@ -61,11 +81,34 @@ class WP_Widget_Text extends WP_Widget {
*/
$text = apply_filters( 'widget_text', $widget_text, $instance, $this );
+ if ( isset( $instance['filter'] ) ) {
+ if ( 'content' === $instance['filter'] ) {
+
+ /**
+ * Filters the content of the Text widget to apply changes expected from the visual (TinyMCE) editor.
+ *
+ * By default a subset of the_content filters are applied, including wpautop and wptexturize.
+ *
+ * @since 4.8.0
+ *
+ * @param string $widget_text The widget content.
+ * @param array $instance Array of settings for the current widget.
+ * @param WP_Widget_Text $this Current Text widget instance.
+ */
+ $text = apply_filters( 'widget_text_content', $widget_text, $instance, $this );
+
+ } elseif ( $instance['filter'] ) {
+ $text = wpautop( $text ); // Back-compat for instances prior to 4.8.
+ }
+ }
+
echo $args['before_widget'];
if ( ! empty( $title ) ) {
echo $args['before_title'] . $title . $args['after_title'];
- } ?>
-
+ }
+
+ ?>
+
'', 'text' => '' ) );
- $filter = isset( $instance['filter'] ) ? $instance['filter'] : 0;
- $title = sanitize_text_field( $instance['title'] );
+ $instance = wp_parse_args(
+ (array) $instance,
+ array(
+ 'title' => '',
+ 'text' => '',
+ )
+ );
?>
-
-
+
+
+
-
-
- />
+ /**
+ * Render form template scripts.
+ *
+ * @since 4.8.0
+ * @access public
+ */
+ public function render_control_template_scripts() {
+ ?>
+