Index: src/wp-admin/admin-ajax.php
===================================================================
--- src/wp-admin/admin-ajax.php	(revision 31531)
+++ src/wp-admin/admin-ajax.php	(working copy)
@@ -61,7 +61,8 @@
 	'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor',
 	'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs',
 	'save-user-color-scheme', 'update-widget', 'query-themes', 'parse-embed', 'set-attachment-thumbnail',
-	'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin'
+	'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin', 'press-this-save-post',
+	'press-this-add-category',
 );
 
 // Register core Ajax calls.
Index: src/wp-admin/css/forms.css
===================================================================
--- src/wp-admin/css/forms.css	(revision 31531)
+++ src/wp-admin/css/forms.css	(working copy)
@@ -684,6 +684,9 @@
 
 .pressthis {
 	margin: 20px 0;
+	vertical-align: top;
+	position: relative;
+	z-index: 1;
 }
 
 .pressthis a,
@@ -748,6 +751,34 @@
 	box-shadow: 0 10px 8px rgba(0, 0, 0, 0.6);
 }
 
+.pressthis .button {
+	margin-left: 10px;
+	padding: 0;
+	height: auto;
+	vertical-align: top;
+}
+
+.pressthis button .dashicons {
+	margin: 5px 8px 6px 7px;
+	color: #777;
+}
+
+.press-this-install {
+	margin: 20px 0 0 0;
+	padding: 0.7em 2em 1em;
+	max-width: 520px;
+}
+
+.press-this-install textarea {
+	width: 100%;
+	font-size: 1em;
+}
+
+.press-this-install h4 {
+	margin: 2em 0 1em;
+}
+
+
 /*------------------------------------------------------------------------------
   20.0 - Settings
 ------------------------------------------------------------------------------*/
Index: src/wp-admin/css/press-this-editor.css
===================================================================
--- src/wp-admin/css/press-this-editor.css	(revision 0)
+++ src/wp-admin/css/press-this-editor.css	(working copy)
@@ -0,0 +1,492 @@
+/*
+Press This TinyMCE editor styles :)
+*/
+
+
+/**
+* Links
+*/
+@import url("//fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,600,700");
+a {
+	color: #0074a2;
+}
+
+a:visited {
+	color: #0074a2;
+}
+
+a:hover,
+a:focus,
+a:active {
+	color: #2ea2cc;
+}
+
+
+/**
+* Lists
+*/
+ul,
+ol {
+	margin: 0 0 1.5em 3em;
+}
+
+ul {
+	list-style: disc;
+}
+
+ol {
+	list-style: decimal;
+}
+
+li > ul,
+li > ol {
+	margin-bottom: 0;
+	margin-left: 1.5em;
+}
+
+dt {
+	font-weight: 700;
+}
+
+dd {
+	margin: 0 1.5em 1.5em;
+}
+
+
+/**
+* Media
+*
+* Basic image and object styles
+*/
+img {
+	max-width: 100%;
+	height: auto;
+}
+
+/* Makes sure embeds and iframes fit inside their containers */
+embed,
+iframe,
+object {
+	max-width: 100%;
+}
+
+
+/**
+* TinyMCE styles
+*
+* Pretty dang good.
+*/
+body {
+	color: #404040;
+	font-family: "Open Sans", Helvetica, Arial, sans-serif;
+	font-size: 20px;
+	font-weight: 400;
+	line-height: 1.6;
+}
+@media (max-width: 900px) {
+	body#tinymce {
+		padding-top: 30px !important;
+	}
+}
+@media (max-width: 640px) {
+	body {
+		font-size: 16px;
+	}
+}
+@media (max-width: 320px) {
+	body {
+		margin: 0 15px;
+	}
+}
+
+#tinymce b,
+#tinymce strong {
+	/* overrides TinyMCE's !important. Woohoo. */
+	font-weight: 700 !important;
+}
+
+blockquote {
+	margin: 1em 1.5em;
+	color: #9ea7af;
+	font-size: em(25px);
+	font-style: italic;
+}
+@media (max-width: 900px) {
+	blockquote {
+		margin: 1.5em 1em;
+	}
+}
+
+ul,
+ol {
+	margin: 0 0 1.5em .75em;
+}
+/*
+Press This TinyMCE editor styles :)
+*/
+
+
+/**
+* Links
+*/
+@import url("//fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,600,700");
+a {
+	color: #0074a2;
+}
+
+a:visited {
+	color: #0074a2;
+}
+
+a:hover,
+a:focus,
+a:active {
+	color: #2ea2cc;
+}
+
+
+/**
+* Lists
+*/
+ul,
+ol {
+	margin: 0 0 1.5em 3em;
+}
+
+ul {
+	list-style: disc;
+}
+
+ol {
+	list-style: decimal;
+}
+
+li > ul,
+li > ol {
+	margin-bottom: 0;
+	margin-left: 1.5em;
+}
+
+dt {
+	font-weight: 700;
+}
+
+dd {
+	margin: 0 1.5em 1.5em;
+}
+
+
+/**
+* Media
+*
+* Basic image and object styles
+*/
+img {
+	max-width: 100%;
+	height: auto;
+}
+
+/* Makes sure embeds and iframes fit inside their containers */
+embed,
+iframe,
+object {
+	max-width: 100%;
+}
+
+
+/**
+* TinyMCE styles
+*
+* Pretty dang good.
+*/
+body {
+	color: #404040;
+	font-family: "Open Sans", Helvetica, Arial, sans-serif;
+	font-size: 20px;
+	font-weight: 400;
+	line-height: 1.6;
+}
+@media (max-width: 900px) {
+	body#tinymce {
+		padding-top: 30px !important;
+	}
+}
+@media (max-width: 640px) {
+	body {
+		font-size: 16px;
+	}
+}
+@media (max-width: 320px) {
+	body {
+		margin: 0 15px;
+	}
+}
+
+#tinymce b,
+#tinymce strong {
+	/* overrides TinyMCE's !important. Woohoo. */
+	font-weight: 700 !important;
+}
+
+blockquote {
+	margin: 1em 1.5em;
+	color: #9ea7af;
+	font-size: em(25px);
+	font-style: italic;
+}
+@media (max-width: 900px) {
+	blockquote {
+		margin: 1.5em 1em;
+	}
+}
+
+ul,
+ol {
+	margin: 0 0 1.5em .75em;
+}
+/*
+Press This TinyMCE editor styles :)
+*/
+
+
+/**
+* Links
+*/
+@import url("//fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,600,700");
+a {
+	color: #0074a2;
+}
+
+a:visited {
+	color: #0074a2;
+}
+
+a:hover,
+a:focus,
+a:active {
+	color: #2ea2cc;
+}
+
+
+/**
+* Lists
+*/
+ul,
+ol {
+	margin: 0 0 1.5em 3em;
+}
+
+ul {
+	list-style: disc;
+}
+
+ol {
+	list-style: decimal;
+}
+
+li > ul,
+li > ol {
+	margin-bottom: 0;
+	margin-left: 1.5em;
+}
+
+dt {
+	font-weight: 700;
+}
+
+dd {
+	margin: 0 1.5em 1.5em;
+}
+
+
+/**
+* Media
+*
+* Basic image and object styles
+*/
+img {
+	max-width: 100%;
+	height: auto;
+}
+
+/* Makes sure embeds and iframes fit inside their containers */
+embed,
+iframe,
+object {
+	max-width: 100%;
+}
+
+
+/**
+* TinyMCE styles
+*
+* Pretty dang good.
+*/
+body {
+	color: #404040;
+	font-family: "Open Sans", Helvetica, Arial, sans-serif;
+	font-size: 20px;
+	font-weight: 400;
+	line-height: 1.6;
+}
+@media (max-width: 900px) {
+	body#tinymce {
+		padding-top: 30px !important;
+	}
+}
+@media (max-width: 640px) {
+	body {
+		font-size: 16px;
+	}
+}
+@media (max-width: 320px) {
+	body {
+		margin: 0 15px;
+	}
+}
+
+#tinymce b,
+#tinymce strong {
+	/* overrides TinyMCE's !important. Woohoo. */
+	font-weight: 700 !important;
+}
+
+blockquote {
+	margin: 1em 1.5em;
+	color: #9ea7af;
+	font-size: em(25px);
+	font-style: italic;
+}
+@media (max-width: 900px) {
+	blockquote {
+		margin: 1.5em 1em;
+	}
+}
+
+ul,
+ol {
+	margin: 0 0 1.5em .75em;
+}
+/*
+Press This TinyMCE editor styles :)
+*/
+
+
+/**
+* Links
+*/
+@import url("//fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,600,700");
+a {
+	color: #0074a2;
+}
+
+a:visited {
+	color: #0074a2;
+}
+
+a:hover,
+a:focus,
+a:active {
+	color: #2ea2cc;
+}
+
+
+/**
+* Lists
+*/
+ul,
+ol {
+	margin: 0 0 1.5em 3em;
+}
+
+ul {
+	list-style: disc;
+}
+
+ol {
+	list-style: decimal;
+}
+
+li > ul,
+li > ol {
+	margin-bottom: 0;
+	margin-left: 1.5em;
+}
+
+dt {
+	font-weight: 700;
+}
+
+dd {
+	margin: 0 1.5em 1.5em;
+}
+
+
+/**
+* Media
+*
+* Basic image and object styles
+*/
+img {
+	max-width: 100%;
+	height: auto;
+}
+
+/* Makes sure embeds and iframes fit inside their containers */
+embed,
+iframe,
+object {
+	max-width: 100%;
+}
+
+
+/**
+* TinyMCE styles
+*
+* Pretty dang good.
+*/
+body {
+	color: #404040;
+	font-family: "Open Sans", Helvetica, Arial, sans-serif;
+	font-size: 20px;
+	font-weight: 400;
+	line-height: 1.6;
+}
+@media (max-width: 900px) {
+	body#tinymce {
+		padding-top: 30px !important;
+	}
+}
+@media (max-width: 640px) {
+	body {
+		font-size: 16px;
+	}
+}
+@media (max-width: 320px) {
+	body {
+		margin: 0 15px;
+	}
+}
+
+#tinymce b,
+#tinymce strong {
+	/* overrides TinyMCE's !important. Woohoo. */
+	font-weight: 700 !important;
+}
+
+blockquote {
+	margin: 1em 1.5em;
+	color: #9ea7af;
+	font-size: em(25px);
+	font-style: italic;
+}
+@media (max-width: 900px) {
+	blockquote {
+		margin: 1.5em 1em;
+	}
+}
+
+ul,
+ol {
+	margin: 0 0 1.5em .75em;
+}
Index: src/wp-admin/css/press-this.css
===================================================================
--- src/wp-admin/css/press-this.css	(revision 31531)
+++ src/wp-admin/css/press-this.css	(working copy)
@@ -1,458 +1,1977 @@
-.press-this #message {
-	border-left: 4px solid #7ad03a;
-	padding: 1px 12px;
-	background-color: #fff;
-	-webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,0.1);
-	box-shadow: 0 1px 1px 0 rgba(0,0,0,0.1);
+/*
+Press This styles :)
+*/
+
+
+/**
+* Normalize
+*
+* normalize.css v3.0.0 | MIT License | git.io/normalize
+*/
+html {
+	font-family: sans-serif;
+	-ms-text-size-adjust: 100%;
+	-webkit-text-size-adjust: 100%;
 }
 
-.press-this #side-sortables .category-tabs li {
-	display: inline;
-	line-height: 1.35em;
+body {
+	margin: 0;
 }
 
-body.press-this ul.category-tabs li.tabs a {
-	color: #32373c;
+*,
+*:before,
+*:after {
+	-webkit-box-sizing: border-box;
+	-moz-box-sizing: border-box;
+	box-sizing: border-box;
 }
+@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) {
+	*,
+	*:before,
+	*:after {
+		-webkit-font-smoothing: antialiased;
+	}
+}
 
-.press-this #content-resize-handle {
-	bottom: 2px;
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section,
+summary {
+	display: block;
 }
 
-body.press-this {
-	color: #32373c;
-	margin: 0;
-	padding: 0;
-	min-width: 708px;
-	min-height: 400px;
+audio,
+canvas,
+progress,
+video {
+	display: inline-block;
+	vertical-align: baseline;
 }
 
-.press-this #titlediv #title {
-	font-size: 1.4em;
+audio:not([controls]) {
+	display: none;
+	height: 0;
 }
 
-.press-this #site-heading:before {
-    top: 3px;
-    position: relative;
-    display: inline-block;
-    font: normal 18px/1 'dashicons';
-    speak: none;
-    color: #727272;
-    content: '\f120';
-    -webkit-font-smoothing: antialiased;
-    -moz-osx-font-smoothing: grayscale;
+[hidden],
+template {
+	display: none;
 }
 
-.press-this #wphead {
-	height: 32px;
-	margin-left: 0;
-	margin-right: 0;
-	margin-bottom: 5px;
+a {
+	background: transparent;
 }
 
-.press-this #header-logo {
-	float: left;
-	margin: 7px 7px 0;
-	-webkit-user-select: none;
-	-moz-user-select: none;
-	-ms-user-select: none;
-	user-select: none;
+a:active,
+a:hover {
+	outline: 0;
 }
 
-.press-this #wphead h1 {
-	font-weight: normal;
-	font-size: 16px;
-	line-height: 32px;
-	margin: 0;
-	float: left;
+abbr[title] {
+	border-bottom: 1px dotted;
 }
 
-.press-this #wphead h1 a {
-	text-decoration: none;
+b,
+strong {
+	font-weight: bold;
 }
 
-.press-this #wphead h1 a:hover {
-	text-decoration: underline;
+dfn {
+	font-style: italic;
 }
 
-.press-this #message {
-	margin: 10px 0;
+h1 {
+	font-size: 2em;
+	margin: 0.67em 0;
 }
 
-.press-this .posting {
-	margin-right: 250px;
+mark {
+	background: #ff0;
+	color: #000;
 }
 
-.press-this-sidebar {
-	float: right;
-	width: 240px;
-	padding-top: 10px;
+small {
+	font-size: 80%;
 }
 
-.press-this #title {
-	margin-left: 0;
-	margin-right: 0;
-	-webkit-box-sizing: border-box;
-	-moz-box-sizing: border-box;
-	box-sizing: border-box;
+sub,
+sup {
+	font-size: 75%;
+	line-height: 0;
+	position: relative;
+	vertical-align: baseline;
 }
 
-.press-this .tagchecklist {
-	margin-top: 8px;
+sup {
+	top: -0.5em;
 }
 
-.press-this #titlediv {
-	margin: 0;
+sub {
+	bottom: -0.25em;
 }
 
-.press-this #wp-content-wrap #wp-content-editor-tools {
-	padding: 0;
-	top: 3px;
+img {
+	border: 0;
+}
+
+svg:not(:root) {
 	overflow: hidden;
 }
 
-.press-this .wp-media-buttons {
+figure {
+	margin: 1em 40px;
+}
+
+hr {
+	-webkit-box-sizing: content-box;
+	-moz-box-sizing: content-box;
+	box-sizing: content-box;
+	height: 0;
+}
+
+pre {
+	overflow: auto;
+}
+
+code,
+kbd,
+pre,
+samp {
+	font-family: monospace, monospace;
+	font-size: 1em;
+}
+
+button,
+input,
+optgroup,
+select,
+textarea {
+	color: inherit;
+	font: inherit;
+	margin: 0;
+}
+
+button {
+	overflow: visible;
+}
+
+button,
+select {
+	text-transform: none;
+}
+
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+	-webkit-appearance: button;
+	cursor: pointer;
+}
+
+button[disabled],
+html input[disabled] {
 	cursor: default;
-	padding: 8px 8px 6px;
 }
 
-.press-this #wp-content-wrap #wp-content-media-buttons a {
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+	border: 0;
 	padding: 0;
+}
+
+input {
 	line-height: normal;
+}
+
+input[type="checkbox"],
+input[type="radio"] {
+	-webkit-box-sizing: border-box;
+	-moz-box-sizing: border-box;
+	box-sizing: border-box;
+	padding: 0;
+}
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
 	height: auto;
-	font-size: 16px;
 }
 
-.press-this #wp-content-wrap .mce-toolbar .mce-btn-group .mce-btn {
-	margin: 0 1px;
+input[type="search"] {
+	-webkit-appearance: textfield;
+	-webkit-box-sizing: content-box;
+	-moz-box-sizing: content-box;
+	box-sizing: content-box;
 }
 
-.press-this #wp-content-wrap .mce-toolbar .mce-btn button {
-	padding: 2px 3px;
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+	-webkit-appearance: none;
 }
 
-.press-this #wp-content-wrap div.mce-toolbar-grp,
-.press-this #wp-content-wrap .quicktags-toolbar {
-	padding-right: 3px;
+fieldset {
+	border: 1px solid #c0c0c0;
+	margin: 0 2px;
+	padding: 0.35em 0.625em 0.75em;
 }
 
-.press-this .howto {
-	margin-top: 2px;
-	margin-bottom: 3px;
-	font-size: 12px;
-	font-style: italic;
-	display: block;
+legend {
+	border: 0;
+	padding: 0;
 }
 
-.press-this #wp-content-editor-container {
-	clear: none;
+textarea {
+	overflow: auto;
 }
 
-.press-this #poststuff .inside {
-	margin-top: 18px;
+optgroup {
+	font-weight: bold;
 }
 
-.press-this .category-tabs {
-	margin-bottom: 3px;
+table {
+	border-collapse: collapse;
+	border-spacing: 0;
 }
 
-/* Editor/Main Column */
-.press-this #poststuff {
-	margin: 0 8px;
+td,
+th {
 	padding: 0;
 }
 
-.press-this #photo-add-url-div input[type="text"] {
-	width: 220px;
+.clearfix:before,
+.clearfix:after {
+	content: "";
+	display: table;
 }
+.clearfix:after {
+	clear: both;
+}
 
-#poststuff #editor-toolbar {
-	height: 30px;
+.hide-if-js {
+	display: none;
 }
 
-.posting {
-	margin-right: 212px;
-	position: relative;
+.screen-reader-text,
+.taghint {
+	position: absolute;
+	margin: -1px;
+	padding: 0;
+	height: 1px;
+	width: 1px;
+	overflow: hidden;
+	clip: rect(0 0 0 0);
+	border: 0;
 }
 
-.press-this .inner-sidebar {
-	width: 200px;
+
+/**
+* Typography
+*
+* Base element typographic styles.
+*/
+body,
+button,
+input,
+select,
+textarea {
+	color: #404040;
+	font-family: "Open Sans", Helvetica, Arial, sans-serif;
+	font-size: 20px;
+	font-weight: 400;
+	line-height: 1.6;
 }
 
-.press-this .inner-sidebar .sleeve {
-	padding-top: 5px;
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+	clear: both;
 }
 
-.press-this #submitdiv p {
+p {
+	margin-bottom: 1.5em;
+}
+
+b,
+strong {
+	font-weight: 700;
+}
+
+
+/**
+* Buttons
+*
+* Pushing buttons is what I do.
+*/
+.button-primary,
+.button-subtle,
+.scan-submit {
+	display: inline-block;
 	margin: 0;
-	padding: 6px;
+	padding: 0 10px 1px;
+	border-width: 1px;
+	border-style: solid;
+	-webkit-border-radius: 3px;
+	border-radius: 3px;
+	font-size: 13px;
+	line-height: 2;
+	text-decoration: none;
+	white-space: nowrap;
+	cursor: pointer;
+	-webkit-appearance: none;
 }
 
-.press-this #submitdiv #publishing-actions {
-	border-bottom: 1px solid #dfdfdf;
+.button-primary {
+	background: #2ea2cc;
+	border-color: #2581a2;
+	color: #fff;
 }
 
-.press-this #publish {
-	float: right;
+.button-primary:hover,
+.button-primary:focus {
+	background: #2991b7;
+	border-color: #20708e;
+	color: #fff;
+	outline: 0;
 }
 
-.press-this #poststuff h2,
-.press-this #poststuff h3 {
-	font-size: 14px;
-	line-height: 1;
+.button-primary:active {
+	background: #2581a2;
+	border-color: #20708e;
+	color: #fff;
 }
 
-.press-this #tagsdiv-post_tag h3,
-.press-this #categorydiv h3 {
-	cursor: pointer;
+.button-primary[disabled],
+.button-primary:disabled {
+	color: #c7ced1 !important;
+	background: #2688ab !important;
+	border-color: #20708e !important;
 }
 
-.press-this #submitdiv h3 {
-	cursor: default;
+.button-primary:visited {
+	color: #fff;
 }
 
-h3.tb {
-	font-weight: 600;
-	font-size: 12px;
-	margin-left: 5px;
+.button-subtle {
+	background: none;
+	border: 0;
+	color: #0074a2;
 }
 
-.press-this .postbox,
-.press-this .stuffbox {
-	margin-bottom: 10px;
-	min-width: 0;
+.button-subtle:visited {
+	color: #0074a2;
 }
 
-.press-this #submitdiv:hover .handlediv {
+.button-subtle:focus,
+.button-subtle:hover,
+.button-subtle:active {
+	color: #2ea2cc;
+}
+
+.button-subtle:focus,
+.button-subtle:active {
+	outline: 0;
+	text-decoration: underline;
+}
+
+.button-reset {
+	margin: 0;
+	padding: 0;
+	border: 0;
 	background: none;
+	cursor: pointer;
+	-webkit-appearance: none;
 }
 
-.tbtitle {
-	font-size: 1.7em;
-	outline: none;
-	padding: 3px 4px;
-	border: 1px solid #dfdfdf;
+.button-reset:focus {
+	outline: 0;
 }
 
-.press-this .actions {
-	float: right;
-	margin: -19px 0 0;
+
+/**
+* Forms
+*
+* So many input types.
+*/
+button,
+input,
+select,
+textarea {
+	font-size: 100%;
+	margin: 0;
+	vertical-align: baseline;
+	*vertical-align: middle;
 }
 
-.press-this #extra-fields .actions {
-	margin: -32px -7px 0 0;
+[type="checkbox"],
+[type="radio"] {
+	padding: 0;
 }
 
-.press-this .actions li {
-	float: left;
-	list-style: none;
-	margin-right: 10px;
+[type="search"] {
+	-webkit-appearance: textfield;
+	-webkit-box-sizing: content-box;
+	-moz-box-sizing: content-box;
+	box-sizing: content-box;
 }
 
-#extra-fields .button {
-	margin-right: 5px;
+[type="search"]::-webkit-search-decoration {
+	-webkit-appearance: none;
 }
 
-/* Photo Styles */
-#photo_saving {
-	margin: 0 8px 8px;
-	vertical-align: middle;
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+	border: 0;
+	padding: 0;
 }
 
-#img_container_container {
+[type="text"],
+[type="email"],
+[type="url"],
+[type="password"],
+[type="search"],
+textarea {
+	padding: 0.4em 0.75em;
+	color: #333;
+	border: 1px solid #ccc;
+}
+
+[type="text"]:focus,
+[type="email"]:focus,
+[type="url"]:focus,
+[type="password"]:focus,
+[type="search"]:focus,
+textarea:focus {
+	color: #333;
+	outline: 0;
+}
+
+textarea {
 	overflow: auto;
+	padding-left: 3px;
+	vertical-align: top;
 }
 
-#extra-fields {
-	margin-top: 10px;
+
+/**
+* Links
+*/
+a {
+	color: #0074a2;
+}
+
+a:visited {
+	color: #0074a2;
+}
+
+a:hover,
+a:focus,
+a:active {
+	color: #2ea2cc;
+}
+
+
+/**
+* Lists
+*/
+ul,
+ol {
+	margin: 0 0 1.5em 3em;
+}
+
+ul {
+	list-style: disc;
+}
+
+ol {
+	list-style: decimal;
+}
+
+li > ul,
+li > ol {
+	margin-bottom: 0;
+	margin-left: 1.5em;
+}
+
+dt {
+	font-weight: 700;
+}
+
+dd {
+	margin: 0 1.5em 1.5em;
+}
+
+
+/**
+* Post formats
+*
+* Complete styles for post formats UI
+*/
+/* TODO if we remove the <br> during merge, this can go. */
+#post-formats-select br {
+	display: none;
+}
+
+/* TODO Needed after merge? */
+.post-format {
+	width: 0;
+	height: 0;
+	position: absolute;
+	top: -9999px;
+}
+
+.lt-ie9 .post-format {
+	margin: 17px 12px 0 13px;
+	width: auto;
+	height: auto;
+	position: static;
+	top: auto;
+	float: left;
+	width: 16px;
+	height: 16px;
+}
+
+.post-format-icon {
 	position: relative;
+	display: block;
+	padding: 13px 2px 14px 13px;
+	cursor: pointer;
 }
 
-#extra-fields h2 {
-	margin: 12px;
+.post-format-icon:before,
+.post-format-icon:after {
+	content: "";
+	display: inline-block;
+	width: 20px;
+	height: 20px;
+	margin-right: 10px;
+	font-size: 20px;
+	line-height: 1;
+	font-family: dashicons;
+	text-decoration: inherit;
+	color: #9ea7af;
+	font-weight: 400;
+	font-style: normal;
+	vertical-align: top;
+	text-align: center;
+	-webkit-transition: color .1s ease-in 0;
+	transition: color .1s ease-in 0;
+	-webkit-font-smoothing: antialiased;
+	-moz-osx-font-smoothing: grayscale;
 }
 
-#waiting {
-	margin-top: 10px;
-	overflow: hidden;
+.post-format-icon:before {
+	content: "\f109";
 }
 
-#waiting span {
+.post-format-icon:after {
+	display: none;
+	content: "\f147";
 	float: right;
-	margin: 0 0 0 5px;
 }
 
-#waiting .spinner {
+.post-format:checked + .post-format-icon {
+	-webkit-box-shadow: inset 6px 0 0 #2ea2cc;
+	box-shadow: inset 6px 0 0 #2ea2cc;
+	background: rgba(46, 162, 204, 0.1);
+}
+
+.post-format:checked + .post-format-icon:before,
+.post-format:checked + .post-format-icon:after {
+	color: #333;
+}
+
+.post-format:focus + .post-format-icon {
+	background: #2ea2cc;
+	color: #fff;
+}
+
+.post-format:focus + .post-format-icon:before,
+.post-format:focus + .post-format-icon:after {
+	color: #fff;
+}
+
+.post-format:checked + .post-format-icon:after {
 	display: block;
 }
 
-#extra-fields .postbox {
-	margin-bottom: 5px;
+.lt-ie9 .post-format-icon {
+	margin-left: 16px;
 }
 
-#extra-fields .titlewrap {
+.post-format-aside:before {
+	content: "\f123";
+}
+
+.post-format-image:before {
+	content: "\f128";
+}
+
+.post-format-video:before {
+	content: "\f126";
+}
+
+.post-format-audio:before {
+	content: "\f127";
+}
+
+.post-format-quote:before {
+	content: "\f122";
+}
+
+.post-format-link:before {
+	content: "\f103";
+}
+
+.post-format-gallery:before {
+	content: "\f161";
+}
+
+
+/**
+* Tags
+*
+* Complete styles for tags UI
+*/
+.tagsdiv p {
+	margin: 0;
+}
+
+.tagsdiv .ajaxtag {
+	position: relative;
+}
+
+.tagsdiv .newtag {
+	display: block;
+	position: relative;
+	padding: 11px 58px 11px 16px;
+	width: 100%;
+	border: 0;
+	border-bottom: 1px solid #e5e5e5;
+	font-size: 16px;
+}
+
+.tagsdiv .tagadd {
+	position: absolute;
+	top: 0;
+	right: 0;
+	bottom: 1px;
+	border: 0;
+	-webkit-border-radius: 0;
+	border-radius: 0;
+	padding: 0 16px;
+	background: #f7f7f7;
+	border-left: 1px solid #f1f1f1;
+}
+
+.tagsdiv .tagadd:hover,
+.tagsdiv .tagadd:active,
+.tagsdiv .tagadd:focus {
+	outline: 0;
+	background: #2991b7;
+	border-color: #20708e;
+	color: #fff;
+}
+
+.tagsdiv .howto {
+	color: #727272;
+	font-style: italic;
+	margin: 10px 0 6px 16px;
+}
+
+
+/* Tag hint TODO needed? */
+/* Tag suggestions */
+.ac_results {
 	padding: 0;
-	overflow: auto;
-	height: 120px;
+	margin: -1px 0 0 -1px;
+	list-style: none;
+	position: absolute;
+	z-index: 10000;
+	display: none;
+	border: 1px solid #d8d8d8;
+	background-color: #fff;
+	font-size: 14px;
 }
 
-#img_container a {
+.ac_results li {
+	padding: 6px 16px;
+	white-space: nowrap;
+	color: #101010;
+	text-align: left;
+}
+
+.ac_results .ac_over {
+	background-color: #e5e5e5;
+	background-color: #2ea2cc;
+	color: #fff;
+	cursor: pointer;
+}
+
+.ac_match {
+	text-decoration: underline;
+}
+
+/* Tags */
+.tagchecklist {
+	padding: 16px 28px 5px;
+}
+
+.tagchecklist:before,
+.tagchecklist:after {
+	content: "";
+	display: table;
+}
+
+.tagchecklist:after {
+	clear: both;
+}
+
+.tagchecklist span {
 	display: block;
+	margin-right: 25px;
 	float: left;
+	font-size: 13px;
+	line-height: 1.8;
+	white-space: nowrap;
+	cursor: default;
+}
+
+@media (max-width: 600px) {
+	.tagchecklist span {
+		margin-bottom: 15px;
+		font-size: 16px;
+		line-height: 1.3;
+	}
+}
+
+.tagchecklist .ntdelbutton {
+	margin: 1px 0 0 -17px;
+	cursor: pointer;
+	width: 20px;
+	height: 20px;
+	display: block;
+	float: left;
+	text-indent: 0;
 	overflow: hidden;
+	position: absolute;
+	outline: 0;
 }
 
-#img_container img,
-#img_container a {
-	width: 68px;
-	height: 68px;
+.tagchecklist .ntdelbutton:before {
+	content: '\f153';
+	display: block;
+	margin: 2px 0;
+	height: 20px;
+	width: 20px;
+	background: 0 0;
+	color: #9ea7af;
+	font: 400 16px/1 dashicons;
+	text-align: center;
+	speak: none;
+	-webkit-font-smoothing: antialiased;
 }
 
-#img_container img {
+.tagchecklist .ntdelbutton:focus:before {
+	color: #2ea2cc;
+}
+
+
+/* THE TAG CLOUD. */
+.tagsdiv + p {
+	margin: 0;
+}
+
+.tagcloud-link {
+	display: block;
+	padding: 0 16px;
+	text-decoration: none;
+	outline: 0;
+}
+
+.tagcloud-link:focus {
+	text-decoration: underline;
+}
+
+.popular-tags {
 	border: none;
-	background-color: #f4f4f4;
+	line-height: 2em;
+	padding: 8px 12px 12px;
+	text-align: justify;
+}
+
+.popular-tags a {
+	padding: 0 3px;
+}
+
+.the-tagcloud {
+	margin: 0;
+	padding: 16px;
+}
+
+.the-tagcloud a {
+	text-decoration: none;
+	outline: 0;
+}
+
+.the-tagcloud a:focus {
+	text-decoration: underline;
+}
+
+.tagcloud h3 {
+	margin: 2px 0 12px;
+}
+
+
+/**
+* Categories
+*
+* Complete styles for post categories UI
+*/
+input[type="search"].categories-search,
+.add-category-name {
+	display: block;
+	width: 100%;
+	padding: 0.85714em 1.07143em;
+	border: 0;
+	-webkit-border-radius: 0;
+	border-radius: 0;
+	border-bottom: 1px solid #e5e5e5;
+	font-size: 14px;
+	-webkit-appearance: none;
+	appearance: none;
+}
+
+@media (max-width: 600px) {
+	input[type="search"].categories-search,
+	.add-category-name {
+		/* Needs to be 16px to prevent zooming on iOS. Guh. */
+		font-size: 16px;
+	}
+}
+
+.add-cat-toggle {
+	float: right;
+	margin-top: -33px;
+}
+
+.add-cat-toggle:focus {
+	text-decoration: none;
+	color: #2ea2cc;
+}
+
+.add-cat-toggle.is-toggled {
+	margin-top: -36px;
+}
+
+.add-cat-toggle.is-toggled .dashicons:before {
+	content: "\f179";
+}
+
+.add-category {
+	position: relative;
+	border-bottom: 1px solid #e5e5e5;
+}
+
+.add-category.is-hidden {
+	display: none;
+}
+
+.add-category .add-cat-submit {
+	position: absolute;
+	top: 0;
+	right: 0;
+	border: 0;
+	-webkit-border-radius: 0;
+	border-radius: 0;
+	padding: 12px 16px;
+	background: #f7f7f7;
+	border-left: 1px solid #f1f1f1;
+}
+
+.add-category .add-cat-submit:hover,
+.add-category .add-cat-submit:active,
+.add-category .add-cat-submit:focus {
+	outline: 0;
+	background: #2991b7;
+	border-color: #20708e;
+	color: #fff;
+}
+
+/* Parent category select */
+.postform-wrapper {
+	padding: 12px;
+}
+
+.postform {
+	display: block;
+	margin: 0;
+	width: 100%;
+	height: 34px;
+	border: 0;
+	-webkit-border-radius: 0;
+	border-radius: 0;
+	border: 1px solid #e5e5e5;
+	background: #fff;
+	-webkit-background-size: 20px 20px;
+	background-size: 20px 20px;
+	overflow: hidden;
+	line-height: 21px;
+	text-overflow: ellipsis;
+	text-decoration: none;
+	vertical-align: top;
+	white-space: nowrap;
 	cursor: pointer;
+	outline: 0;
 }
 
-#img_container a,
-#img_container a:link,
-#img_container a:visited {
-	border: 1px solid #ccc;
+.postform:focus {
+	border-color: #0074a2;
+	-webkit-box-shadow: 0 0 0 3px #2ea2cc;
+	box-shadow: 0 0 0 3px #2ea2cc;
+	outline: 0;
+	-moz-outline: none;
+	-moz-user-focus: ignore;
+}
+
+.postform::-ms-expand {
+	display: none;
+}
+
+.postform::-ms-value {
+	background: none;
+	color: #727272;
+}
+
+.postform:-moz-focusring {
+	color: transparent;
+	text-shadow: 0 0 0 #727272;
+}
+
+/* Category list */
+.categories-select {
+	margin: 0;
+	padding: 0;
+	list-style: none;
+}
+
+.categories-select ul {
+	margin: 0;
+	padding: 0;
+	list-style: none;
+}
+
+.categories-select input {
+	clear: none;
+	position: absolute;
+	top: 0;
+	left: 0;
 	display: block;
+	line-height: 0;
+	width: 100%;
+	height: 100%;
+	outline: 0;
+	padding: 0;
+	border: 0;
+	-webkit-border-radius: 0;
+	border-radius: 0;
+	text-align: center;
+	vertical-align: middle;
+	-webkit-appearance: none;
+	appearance: none;
+	cursor: pointer;
+}
+
+.categories-select input:checked {
+	-webkit-box-shadow: inset 6px 0 0 #2ea2cc;
+	box-shadow: inset 6px 0 0 #2ea2cc;
+	background: rgba(46, 162, 204, 0.1);
+}
+
+.categories-select input:checked:after {
+	display: inline-block;
+	content: "\f147";
+	position: absolute;
+	top: 13px;
+	right: 0;
+	width: 20px;
+	height: 20px;
+	margin-right: 10px;
+	font-size: 20px;
+	line-height: 1;
+	font-family: dashicons;
+	text-decoration: inherit;
+	color: #222;
+	font-weight: 400;
+	font-style: normal;
+	vertical-align: top;
+	text-align: center;
+	-webkit-transition: color .1s ease-in 0;
+	transition: color .1s ease-in 0;
+	-webkit-font-smoothing: antialiased;
+	-moz-osx-font-smoothing: grayscale;
+}
+
+.categories-select input:focus {
+	-webkit-box-shadow: inset 6px 0 0 #2ea2cc;
+	box-shadow: inset 6px 0 0 #2ea2cc;
+	background: rgba(46, 162, 204, 0.05);
+}
+
+.categories-select label {
 	position: relative;
+	display: block;
+	padding: 13px 16px 14px 16px;
+	cursor: pointer;
+	background: #fff;
 }
 
-#img_container a:hover,
-#img_container a:active {
-	border-color: #000;
-	z-index: 1000;
-	border-width: 1px;
+.categories-select ul label {
+	padding-left: 24px;
 }
 
-/* Video */
-#embed-code {
+.categories-select ul ul label {
+	padding-left: 32px;
+}
+
+.categories-select ul ul ul label {
+	padding-left: 40px;
+}
+
+.categories-select ul ul ul ul label {
+	padding-left: 48px;
+}
+
+.categories-select ul ul ul ul ul label {
+	padding-left: 56px;
+}
+
+.categories-select ul ul ul ul ul ul label {
+	padding-left: 64px;
+}
+
+.categories-select .is-hidden {
+	display: none;
+}
+
+.categories-select .is-hidden.searched-parent {
+	display: block;
+}
+
+.lt-ie9 .categories-select input {
+	top: 50%;
+	right: 10px;
+	left: auto;
+	margin-top: -8px;
+	width: 16px;
+	height: 16px;
+}
+
+/* TODO Reformats checkbox on Firefox until we remove checkbox in merge */
+@-moz-document url-prefix() {
+	.categories-select input {
+		top: 50%;
+		right: 10px;
+		left: auto;
+		margin-top: -8px;
+		width: 16px;
+		height: 16px;
+	}
+}
+
+/* Category search */
+.categories-search-wrapper {
+	position: relative;
+}
+
+.categories-search-wrapper.is-hidden {
+	display: none;
+}
+
+.categories-search-wrapper label {
+	position: absolute;
+	top: 50%;
+	right: 10px;
+	margin-top: -10px;
+	color: #9ea7af;
+}
+
+
+/**
+* Main
+*/
+html,
+body {
+	overflow-x: hidden;
+}
+
+@media (min-width: 901px) {
+	html,
+	body {
+		height: 100%;
+	}
+}
+
+html {
+	background: #fff;
+	-webkit-box-shadow: -10px 0 0 rgba(0, 0, 0, 0.3);
+	box-shadow: -10px 0 0 rgba(0, 0, 0, 0.3);
+}
+
+@media (max-width: 900px) {
+	body {
+		font-size: 16px;
+	}
+}
+
+@media (max-width: 320px) {
+	body {
+		font-size: 14px;
+	}
+}
+
+.lt-ie9 {
+	overflow: visible;
+}
+
+.adminbar {
+	position: relative;
 	width: 100%;
-	height: 98px;
+	padding: 0 0.8em;
+	min-height: 3.2em;
+	background: #222;
+	color: #fff;
+	z-index: 9999;
 }
 
-/* Categories */
-.press-this .categorydiv div.tabs-panel {
-	height: 100px;
+.adminbar:before,
+.adminbar:after {
+	content: "";
+	display: table;
 }
 
-/* Tags */
-.press-this .tagsdiv .newtag {
-	width: 120px;
+.adminbar:after {
+	clear: both;
 }
 
-.press-this #content {
-	margin: 5px 0;
-	padding: 0 5px;
-	border: 0 none;
-	height: 340px;
-	font-family: Consolas, Monaco, monospace;
-	font-size: 13px;
-	line-height: 19px;
-	background: transparent;
+.adminbar .dashicons {
+	color: #999;
 }
 
-/* Submit */
-.press-this #publishing-actions .spinner {
-	display: inline;
+.adminbar button {
+	position: absolute;
+	top: 50%;
+	right: 6px;
+	margin-top: -13px;
+}
+
+@media (max-width: 320px) {
+	.adminbar {
+		min-height: 45px;
+	}
+}
+
+.current-site {
+	margin-top: 0.5625em;
+	font-size: 16px;
+	line-height: 44px;
+	font-weight: 400;
+	overflow: hidden;
+	white-space: nowrap;
+	text-overflow: ellipsis;
+}
+
+@media (max-width: 600px) {
+	.current-site {
+		margin: 3px 0 0;
+	}
+}
+
+@media (max-width: 320px) {
+	.current-site {
+		margin: 0;
+		font-size: 14px;
+	}
+}
+
+.current-site span:nth-child(2) {
+	color: #ededed;
+}
+
+@media (max-width: 320px) {
+	.current-site span:nth-child(2) {
+		font-weight: 600;
+	}
+}
+
+.current-site .dashicons-wordpress {
+	position: relative;
+	top: -1px;
+	margin-right: 10px;
 	vertical-align: middle;
 }
 
-/* =Media Queries
--------------------------------------------------------------- */
+.options-open,
+.options-close {
+	display: none;
+}
 
-/* Reset responsive styles in Press This */
-@media screen and ( max-width: 782px ) {
-	.press-this ul.category-tabs li.tabs {
-		padding: 3px 5px 5px; /* Reset tabs in Press This to standard size */
+@media (max-width: 900px) {
+	.options-open,
+	.options-close {
+		display: block;
 	}
+}
 
-	.press-this a.wp-switch-editor {
-		font: 13px/19px "Open Sans", sans-serif;
-		margin: 5px 0 0 5px;
-		padding: 3px 8px 4px;
+.options-open.is-hidden,
+.options-close.is-hidden {
+	display: none;
+}
+
+.options-open:focus .dashicons {
+	color: #fff;
+	text-decoration: none;
+}
+
+.options-open .dashicons {
+	margin-top: 3px;
+}
+
+.options-close {
+	color: #2ea2cc;
+}
+
+.alert {
+	position: relative;
+	margin: 0;
+	padding: 16px 50px;
+	border-bottom: 1px solid #e5e5e5;
+	font-size: 14px;
+}
+
+.alert:before {
+	content: '';
+	position: absolute;
+	top: 50%;
+	left: 30px;
+	width: 8px;
+	height: 8px;
+	margin-top: -4px;
+	-webkit-border-radius: 50%;
+	border-radius: 50%;
+	background: #2ea2cc;
+}
+
+@media (max-width: 600px) {
+	.alert {
+		padding: 16px 35px;
 	}
+	.alert:before {
+		left: 15px;
+	}
+}
 
-	.press-this #wp-content-media-buttons a {
-		padding: 0;
-		line-height: normal;
-		height: auto;
+.alert.is-hidden {
+	display: none;
+}
+.alert.is-error:before {
+	background: red;
+}
+
+.scan {
+	position: relative;
+	border-bottom: 1px solid #e5e5e5;
+}
+
+@media (max-width: 900px) {
+	.scan form {
+		-webkit-transition: opacity .3s ease-in-out;
+		transition: opacity .3s ease-in-out;
 	}
+	.scan.is-hidden form {
+		opacity: .2;
+		pointer-events: none;
+	}
+}
 
-	.press-this #wp-content-editor-tools {
-		padding: 0;
-		top: 3px;
+.scan-url {
+	display: block;
+	border: 0;
+	padding: 0.85714em 1.07143em;
+	font-size: 14px;
+	width: 100%;
+}
+
+@media (max-width: 600px) {
+	.scan-url {
+		font-size: 16px;
 	}
+}
 
-	.press-this .category-tabs {
-		margin-top: 0;
+.scan-submit {
+	position: absolute;
+	top: 0;
+	right: 0;
+	bottom: 0;
+	padding: 0.85714em 1.07143em;
+	background: #f7f7f7;
+	border-color: #dedede;
+	border-bottom: 0;
+	border-left: 1px solid #f1f1f1;
+	-webkit-border-radius: 0;
+	border-radius: 0;
+	color: #555;
+	font-size: 14px;
+	line-height: 1.6;
+}
+
+.scan-submit:hover,
+.scan-submit:focus {
+	background: #2991b7;
+	border-color: #20708e;
+	color: #fff;
+	outline: 0;
+}
+
+.scan-submit:active {
+	background: #2581a2;
+	border-color: #20708e;
+	color: #fff;
+}
+
+.scan-submit:visited {
+	color: #555;
+}
+
+.wrapper {
+	position: relative;
+	margin-bottom: 60px;
+	margin-right: 320px;
+}
+
+.wrapper:before,
+.wrapper:after {
+	content: "";
+	display: table;
+}
+
+.wrapper:after {
+	clear: both;
+}
+
+@media (max-width: 900px) {
+	.wrapper {
+		margin: 0;
+		width: 100%;
 	}
+}
 
-	.press-this .tagsdiv .newtag {
-		width: 120px;
-		padding: 3px 5px;
-		margin-bottom: 0;
+.editor-wrapper {
+	overflow: auto;
+	float: left;
+	width: 100%;
+}
+
+.editor-wrapper:before,
+.editor-wrapper:after {
+	content: "";
+	display: table;
+}
+
+.editor-wrapper:after {
+	clear: both;
+}
+
+.editor {
+	padding: 0 1.5em 4.75em;
+	max-width: 700px;
+	margin: 0 auto;
+}
+
+@media (min-width: 901px) {
+	.editor {
+		max-width: 760px;
 	}
+}
 
-	.press-this .tagchecklist {
+@media (max-width: 320px) {
+	.editor {
 		padding: 0;
-		margin-bottom: 0;
 	}
+}
 
-	.press-this .wp_themeSkin a.mceButton {
-		width: 20px;
-		height: 20px;
+.post-title,
+.post-title-placeholder {
+	margin: 0;
+	padding: .83em 0;
+	width: 100%;
+	border-bottom: 1px solid #e5e5e5;
+	font-size: 32px;
+	line-height: 1.4;
+	font-weight: 700;
+}
+
+.post-title:active,
+.post-title:focus,
+.post-title-placeholder:active,
+.post-title-placeholder:focus {
+	outline: 0;
+	-webkit-box-shadow: inset 0px -3px 0 #2ea2cc;
+	box-shadow: inset 0px -3px 0 #2ea2cc;
+	border-color: #2ea2cc;
+}
+
+@media (max-width: 900px) {
+	.post-title,
+	.post-title-placeholder {
+		font-size: 24px;
 	}
+}
 
-	.press-this .wp_themeSkin .mceButton .mceIcon {
-		margin: 0;
+@media (max-height: 400px) {
+	.post-title,
+	.post-title-placeholder {
+		padding: 15px 0;
+		font-size: 16px;
 	}
+}
 
-	.press-this #poststuff h3,
-	.press-this .metabox-holder h3 {
-		padding: 7px 12px;
+@media (max-width: 320px) {
+	.post-title,
+	.post-title-placeholder {
+		font-size: 16px;
+		font-weight: 600;
+		padding: 1.14286em 1.42857em;
 	}
+}
 
-	.press-this input[type=checkbox],
-	.press-this input[type=radio] {
-		height: 16px;
-		width: 16px;
+.post-title {
+	/* IE8 fallback */
+	background: url(data:image/gif;base64,R0lGODlhAQABAJEAAAAAAP///////wAAACH5BAEHAAIALAAAAAABAAEAAAICVAEAOw==);
+	background: none, none;
+}
+
+.post-title:before {
+	/* Keeps empty container from collapsing */
+	content: '\a0';
+	display: inline-block;
+	width: 0;
+	speak: none;
+}
+
+.post-title-placeholder {
+	position: absolute;
+	border: 0;
+	color: #9ea7af;
+	z-index: -1;
+}
+
+.post-title-placeholder.is-hidden {
+	display: none;
+}
+
+/* Suggested images */
+.featured-container {
+	position: relative;
+	padding: 2px 0;
+	border-bottom: 1px solid #e5e5e5;
+}
+
+.all-media {
+	display: none;
+	overflow: auto;
+	max-height: 150px;
+	max-height: 40vw;
+}
+
+.all-media:before, .all-media:after {
+	content: "";
+	display: table;
+}
+
+.all-media:after {
+	clear: both;
+}
+
+@media (min-width: 321px) {
+	.all-media {
+		max-height: 250px;
+		max-height: 40vw;
 	}
+}
 
-	.press-this input[type=checkbox]:checked:before {
-		width: 16px;
-		font: normal 21px/1 'dashicons';
-		margin: -3px 0 0 -4px;
+@media (min-width: 601px) {
+	.all-media {
+		max-height: 200px;
+		max-height: 18.75vw;
 	}
+}
 
-	.press-this input[type=radio]:checked:before {
-		font: normal 21px/1 'dashicons';
-		width: 6px;
-		height: 6px;
-		margin: 4px;
+.wppt-all-media-list {
+	list-style: none;
+	margin: 0;
+	padding: 0;
+}
+
+.suggested-media-thumbnail:focus,
+.suggested-media-embed:focus {
+	outline: 0;
+	-webkit-box-shadow: inset 0 0 0 3px #2ea2cc;
+	box-shadow: inset 0 0 0 3px #2ea2cc;
+}
+
+.suggested-media-thumbnail {
+	position: relative;
+	display: block;
+	float: left;
+	width: 16.66%;
+	padding: 16.66% 0 0 16.66%;
+	background-position: center;
+	background-repeat: no-repeat;
+	-webkit-background-size: cover;
+	background-size: cover;
+	background-color: #d8d8d8;
+	color: #fff;
+	color: rgba(255, 255, 255, 0.6);
+	cursor: pointer;
+}
+
+.suggested-media-thumbnail:hover,
+.suggested-media-thumbnail:active,
+.suggested-media-thumbnail:focus {
+	color: #fff;
+}
+
+.suggested-media-thumbnail:before,
+.suggested-media-thumbnail:after {
+	display: inline-block;
+	position: absolute;
+	font-size: 20px;
+	line-height: 1;
+	font-family: dashicons;
+	text-decoration: inherit;
+	font-weight: 400;
+	font-style: normal;
+	-webkit-transition: color .1s ease-in 0;
+	transition: color .1s ease-in 0;
+	-webkit-font-smoothing: antialiased;
+	-moz-osx-font-smoothing: grayscale;
+}
+
+.suggested-media-thumbnail:before {
+	left: 50%;
+	top: 50%;
+	margin: -20px 0 0 -20px;
+	font-size: 40px;
+}
+
+.suggested-media-thumbnail:after {
+	content: "\f132";
+	right: 3%;
+	bottom: 2%;
+}
+
+@media (min-width: 601px) {
+	.suggested-media-thumbnail {
+		width: 12.5%;
+		padding: 12.5% 0 0 12.5%;
 	}
+}
 
-	.press-this ul.categorychecklist ul,
-	.press-this ul.categorychecklist li {
-		margin-top: 0;
-		margin-bottom: 0;
+.suggested-media-embed:before {
+	content: "\f104";
+	color: #fff;
+	color: rgba(255, 255, 255, 0.9);
+}
+
+.suggested-media-embed.is-audio:hover:before,
+.suggested-media-embed.is-audio:active:before,
+.suggested-media-embed.is-audio:focus:before,
+.suggested-media-embed.is-tweet:hover:before,
+.suggested-media-embed.is-tweet:active:before,
+.suggested-media-embed.is-tweet:focus:before {
+	color: #fff;
+}
+
+.suggested-media-embed.is-video {
+	background-color: #222;
+}
+
+.suggested-media-embed.is-video:hover:before,
+.suggested-media-embed.is-video:active:before,
+.suggested-media-embed.is-video:focus:before {
+	color: rgba(255, 255, 255, 0.2);
+}
+
+.suggested-media-embed.is-video:before {
+	content: "\f236";
+}
+
+.suggested-media-embed.is-audio {
+	background-color: #ff7d44;
+}
+
+.suggested-media-embed.is-audio:before {
+	content: "\f127";
+}
+
+.suggested-media-embed.is-tweet {
+	background-color: #55acee;
+}
+
+.suggested-media-embed.is-tweet:before {
+	content: "\f301";
+}
+
+.all-media-visible .all-media {
+	display: block;
+}
+
+.no-media {
+	margin: 0;
+	padding: 0;
+	border: 0;
+}
+
+/* Actions bar */
+.press-this-actions {
+	position: fixed;
+	bottom: 0;
+	left: 0;
+	width: 100%;
+	background: #f1f1f1;
+	background: rgba(241, 241, 241, 0.9);
+	border-top: 1px solid #e5e5e5;
+}
+
+@media (max-width: 900px) {
+	.press-this-actions {
+		-webkit-transform: translateY(0);
+		-ms-transform: translateY(0);
+		transform: translateY(0);
+		-webkit-transition: -webkit-transform .3s ease-in-out;
+		transition: transform .3s ease-in-out;
 	}
+	.press-this-actions.is-hidden {
+		-webkit-transform: translateY(100%);
+		-ms-transform: translateY(100%);
+		transform: translateY(100%);
+	}
+}
 
-	.press-this div.quicktags-toolbar input {
-		padding: 2px 4px;
+.add-media {
+	float: left;
+	margin: 14px 0 14px 30px;
+	font-size: 0;
+}
+
+@media (max-width: 320px) {
+	.add-media {
+		margin: 10px 0 10px 10px;
 	}
+}
 
-	.press-this textarea,
-	.press-this input {
-		font-size: 14px;
+.insert-media {
+	color: #9ea7af;
+	float: left;
+	margin: 0;
+	padding: 0;
+	border: 0;
+	border-right: 1px solid #e5e5e5;
+	-webkit-border-radius: 0;
+	border-radius: 0;
+	background: none;
+	-webkit-box-shadow: none;
+	box-shadow: none;
+	overflow: hidden;
+}
+
+.insert-media:hover,
+.insert-media:focus,
+.insert-media:active {
+	margin: 0;
+	background: none;
+	border-color: #e5e5e5;
+	color: #222;
+}
+
+.insert-media:focus,
+.insert-media:active {
+	outline: 0;
+	color: #2ea2cc;
+	text-decoration: none;
+}
+
+.insert-media .dashicons {
+	padding: 11px;
+	width: 63px;
+	height: 58px;
+	font-size: 40px;
+}
+
+@media (max-width: 320px) {
+	.insert-media .dashicons {
+		width: 55px;
+		height: 49px;
+		padding: 14px;
+		font-size: 20px;
 	}
+}
 
-	.press-this .tagchecklist span {
-		font-size: 13px;
-		line-height: 1.8em;
+.post-actions {
+	float: right;
+	margin: 14px 30px 14px 0;
+	font-size: 0;
+}
+
+@media (max-width: 320px) {
+	.post-actions {
+		margin: 10px 10px 10px 0;
 	}
 }
+
+/* TinyMCE styles */
+.editor .wp-media-buttons {
+	float: none;
+}
+
+.editor div.mce-toolbar-grp {
+	padding: 0.71429em 0;
+	background: none;
+	border: 0;
+}
+
+@media (max-height: 400px), (max-width: 320px) {
+	.editor div.mce-toolbar-grp {
+		padding: 0;
+	}
+}
+
+.mce-stack-layout:before,
+.mce-stack-layout:after {
+	content: "";
+	display: table;
+}
+
+.mce-stack-layout:after {
+	clear: both;
+}
+
+.mce-container.mce-toolbar {
+	float: left;
+}
+
+.mce-container.mce-toolbar:nth-child(2) {
+	float: right;
+}
+
+@media (max-width: 600px) {
+	#mceu_11,
+	#mceu_12 {
+		position: absolute;
+		margin: -1px;
+		padding: 0;
+		height: 1px;
+		width: 1px;
+		overflow: hidden;
+		clip: rect(0 0 0 0);
+		border: 0;
+	}
+
+	#mceu_11:focus,
+	#mceu_12:focus {
+		position: static;
+		margin: 1px;
+		padding: inherit;
+		height: auto;
+		width: auto;
+		overflow: visible;
+		clip: auto;
+		border: 1px solid #999;
+	}
+}
+
+#wp-link-wrap.search-panel-visible {
+	font-size: 13px;
+}
+
+/* Options panel (sidebar) */
+.options-panel {
+	position: relative;
+	float: right;
+	margin-right: -320px;
+	width: 320px;
+	border-left: 1px solid #e5e5e5;
+	font-size: 14px;
+	/* Keeps background the full height of the screen */
+	-webkit-box-shadow: 5001px 5000px 0 5000px #fff, 5000px 5000px 0 5000px #e5e5e5;
+	box-shadow: 5001px 5000px 0 5000px #fff, 5000px 5000px 0 5000px #e5e5e5;
+}
+
+@media (max-width: 900px) {
+	.options-panel {
+		background: #fff;
+		-webkit-transform: translateX(-100%);
+		-ms-transform: translateX(-100%);
+		transform: translateX(-100%);
+		-webkit-transition: -webkit-transform .3s ease-in-out;
+		transition: transform .3s ease-in-out;
+	}
+
+	.options-panel.is-hidden {
+		visibility: hidden;
+	}
+
+	.options-panel.is-off-screen {
+		-webkit-transform: translateX(0);
+		-ms-transform: translateX(0);
+		transform: translateX(0);
+	}
+}
+
+@media (max-width: 320px) {
+	.options-panel {
+		margin-right: -100%;
+		width: 100%;
+		border: 0;
+		-webkit-box-shadow: 5001px 5000px 0 5000px #fff;
+		box-shadow: 5001px 5000px 0 5000px #fff;
+	}
+}
+
+.post-options {
+	background: #fff;
+	position: absolute;
+	right: 0;
+	width: 100%;
+	overflow-x: hidden;
+}
+
+.post-options .post-option-contents {
+	margin-left: 3px;
+	color: #333;
+}
+
+.post-options .dashicons-arrow-right-alt2 {
+	position: absolute;
+	top: 50%;
+	right: 8px;
+	margin-top: -10px;
+}
+
+.lt-ie9 .options-panel,
+.lt-ie9 .post-options {
+	border-left: 1px solid #e5e5e5;
+}
+
+.lt-ie9 .post-options.is-off-screen {
+	border: 0;
+}
+
+.post-option {
+	position: relative;
+}
+
+.post-options .post-option {
+	display: block;
+	width: 100%;
+	padding: 13px 37px 13px 14px;
+	border-bottom: 1px solid #e5e5e5;
+	text-decoration: none;
+	text-align: left;
+	color: #9ea7af;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+	-webkit-transition: -webkit-transform .3s ease-in-out;
+	transition: transform .3s ease-in-out;
+}
+
+.post-options .post-option:focus {
+	outline: 0;
+	-webkit-box-shadow: inset 5px 0 0 #2ea2cc;
+	box-shadow: inset 5px 0 0 #2ea2cc;
+}
+
+.is-off-screen > .post-option {
+	right: 100%;
+}
+
+.is-hidden > .post-option {
+	visibility: hidden;
+}
+
+@media (min-width: 1px) {
+	.is-off-screen > .post-option {
+		right: auto;
+		-webkit-transform: translateX(-100%);
+		-ms-transform: translateX(-100%);
+		transform: translateX(-100%);
+	}
+}
+
+.post-option-title {
+	display: inline-block;
+	margin: 0 0 0 8px;
+	font-size: 14px;
+	font-weight: normal;
+}
+
+.setting-modal {
+	position: relative;
+	top: 0;
+	left: 0;
+	width: 100%;
+	overflow: hidden;
+	-webkit-transition: -webkit-transform .3s ease-in-out;
+	transition: transform .3s ease-in-out;
+}
+
+.setting-modal.is-hidden {
+	visibility: hidden;
+	height: 0;
+}
+
+.setting-modal.is-off-screen {
+	left: 100%;
+}
+
+@media (min-width: 1px) {
+	.setting-modal.is-off-screen {
+		left: 0;
+		-webkit-transform: translateX(100%);
+		-ms-transform: translateX(100%);
+		transform: translateX(100%);
+	}
+}
+
+.modal-close {
+	display: block;
+	width: 100%;
+	padding: 13px 14px;
+	border-bottom: 1px solid #e5e5e5;
+	color: #2ea2cc;
+	text-decoration: none;
+	text-align: left;
+}
+
+.modal-close:focus {
+	outline: 0;
+	-webkit-box-shadow: inset 5px 0 0 #2ea2cc;
+	box-shadow: inset 5px 0 0 #2ea2cc;
+}
+
+.setting-title {
+	position: relative;
+	top: -1px;
+	margin-left: 11px;
+}
Index: src/wp-admin/css/wp-admin.css
===================================================================
--- src/wp-admin/css/wp-admin.css	(revision 31531)
+++ src/wp-admin/css/wp-admin.css	(working copy)
@@ -7,7 +7,6 @@
 @import url(revisions.css);
 @import url(media.css);
 @import url(themes.css);
-@import url(press-this.css);
 @import url(about.css);
 @import url(nav-menus.css);
 @import url(widgets.css);
Index: src/wp-admin/includes/ajax-actions.php
===================================================================
--- src/wp-admin/includes/ajax-actions.php	(revision 31531)
+++ src/wp-admin/includes/ajax-actions.php	(working copy)
@@ -2954,3 +2954,29 @@
 
 	wp_send_json_success( $status );
 }
+
+/**
+ * AJAX handler for saving a post from Ptrss This.
+ *
+ * @since 4.2.0
+ */
+function wp_ajax_press_this_save_post() {
+	if ( empty( $GLOBALS['wp_press_this'] ) ) {
+		include( ABSPATH . 'wp-admin/includes/class-wp-press-this.php' );
+	}
+
+	$GLOBALS['wp_press_this']->save_post();
+}
+
+/**
+ * AJAX handler for creating new category from Ptrss This.
+ *
+ * @since 4.2.0
+ */
+function wp_ajax_press_this_add_category() {
+	if ( empty( $GLOBALS['wp_press_this'] ) ) {
+		include( ABSPATH . 'wp-admin/includes/class-wp-press-this.php' );
+	}
+
+	$GLOBALS['wp_press_this']->add_category();
+}
Index: src/wp-admin/includes/class-wp-press-this.php
===================================================================
--- src/wp-admin/includes/class-wp-press-this.php	(revision 0)
+++ src/wp-admin/includes/class-wp-press-this.php	(working copy)
@@ -0,0 +1,891 @@
+<?php
+/**
+ * Press This class and display functionality
+ *
+ * @package WordPress
+ * @subpackage Press_This
+ * @since 4.2.0
+ */
+
+/**
+ * Press This class
+ *
+ * @since 4.2.0
+ */
+class WP_Press_This {
+
+	/**
+	 * Constructor.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 */
+	public function __construct() {}
+
+	/**
+	 * App and site settings data, including i18n strings for the client-side.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 *
+	 * @return array Site settings.
+	 */
+	public function site_settings() {
+		$supported_formats = get_theme_support( 'post-formats' );
+		$post_formats      = array();
+
+		if ( ! empty( $supported_formats[0] ) && is_array( $supported_formats[0] ) ) {
+			$post_formats[0] = __( 'Standard' );
+			foreach ( $supported_formats[0] as $post_format ) {
+				$post_formats[ $post_format ] = esc_html( get_post_format_string( $post_format ) );
+			}
+		}
+
+		return array(
+			'version'         => 5,
+			'post_formats'    => $post_formats,
+
+			/**
+			 * Filter whether Press This should redirect the user in the parent window instead of the popup, upon save.
+			 *
+			 * @since 4.2.0
+			 *
+			 * @param bool $redir_in_parent Whether to redirect in parent window or not. Default false.
+			 */
+			'redir_in_parent' => apply_filters( 'press_this_redirect_in_parent', __return_false() ),
+		);
+	}
+
+	/**
+	 * Get the sources images and save them locally, fr posterity, unless we can't.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 *
+	 * @param int    $post_id Post ID.
+	 * @param string $content Optional. Current expected markup for Press This. Default empty.
+	 * @return string New markup with old image URLs replaced with the local attachment ones if swapped.
+	 */
+	public function side_load_images( $post_id, $content = '' ) {
+		$new_content = $content;
+
+		preg_match_all( '/<img [^>]+>/', $content, $matches );
+
+		if ( ! empty( $matches ) && current_user_can( 'upload_files' ) ) {
+			foreach ( (array) $matches[0] as $key => $image ) {
+				preg_match( '/src=["\']{1}([^"\']+)["\']{1}/', stripslashes( $image ), $url_matches );
+
+				if ( empty( $url_matches[1] ) ) {
+					continue;
+				}
+
+				$image_url = $url_matches[1];
+
+				// Don't try to sideload a file without a file extension, leads to WP upload error.
+				if ( ! preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $image_url ) )
+					 continue;
+
+				// See if files exist in content - we don't want to upload non-used selected files.
+				if ( false !== strpos( $new_content, htmlspecialchars( $image_url ) ) ) {
+
+					// Sideload image, which ives us a new image tag, strip the empty alt that comes with it.
+					$upload = str_replace( ' alt=""', '', media_sideload_image( $image_url, $post_id ) );
+
+					// Preserve assigned class, id, width, height and alt attributes.
+					if ( preg_match_all( '/(class|width|height|id|alt)=\\\?(\"|\')[^"\']+\\\?(\2)/', $image, $attr_matches )
+					     && is_array( $attr_matches[0] )
+					) {
+						foreach ( $attr_matches[0] as $attr ) {
+							$upload = str_replace( '<img', '<img ' . $attr, $upload );
+						}
+					}
+
+					/*
+					 * Replace the POSTED content <img> with correct uploaded ones.
+					 * Regex contains fix for Magic Quotes.
+					 */
+					if ( ! is_wp_error( $upload ) ) {
+						$new_content = str_replace( $image, $upload, $new_content );
+					}
+				}
+			}
+		}
+
+		// Error handling for media_sideload, send original content back.
+		if ( is_wp_error( $new_content ) ) {
+			return $content;
+		}
+
+		return $new_content;
+	}
+
+	/**
+	 * AJAX handler for saving the post as draft or published.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 */
+	public function save_post() {
+		if ( empty( $_POST['pressthis-nonce'] ) || ! wp_verify_nonce( $_POST['pressthis-nonce'], 'press-this' ) ) {
+			wp_send_json_error( array( 'errorMessage' => __( 'Cheatin&#8217; uh?' ) ) );
+		}
+
+		if ( empty( $_POST['post_ID'] ) || ! $post_id = (int) $_POST['post_ID'] ) {
+			wp_send_json_error( array( 'errorMessage' => __( 'Missing post ID.' ) ) );
+		}
+	
+		if ( ! current_user_can( 'edit_post', $post_id ) ) {
+			wp_send_json_error( array( 'errorMessage' => __( 'Cheatin&#8217; uh?' ) ) );
+		}
+	
+		$post = array(
+			'ID'            => $post_id,
+			'post_title'    => ( ! empty( $_POST['title'] ) ) ? sanitize_text_field( trim( $_POST['title'] ) ) : '',
+			'post_content'  => ( ! empty( $_POST['pressthis'] ) ) ? trim( $_POST['pressthis'] ) : '',
+			'post_type'     => 'post',
+			'post_status'   => 'draft',
+			'post_format'   => ( ! empty( $_POST['post_format'] ) ) ? sanitize_text_field( $_POST['post_format'] ) : '',
+			'tax_input'     => ( ! empty( $_POST['tax_input'] ) ) ? $_POST['tax_input'] : array(),
+			'post_category' => ( ! empty( $_POST['post_category'] ) ) ? $_POST['post_category'] : array(),
+		);
+	
+		if ( ! empty( $_POST['post_status'] ) && 'publish' === $_POST['post_status'] ) {
+			if ( current_user_can( 'publish_posts' ) ) {
+				$post['post_status'] = 'publish';
+			} else {
+				$post['post_status'] = 'pending';
+			}
+		}
+
+		$new_content = $this->side_load_images( $post_id, $post['post_content'] );
+
+		if ( ! is_wp_error( $new_content ) ) {
+			$post['post_content'] = $new_content;
+		}
+
+		$updated = wp_update_post( $post, true );
+	
+		if ( is_wp_error( $updated ) || intval( $updated ) < 1 ) {
+			wp_send_json_error( array( 'errorMessage' => __( 'Error while saving the post. Please try again later.' ) ) );
+		} else {
+			if ( isset( $post['post_format'] ) ) {
+				if ( current_theme_supports( 'post-formats', $post['post_format'] ) ) {
+					set_post_format( $post_id, $post['post_format'] );
+				} elseif ( $post['post_format'] ) {
+					set_post_format( $post_id, false );
+				}
+			}
+
+			if ( 'publish' === get_post_status( $post_id ) ) {
+				/**
+				 * Filter the URL to redirect to when Press This saves.
+				 *
+				 * @since 4.2.0
+				 *
+				 * @param string $url     Redirect URL. If `$status` is 'publish', this will be the post permalink.
+				 *                        Otherwise, the post edit URL will be used.
+				 * @param int    $post_id Post ID.
+				 * @param string $status  Post status.
+				 */
+				$redirect = apply_filters( 'press_this_save_redirect', get_post_permalink( $post_id ), $post_id, $post['post_status'] );
+			} else {
+				/** This filter is documented in wp-admin/includes/class-wp-press-this.php */
+				$redirect = apply_filters( 'press_this_save_redirect', get_edit_post_link( $post_id, 'raw' ), $post_id, $post['post_status'] );
+			}
+	
+			wp_send_json_success( array( 'redirect' => $redirect ) );
+		}
+	}
+
+	/**
+	 * AJAX handler for adding a new category.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 */
+	public function add_category() {
+		if ( false === wp_verify_nonce( $_POST['new_cat_nonce'], 'add-category' ) ) {
+			wp_send_json_error();
+		}
+
+		$taxonomy = get_taxonomy( 'category' );
+
+		if ( ! current_user_can( $taxonomy->cap->edit_terms ) || empty( $_POST['name'] ) ) {
+			wp_send_json_error();
+		}
+
+		$parent = isset( $_POST['parent'] ) && (int) $_POST['parent'] > 0 ? (int) $_POST['parent'] : 0;
+		$names = explode( ',', $_POST['name'] );
+		$added = $data = array();
+
+		foreach ( $names as $cat_name ) {
+			$cat_name = trim( $cat_name );
+			$cat_nicename = sanitize_title( $cat_name );
+
+			if ( empty( $cat_nicename ) ) {
+				continue;
+			}
+
+			// @todo Find a more performant to check existence, maybe get_term() with a separate parent check.
+			if ( ! $cat_id = term_exists( $cat_name, $taxonomy->name, $parent ) ) {
+				$cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
+			}
+
+			if ( is_wp_error( $cat_id ) ) {
+				continue;
+			} elseif ( is_array( $cat_id ) ) {
+				$cat_id = $cat_id['term_id'];
+			}
+
+			$added[] = $cat_id;
+		}
+
+		if ( empty( $added ) ) {
+			wp_send_json_error( array( 'errorMessage' => __( 'This category cannot be added. Please change the name and try again.' ) ) );
+		}
+
+		foreach ( $added as $new_cat_id ) {
+			$new_cat = get_category( $new_cat_id );
+
+			if ( is_wp_error( $new_cat ) ) {
+				wp_send_json_error( array( 'errorMessage' => __( 'Error while adding the category. Please try again later.' ) ) );
+			}
+
+			$data[] = array(
+				'term_id' => $new_cat->term_id,
+				'name' => $new_cat->name,
+				'parent' => $new_cat->parent,
+			);
+		}
+		wp_send_json_success( $data );
+	}
+
+	/**
+	 * Downloads the source's HTML via server-side call for the given URL.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 *
+	 * @param string $url URL to scan.
+	 * @return string Source's HTML sanitized markup
+	 */
+	public function fetch_source_html( $url ) {
+		// Download source page to tmp file.
+		$source_tmp_file = ( ! empty( $url ) ) ? download_url( $url ) : '';
+		$source_content  = '';
+
+		if ( ! is_wp_error( $source_tmp_file ) && file_exists( $source_tmp_file ) ) {
+			// Get the content of the source page from the tmp file..
+
+			$source_content = wp_kses(
+				file_get_contents( $source_tmp_file ),
+				array(
+					'img' => array(
+						'src'      => array(),
+					),
+					'iframe' => array(
+						'src'      => array(),
+					),
+					'link' => array(
+						'rel'      => array(),
+						'itemprop' => array(),
+						'href'     => array(),
+					),
+					'meta' => array(
+						'property' => array(),
+						'name'     => array(),
+						'content'  => array(),
+					)
+				)
+			);
+
+			// All done with backward compatibility. Let's do some cleanup, for good measure :)
+			unlink( $source_tmp_file );
+
+		} else if ( is_wp_error( $source_tmp_file ) ) {
+			$source_content = new WP_Error( 'upload-error',  sprintf( __( 'Error: %s' ), sprintf( __( 'Could not download the source URL (native error: %s).' ), $source_tmp_file->get_error_message() ) ) );
+		} else if ( ! file_exists( $source_tmp_file ) ) {
+			$source_content = new WP_Error( 'no-local-file',  sprintf( __( 'Error: %s' ), __( 'Could not save or locate the temporary download file for the source URL.' ) ) );
+		}
+
+		return $source_content;
+	}
+
+	/**
+	 * Fetches and parses _meta, _img, and _links data from the source.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 *
+	 * @param string $url  URL to scan.
+	 * @param array  $data Optional. Existing data array if you have one. Default empty array.
+	 * @return array New data array.
+	 */
+	public function source_data_fetch_fallback( $url, $data = array() ) {
+		if ( empty( $url ) ) {
+			return array();
+		}
+
+		// Download source page to tmp file.
+		$source_content = $this->fetch_source_html( $url );
+		if ( is_wp_error( $source_content ) ) {
+			return array( 'errors' => $source_content->get_error_messages() );
+		}
+
+		// Fetch and gather <img> data.
+		if ( empty( $data['_img'] ) ) {
+			$data['_img'] = array();
+		}
+
+		if ( preg_match_all( '/<img (.+)[\s]?\/>/', $source_content, $matches ) ) {
+			if ( ! empty( $matches[0] ) ) {
+				foreach ( $matches[0] as $value ) {
+					if ( preg_match( '/<img[^>]+src="([^"]+)"[^>]+\/>/', $value, $new_matches ) ) {
+						if ( ! in_array( $new_matches[1], $data['_img'] ) ) {
+							$data['_img'][] = $new_matches[1];
+						}
+					}
+				}
+			}
+		}
+
+		// Fetch and gather <iframe> data.
+		if ( empty( $data['_embed'] ) ) {
+			$data['_embed'] = array();
+		}
+
+		if ( preg_match_all( '/<iframe (.+)[\s][^>]*>/', $source_content, $matches ) ) {
+			if ( ! empty( $matches[0] ) ) {
+				foreach ( $matches[0] as $value ) {
+					if ( preg_match( '/<iframe[^>]+src=(\'|")([^"]+)(\'|")/', $value, $new_matches ) ) {
+						if ( ! in_array( $new_matches[2], $data['_embed'] ) ) {
+							if ( preg_match( '/\/\/www\.youtube\.com\/embed\/([^\?]+)\?.+$/', $new_matches[2], $src_matches ) ) {
+								$data['_embed'][] = 'https://www.youtube.com/watch?v=' . $src_matches[1];
+							} else if ( preg_match( '/\/\/player\.vimeo\.com\/video\/([\d]+)([\?\/]{1}.*)?$/', $new_matches[2], $src_matches ) ) {
+								$data['_embed'][] = 'https://vimeo.com/' . (int) $src_matches[1];
+							} else if ( preg_match( '/\/\/vine\.co\/v\/([^\/]+)\/embed/', $new_matches[2], $src_matches ) ) {
+								$data['_embed'][] = 'https://vine.co/v/' . $src_matches[1];
+							}
+						}
+					}
+				}
+			}
+		}
+
+		// Fetch and gather <meta> data.
+		if ( empty( $data['_meta'] ) ) {
+			$data['_meta'] = array();
+		}
+
+		if ( preg_match_all( '/<meta ([^>]+)[\s]?\/?>/  ', $source_content, $matches ) ) {
+			if ( ! empty( $matches[0] ) ) {
+				foreach ( $matches[0] as $key => $value ) {
+					if ( preg_match( '/<meta[^>]+(property|name)="(.+)"[^>]+content="(.+)"/', $value, $new_matches ) ) {
+						if ( empty( $data['_meta'][ $new_matches[2] ] ) ) {
+							if ( preg_match( '/:?(title|description|keywords)$/', $new_matches[2] ) ) {
+								$data['_meta'][ $new_matches[2] ] = str_replace( '&#039;', "'", str_replace( '&#034;', '', html_entity_decode( $new_matches[3] ) ) );
+							} else {
+								$data['_meta'][ $new_matches[2] ] = $new_matches[3];
+								if ( 'og:url' == $new_matches[2] ) {
+									if ( false !== strpos( $new_matches[3], '//www.youtube.com/watch?' )
+									     || false !== strpos( $new_matches[3], '//www.dailymotion.com/video/' )
+									     || preg_match( '/\/\/vimeo\.com\/[\d]+$/', $new_matches[3] )
+									     || preg_match( '/\/\/soundcloud\.com\/.+$/', $new_matches[3] )
+									     || preg_match( '/\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/', $new_matches[3] )
+									     || preg_match( '/\/\/vine\.co\/v\/[^\/]+/', $new_matches[3] ) ) {
+										if ( ! in_array( $new_matches[3], $data['_embed'] ) ) {
+											$data['_embed'][] = $new_matches[3];
+										}
+									}
+								} else if ( 'og:video' == $new_matches[2] || 'og:video:secure_url' == $new_matches[2] ) {
+									if ( preg_match( '/\/\/www\.youtube\.com\/v\/([^\?]+)/', $new_matches[3], $src_matches ) ) {
+										if ( ! in_array( 'https://www.youtube.com/watch?v=' . $src_matches[1], $data['_embed'] ) ) {
+											$data['_embed'][] = 'https://www.youtube.com/watch?v=' . $src_matches[1];
+										}
+									} else if ( preg_match( '/\/\/vimeo.com\/moogaloop\.swf\?clip_id=([\d]+)$/', $new_matches[3], $src_matches ) ) {
+										if ( ! in_array( 'https://vimeo.com/' . $src_matches[1], $data['_embed'] ) ) {
+											$data['_embed'][] = 'https://vimeo.com/' . $src_matches[1];
+										}
+									}
+								} else if ( 'og:image' == $new_matches[2] || 'og:image:secure_url' == $new_matches[2] ) {
+									if ( ! in_array( $new_matches[3], $data['_img'] ) ) {
+										$data['_img'][] = $new_matches[3];
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+
+		// Fetch and gather <link> data
+		if ( empty( $data['_links'] ) ) {
+			$data['_links'] = array();
+		}
+
+		if ( preg_match_all( '/<link ([^>]+)[\s]?\/>/', $source_content, $matches ) ) {
+			if ( ! empty( $matches[0] ) ) {
+				foreach ( $matches[0] as $key => $value ) {
+					if ( preg_match( '/<link[^>]+(rel|itemprop)="([^"]+)"[^>]+href="([^"]+)"[^>]+\/>/', $value, $new_matches ) ) {
+						if ( 'alternate' == $new_matches[2] || 'thumbnailUrl' == $new_matches[2] || 'url' == $new_matches[2] ) {
+							if ( empty( $data['_links'][ $new_matches[2] ] ) ) {
+								$data['_links'][ $new_matches[2] ] = $new_matches[3];
+							}
+						}
+					}
+				}
+			}
+		}
+
+		return $data;
+	}
+
+	/**
+	 * Handles backward-compat with the legacy version of Press This by supporting its query string params.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 *
+	 * @return array
+	 */
+	public function merge_or_fetch_data() {
+		// Merge $_POST and $_GET, as appropriate ($_POST > $_GET), to remain backward compatible.
+		$data = array_merge_recursive( $_POST, $_GET );
+
+		// Get the legacy QS params, or equiv POST data
+		$data['u'] = ( ! empty( $data['u'] ) && preg_match( '/^https?:/', $data['u'] ) ) ? $data['u'] : '';
+		$data['s'] = ( ! empty( $data['s'] ) ) ? $data['s'] : '';
+		$data['t'] = ( ! empty( $data['t'] ) ) ? $data['t'] : '';
+
+		/**
+		 * Filter whether to enable in-source media discovery in Press This.
+		 *
+		 * @since 4.2.0
+		 *
+		 * @param bool $enable Whether to enable media discovery.
+		 */
+		if ( apply_filters( 'enable_press_this_media_discovery', __return_true() ) ) {
+			/*
+			 * If no _meta (a new thing) was passed via $_POST, fetch data from source as fallback,
+			 * makes PT fully backward compatible
+			 */
+			if ( empty( $data['_meta'] ) && ! empty( $data['u'] ) ) {
+				$data = $this->source_data_fetch_fallback( $data['u'], $data );
+			}
+		} else {
+			if ( ! empty( $data['_img'] ) ) {
+				$data['_img'] = array();
+			}
+			if ( ! empty( $data['_embed'] ) ) {
+				$data['_embed'] = array();
+			}
+			if ( ! empty( $data['_meta'] ) ) {
+				$data['_meta'] = array();
+			}
+		}
+
+		/**
+		 * Filter the Press This data array.
+		 *
+		 * @since 4.2.0
+		 *
+		 * @param array $data Press This Data array.
+		 */
+		return apply_filters( 'press_this_data', $data );
+	}
+
+	/**
+	 * Adds another stylesheet inside TinyMCE.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 *
+	 * @param string $styles URL to editor stylesheet.
+	 * @return string Possibly modified stylesheets list.
+	 */
+	public function add_editor_style( $styles ) {
+		if ( ! empty( $styles ) ) {
+			$styles .= ',';
+		}
+		return $styles . admin_url( 'css/press-this-editor.css' );
+	}
+
+	/**
+	 * Outputs the post format selection HTML.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 *
+	 * @param WP_Post $post Post object.
+	 */
+	function post_formats_html( $post ) {
+		if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) ) {
+			$post_formats = get_theme_support( 'post-formats' );
+
+			if ( is_array( $post_formats[0] ) ) {
+				$post_format = get_post_format( $post->ID );
+
+				if ( ! $post_format ) {
+					$post_format = '0';
+				}
+
+				// Add in the current one if it isn't there yet, in case the current theme doesn't support it.
+				if ( $post_format && ! in_array( $post_format, $post_formats[0] ) ) {
+					$post_formats[0][] = $post_format;
+				}
+
+				?>
+				<div id="post-formats-select">
+					<input type="radio" name="post_format" class="post-format" id="post-format-0" value="0" <?php checked( $post_format, '0' ); ?> />
+					<label for="post-format-0" class="post-format-icon post-format-standard"><?php echo get_post_format_string( 'standard' ); ?></label>
+					<?php
+
+					foreach ( $post_formats[0] as $format ) {
+						$attr_format = esc_attr( $format );
+						?>
+						<br />
+						<input type="radio" name="post_format" class="post-format" id="post-format-<?php echo $attr_format; ?>" value="<?php echo $attr_format; ?>" <?php checked( $post_format, $format ); ?> />
+						<label for="post-format-<?php echo $attr_format ?>" class="post-format-icon post-format-<?php echo $attr_format; ?>"><?php echo esc_html( get_post_format_string( $format ) ); ?></label>
+						<?php
+					 }
+					 ?>
+				</div>
+				<?php
+			}
+		}
+	}
+
+	/**
+	 * Outputs the categories HTML.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 *
+	 * @param WP_Post $post Post object.
+	 */
+	function categories_html( $post ) {
+		$taxonomy = get_taxonomy( 'category' );
+
+		if ( current_user_can( $taxonomy->cap->edit_terms ) ) {
+			?>
+			<button type="button" class="add-cat-toggle button-subtle">
+				<span class="dashicons dashicons-plus"></span>
+			</button>
+			<div class="add-category is-hidden">
+				<label class="screen-reader-text" for="new-category"><?php echo $taxonomy->labels->add_new_item; ?></label>
+				<input type="text" id="new-category" class="add-category-name" placeholder="<?php echo esc_attr( $taxonomy->labels->new_item_name ); ?>" value="" aria-required="true">
+				<label class="screen-reader-text" for="new-category-parent"><?php echo $taxonomy->labels->parent_item_colon; ?></label>
+				<div class="postform-wrapper">
+					<?php
+					wp_dropdown_categories( array(
+						'taxonomy'         => 'category',
+						'hide_empty'       => 0,
+						'name'             => 'new-category-parent',
+						'orderby'          => 'name',
+						'hierarchical'     => 1,
+						'show_option_none' => '&mdash; ' . $taxonomy->labels->parent_item . ' &mdash;'
+					) );
+					?>
+				</div>
+				<button type="button" class="button add-cat-submit"><?php _e( 'Add' ); ?></button>
+			</div>
+		<?php } ?>
+		<div class="categories-search-wrapper">
+			<input id="categories-search" type="search" class="categories-search" placeholder="<?php esc_attr_e( 'Search categories' ) ?>">
+			<label for="categories-search">
+				<span class="dashicons dashicons-search"></span>
+			</label>
+		</div>
+		<ul class="categories-select">
+			<?php wp_terms_checklist( $post->ID, array( 'taxonomy' => 'category' ) ); ?>
+		</ul>
+		<?php
+	}
+
+	/**
+	 * Outputs the tags HTML.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 *
+	 * @param WP_Post $post Post object.
+	 */
+	function tags_html( $post ) {
+		$taxonomy              = get_taxonomy( 'post_tag' );
+		$user_can_assign_terms = current_user_can( $taxonomy->cap->assign_terms );
+		$esc_tags              = get_terms_to_edit( $post->ID, 'post_tag' );
+
+		if ( ! $esc_tags || is_wp_error( $esc_tags ) ) {
+			$esc_tags = '';
+		}
+		?>
+		<div class="tagsdiv" id="post_tag">
+			<div class="jaxtag">
+			<input type="hidden" name="tax_input[post_tag]" class="the-tags" value="<?php echo $esc_tags; // escaped in get_terms_to_edit() ?>">
+
+		 	<?php
+			if ( $user_can_assign_terms ) {
+				?>
+				<div class="ajaxtag hide-if-no-js">
+					<label class="screen-reader-text" for="new-tag-post_tag"><?php _e( 'Tags' ); ?></label>
+					<div class="taghint"><?php echo $taxonomy->labels->add_new_item; ?></div>
+					<p>
+						<input type="text" id="new-tag-post_tag" name="newtag[post_tag]" class="newtag form-input-tip" size="16" autocomplete="off" value="" />
+						<button type="button" class="button tagadd"><?php _e( 'Add' ); ?></button>
+					</p>
+				</div>
+				<p class="howto">
+					<?php echo $taxonomy->labels->separate_items_with_commas; ?>
+				</p>
+			<?php } ?>
+			</div>
+			<div class="tagchecklist"></div>
+		</div>
+		<?php
+		if ( $user_can_assign_terms ) {
+			?>
+			<p>
+				<a href="#titlediv" class="tagcloud-link" id="link-post_tag"><?php echo $taxonomy->labels->choose_from_most_used; ?></a>
+			</p>
+			<?php
+		}
+	}
+
+	/**
+	 * Serves the app's base HTML, which in turns calls the load script.
+	 *
+	 * @since 4.2.0
+	 * @access public
+	 */
+	public function html() {
+		global $wp_locale, $hook_suffix;
+
+		// Get data, new (POST) and old (GET).
+		$data = $this->merge_or_fetch_data();
+
+		// Get site settings array/data.
+		$site_settings = $this->site_settings();
+
+		// Set the passed data.
+		$data['_version'] = $site_settings['version'];
+
+		// Add press-this-editor.css and remove theme's editor-style.css, if any.
+		remove_editor_styles();
+
+		add_filter( 'mce_css', array( $this, 'add_editor_style' ) );
+
+		if ( ! empty( $GLOBALS['is_IE'] ) ) {
+			@header( 'X-UA-Compatible: IE=edge' );
+		}
+
+		@header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) );
+
+?>
+<!DOCTYPE html>
+<!--[if IE 7]>         <html class="lt-ie9 lt-ie8" <?php language_attributes(); ?>> <![endif]-->
+<!--[if IE 8]>         <html class="lt-ie9" <?php language_attributes(); ?>> <![endif]-->
+<!--[if gt IE 8]><!--> <html <?php language_attributes(); ?>> <!--<![endif]-->
+<head>
+	<meta http-equiv="Content-Type" content="<?php esc_attr( bloginfo( 'html_type' ) ); ?>; charset=<?php echo esc_attr( get_option( 'blog_charset' ) ); ?>" />
+	<meta name="viewport" content="width=device-width">
+	<title><?php esc_html_e( 'Press This!' ) ?></title>
+
+	<script>
+		window.wpPressThisData   = <?php echo json_encode( $data ) ?>;
+		window.wpPressThisConfig = <?php echo json_encode( $site_settings ) ?>;
+	</script>
+
+	<script type="text/javascript">
+		var ajaxurl = '<?php echo esc_js( admin_url( 'admin-ajax.php', 'relative' ) ); ?>',
+			pagenow = 'press-this',
+			typenow = 'post',
+			adminpage = 'press-this-php',
+			thousandsSeparator = '<?php echo addslashes( $wp_locale->number_format['thousands_sep'] ); ?>',
+			decimalPoint = '<?php echo addslashes( $wp_locale->number_format['decimal_point'] ); ?>',
+			isRtl = <?php echo esc_js( (int) is_rtl() ); ?>;
+	</script>
+
+	<?php
+		/*
+		 * $post->ID is needed for the embed shortcode so we can show oEmbed previews in the editor.
+		 * Maybe find a way without it.
+		 */
+		$post = get_default_post_to_edit( 'post', true );
+		$post_ID = (int) $post->ID;
+
+		wp_enqueue_style( 'press-this' );
+		wp_enqueue_script( 'press-this' );
+		wp_enqueue_script( 'json2' );
+		wp_enqueue_media( array( 'post' => $post->ID ) );
+		wp_enqueue_script( 'editor' );
+
+		$supports_formats = false;
+		$post_format      = 0;
+
+		if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) ) {
+			$supports_formats = true;
+
+			if ( ! ( $post_format = get_post_format( $post->ID ) ) ) {
+				$post_format = 0;
+			}
+		}
+
+		/** This action is documented in wp-admin/admin-header.php */
+		do_action( 'admin_enqueue_scripts', $hook_suffix );
+
+		/** This action is documented in wp-admin/admin-header.php */
+		do_action( 'admin_print_styles' );
+
+		/** This action is documented in wp-admin/admin-header.php */
+		do_action( 'admin_print_scripts' );
+
+	?>
+</head>
+<body>
+	<div id="adminbar" class="adminbar">
+		<h1 id="current-site" class="current-site">
+			<span class="dashicons dashicons-wordpress"></span>
+			<span><?php bloginfo( 'name' ); ?></span>
+		</h1>
+		<button type="button" class="options-open button-subtle">
+			<span class="dashicons dashicons-tag"></span><span class="screen-reader-text"><?php _e( 'Show post options' ); ?></span>
+		</button>
+		<button type="button" class="options-close button-subtle is-hidden"><?php _e( 'Done' ); ?></button>
+	</div>
+
+	<div id="scanbar" class="scan">
+		<form method="GET">
+			<input type="url" name="u" id="url-scan" class="scan-url" value="" placeholder="<?php esc_attr_e( 'Enter a URL to scan' ) ?>" />
+			<input type="submit" name="url-scan-submit" id="url-scan-submit" class="scan-submit" value="<?php esc_attr_e( 'Scan' ) ?>" />
+		</form>
+	</div>
+
+	<form id="pressthis-form" name="pressthis-form" method="POST" autocomplete="off">
+		<input type="hidden" name="post_ID" id="post_ID" value="<?php echo esc_attr( $post_ID ); ?>" />
+		<input type="hidden" name="action" value="press-this-save-post" />
+		<input type="hidden" name="post_status" id="post_status" value="draft" />
+		<?php
+		wp_nonce_field( 'press-this', 'pressthis-nonce', false );
+		wp_nonce_field( 'add-category', '_ajax_nonce-add-category', false );
+		?>
+		<input type="hidden" name="title" id="title-field" value="" />
+
+	<div class="wrapper">
+		<div class="editor-wrapper">
+			<div class="alerts">
+				<p class="alert is-notice is-hidden should-upgrade-bookmarklet">
+					<?php printf( __( 'You should upgrade <a href="%s" target="_blank">your bookmarklet</a> to the latest version!' ), admin_url( 'tools.php?page=press_this_options' ) ); ?>
+				</p>
+			</div>
+
+			<div id='app-container' class="editor">
+				<span id="title-container-label" class="post-title-placeholder" aria-hidden="true"><?php _e( 'Post title' ); ?></span>
+				<h2 id="title-container" class="post-title" contenteditable="true" spellcheck="true" aria-label="<?php esc_attr_e( 'Post title' ); ?>" tabindex="0"></h2>
+				<div id='featured-media-container' class="featured-container no-media">
+					<div id='all-media-widget' class="all-media">
+						<div id='all-media-container'></div>
+					</div>
+				</div>
+
+				<?php
+				wp_editor( '', 'pressthis', array(
+					'drag_drop_upload' => true,
+					'editor_height'    => 600,
+					'media_buttons'    => false,
+					'teeny'            => true,
+					'tinymce'          => array(
+						'resize'                => false,
+						'wordpress_adv_hidden'  => false,
+						'add_unload_trigger'    => false,
+						'statusbar'             => false,
+						'autoresize_min_height' => 600,
+						'wp_autoresize_on'      => true,
+						'plugins'               => 'lists,media,paste,tabfocus,fullscreen,wordpress,wpautoresize,wpeditimage,wpgallery,wplink,wpview',
+						'toolbar1'              => 'bold,italic,bullist,numlist,blockquote,link,unlink',
+						'toolbar2'              => 'undo,redo',
+					),
+					'quicktags'        => false,
+				) );
+
+				?>
+			</div>
+		</div>
+
+		<div class="options-panel is-off-screen is-hidden">
+			<div class="post-options">
+
+				<?php if ( $supports_formats ) : ?>
+					<button type="button" class="button-reset post-option">
+						<span class="dashicons dashicons-admin-post"></span>
+						<span class="post-option-title"><?php _e( 'Format' ); ?></span>
+						<span class="post-option-contents" id="post-option-post-format"><?php echo esc_html( get_post_format_string( $post_format ) ); ?></span>
+						<span class="dashicons dashicons-arrow-right-alt2"></span>
+					</button>
+				<?php endif; ?>
+
+				<button type="button" class="button-reset post-option">
+					<span class="dashicons dashicons-category"></span>
+					<span class="post-option-title"><?php _e( 'Categories' ); ?></span>
+					<span class="post-option-contents" id="post-option-category"></span>
+					<span class="dashicons dashicons-arrow-right-alt2"></span>
+				</button>
+
+				<button type="button" class="button-reset post-option">
+					<span class="dashicons dashicons-tag"></span>
+					<span class="post-option-title"><?php _e( 'Tags' ); ?></span>
+					<span class="post-option-contents" id="post-option-tags"></span>
+					<span class="dashicons dashicons-arrow-right-alt2"></span>
+				</button>
+			</div>
+
+			<?php if ( $supports_formats ) : ?>
+				<div class="setting-modal is-off-screen is-hidden">
+					<button type="button" class="button-reset modal-close">
+						<span class="dashicons dashicons-arrow-left-alt2"></span><span class="setting-title"><?php _e( 'Post format' ); ?></span>
+					</button>
+					<?php $this->post_formats_html( $post ); ?>
+				</div>
+			<?php endif; ?>
+
+			<div class="setting-modal is-off-screen is-hidden">
+				<button type="button" class="button-reset modal-close"><span class="dashicons dashicons-arrow-left-alt2"></span><span class="setting-title"><?php _e( 'Categories' ); ?></span></button>
+				<?php $this->categories_html( $post ); ?>
+			</div>
+
+			<div class="setting-modal tags is-off-screen is-hidden">
+				<button type="button" class="button-reset modal-close"><span class="dashicons dashicons-arrow-left-alt2"></span><span class="setting-title"><?php _e( 'Tags' ); ?></span></button>
+				<?php $this->tags_html( $post ); ?>
+			</div>
+		</div><!-- .options-panel -->
+	</div><!-- .wrapper -->
+
+	<div class="press-this-actions">
+		<div class="pressthis-media-buttons">
+			<button type="button" class="insert-media button-subtle" data-editor="pressthis">
+				<span class="dashicons dashicons-admin-media"></span>
+				<span class="screen-reader-text"><?php _e( 'Add Media' ); ?></span>
+			</button>
+		</div>
+		<div class="post-actions">
+			<button type="button" class="button-subtle" id="draft-field"><?php _e( 'Save Draft' ); ?></button>
+			<button type="button" class="button-primary" id="publish-field"><?php _e( 'Publish' ); ?></button>
+		</div>
+	</div>
+	</form>
+
+	<?php
+
+		// TODO: consider running "special" press-this hooks here?
+		// Maybe better so we don't output stuff accidentaly added by plugins. Would probably prevent some errors.
+		do_action( 'admin_footer', '' );
+		do_action( 'admin_print_footer_scripts' );
+
+	?>
+</body>
+</html>
+<?php
+		die();
+	}
+}
+$GLOBALS['wp_press_this'] = new WP_Press_This;
Index: src/wp-admin/js/bookmarklet.js
===================================================================
--- src/wp-admin/js/bookmarklet.js	(revision 0)
+++ src/wp-admin/js/bookmarklet.js	(working copy)
@@ -0,0 +1,561 @@
+( function( window, document, href, pt_url ) {
+	var encodeURI = window.encodeURIComponent,
+		form = document.createElement( 'form' ),
+		head = document.getElementsByTagName( 'head' )[0],
+		img = new Image(),
+		target = '_press_this_app',
+		windowWidth, windowHeight,
+		metas, links, content, imgs, ifrs,
+		vid, selection;
+
+	if ( ! pt_url ) {
+		return;
+	}
+
+	if ( window.getSelection ) {
+		selection = window.getSelection() + '';
+	} else if ( document.getSelection ) {
+		selection = document.getSelection() + '';
+	} else if ( document.selection ) {
+		selection = document.selection.createRange().text;
+	}
+
+	pt_url += ( pt_url.indexOf( '?' ) > -1 ? '&' : '?' ) + 'buster=' + ( new Date().getTime() );
+
+	if ( document.title.length && document.title.length <= 512 ) {
+		pt_url += '&t=' + encodeURI( document.title );
+	}
+
+	if ( selection && selection.length <= 512 ) {
+		pt_url += '&s=' + encodeURI( selection );
+	}
+
+	if ( href.match( /^https?:/ ) ) {
+		pt_url += '&u=' + encodeURI( href );
+	} else {
+		top.location.href = pt_url;
+		return;
+	}
+
+	function add( name, value ) {
+		if ( typeof value === 'undefined' ) {
+			return;
+		}
+
+		var input = document.createElement( 'input' );
+
+		input.name = name;
+		input.value = value;
+		input.type = 'hidden';
+
+		form.appendChild( input );
+	}
+
+	if ( href.match( /\/\/www\.youtube\.com\/watch/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/vimeo\.com\/(.+\/)?([\d]+)$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/soundcloud\.com\/.+$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
+		add( '_embed[]', href );
+	}
+
+	metas = head.getElementsByTagName( 'meta' ) || [];
+
+	for ( var m = 0; m < metas.length; m++ ) {
+		if ( m >= 50 ) {
+			break;
+		}
+
+		var q = metas[ m ],
+			q_name = q.getAttribute( 'name' ),
+			q_prop = q.getAttribute( 'property' ),
+			q_cont = q.getAttribute( 'content' );
+
+		if ( q_name ) {
+			add( '_meta[' + q_name + ']', q_cont );
+		} else if ( q_prop ) {
+			add( '_meta[' + q_prop + ']', q_cont );
+		}
+	}
+
+	links = head.getElementsByTagName( 'link' ) || [];
+
+	for ( var y = 0; y < links.length; y++ ) {
+		if ( y >= 50 ) {
+			break;
+		}
+
+		var g = links[ y ],
+			g_rel = g.getAttribute( 'rel' );
+
+		if ( g_rel ) {
+			switch ( g_rel ) {
+				case 'canonical':
+				case 'icon':
+				case 'shortlink':
+					add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
+					break;
+				case 'alternate':
+					if ( 'application/json+oembed' === g.getAttribute( 'type' ) ) {
+						add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
+					} else if ( 'handheld' === g.getAttribute( 'media' ) ) {
+						add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
+					}
+			}
+		}
+	}
+
+	if ( document.body.getElementsByClassName ) {
+		content = document.body.getElementsByClassName( 'hfeed' )[0];
+	}
+
+	content = document.getElementById( 'content' ) || content || document.body;
+	imgs = content.getElementsByTagName( 'img' ) || [];
+
+	for ( var n = 0; n < imgs.length; n++ ) {
+		if ( n >= 100 ) {
+			break;
+		}
+
+		if ( imgs[ n ].src.indexOf( 'avatar' ) > -1 || imgs[ n ].className.indexOf( 'avatar' ) > -1 ) {
+			continue;
+		}
+
+		img.src = imgs[ n ].src;
+
+		if ( img.width >= 256 && img.height >= 128 ) {
+			add( '_img[]', img.src );
+		}
+	}
+
+	ifrs = document.body.getElementsByTagName( 'iframe' ) || [];
+
+	for ( var p = 0; p < ifrs.length; p++ ) {
+		if ( p >= 100 ) {
+			break;
+		}
+
+		vid = ifrs[ p ].src.match(/\/\/www\.youtube\.com\/embed\/([^\?]+)\?.+$/);
+
+		if ( vid && 2 === vid.length ) {
+			add( '_embed[]', 'https://www.youtube.com/watch?v=' + vid[1] );
+		}
+
+		vid = ifrs[ p ].src.match( /\/\/player\.vimeo\.com\/video\/([\d]+)$/ );
+
+		if ( vid && 2 === vid.length ) {
+			add( '_embed[]', 'https://vimeo.com/' + vid[1] );
+		}
+
+		vid = ifrs[ p ].src.match( /\/\/vine\.co\/v\/([^\/]+)\/embed/ );
+
+		if ( vid && 2 === vid.length ) {
+			add( '_embed[]', 'https://vine.co/v/' + vid[1] );
+		}
+	}
+
+	if ( document.title && document.title > 512 ) {
+		add( 't', document.title );
+	}
+
+	if ( selection && selection.length > 512 ) {
+		add( 's', selection );
+	}
+
+	form.setAttribute( 'method', 'POST' );
+	form.setAttribute( 'action', pt_url );
+	form.setAttribute( 'target', target );
+	form.setAttribute( 'style', 'display: none;' );
+
+	windowWidth  = window.outerWidth || document.documentElement.clientWidth || 600;
+	windowHeight = window.outerHeight || document.documentElement.clientHeight || 700;
+
+	windowWidth = ( windowWidth < 800 || windowWidth > 5000 ) ? 600 : ( windowWidth * 0.7 );
+	windowHeight = ( windowHeight < 800 || windowHeight > 3000 ) ? 700 : ( windowHeight * 0.9 );
+
+	window.open( 'about:blank', target, 'width=' + windowWidth + ',height=' + windowHeight );
+
+	document.body.appendChild( form );
+
+	form.submit();
+} )( window, document, top.location.href, window.pt_url );
+( function( window, document, href, pt_url ) {
+	var encodeURI = window.encodeURIComponent,
+		form = document.createElement( 'form' ),
+		head = document.getElementsByTagName( 'head' )[0],
+		img = new Image(),
+		target = '_press_this_app',
+		windowWidth, windowHeight,
+		metas, links, content, imgs, ifrs,
+		vid, selection;
+
+	if ( ! pt_url ) {
+		return;
+	}
+
+	if ( window.getSelection ) {
+		selection = window.getSelection() + '';
+	} else if ( document.getSelection ) {
+		selection = document.getSelection() + '';
+	} else if ( document.selection ) {
+		selection = document.selection.createRange().text;
+	}
+
+	pt_url += ( pt_url.indexOf( '?' ) > -1 ? '&' : '?' ) + 'buster=' + ( new Date().getTime() );
+
+	if ( document.title.length && document.title.length <= 512 ) {
+		pt_url += '&t=' + encodeURI( document.title );
+	}
+
+	if ( selection && selection.length <= 512 ) {
+		pt_url += '&s=' + encodeURI( selection );
+	}
+
+	if ( href.match( /^https?:/ ) ) {
+		pt_url += '&u=' + encodeURI( href );
+	} else {
+		top.location.href = pt_url;
+		return;
+	}
+
+	function add( name, value ) {
+		if ( typeof value === 'undefined' ) {
+			return;
+		}
+
+		var input = document.createElement( 'input' );
+
+		input.name = name;
+		input.value = value;
+		input.type = 'hidden';
+
+		form.appendChild( input );
+	}
+
+	if ( href.match( /\/\/www\.youtube\.com\/watch/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/vimeo\.com\/(.+\/)?([\d]+)$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/soundcloud\.com\/.+$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
+		add( '_embed[]', href );
+	}
+
+	metas = head.getElementsByTagName( 'meta' ) || [];
+
+	for ( var m = 0; m < metas.length; m++ ) {
+		if ( m >= 50 ) {
+			break;
+		}
+
+		var q = metas[ m ],
+			q_name = q.getAttribute( 'name' ),
+			q_prop = q.getAttribute( 'property' ),
+			q_cont = q.getAttribute( 'content' );
+
+		if ( q_name ) {
+			add( '_meta[' + q_name + ']', q_cont );
+		} else if ( q_prop ) {
+			add( '_meta[' + q_prop + ']', q_cont );
+		}
+	}
+
+	links = head.getElementsByTagName( 'link' ) || [];
+
+	for ( var y = 0; y < links.length; y++ ) {
+		if ( y >= 50 ) {
+			break;
+		}
+
+		var g = links[ y ],
+			g_rel = g.getAttribute( 'rel' );
+
+		if ( g_rel ) {
+			switch ( g_rel ) {
+				case 'canonical':
+				case 'icon':
+				case 'shortlink':
+					add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
+					break;
+				case 'alternate':
+					if ( 'application/json+oembed' === g.getAttribute( 'type' ) ) {
+						add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
+					} else if ( 'handheld' === g.getAttribute( 'media' ) ) {
+						add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
+					}
+			}
+		}
+	}
+
+	if ( document.body.getElementsByClassName ) {
+		content = document.body.getElementsByClassName( 'hfeed' )[0];
+	}
+
+	content = document.getElementById( 'content' ) || content || document.body;
+	imgs = content.getElementsByTagName( 'img' ) || [];
+
+	for ( var n = 0; n < imgs.length; n++ ) {
+		if ( n >= 100 ) {
+			break;
+		}
+
+		if ( imgs[ n ].src.indexOf( 'avatar' ) > -1 || imgs[ n ].className.indexOf( 'avatar' ) > -1 ) {
+			continue;
+		}
+
+		img.src = imgs[ n ].src;
+
+		if ( img.width >= 256 && img.height >= 128 ) {
+			add( '_img[]', img.src );
+		}
+	}
+
+	ifrs = document.body.getElementsByTagName( 'iframe' ) || [];
+
+	for ( var p = 0; p < ifrs.length; p++ ) {
+		if ( p >= 100 ) {
+			break;
+		}
+
+		vid = ifrs[ p ].src.match(/\/\/www\.youtube\.com\/embed\/([^\?]+)\?.+$/);
+
+		if ( vid && 2 === vid.length ) {
+			add( '_embed[]', 'https://www.youtube.com/watch?v=' + vid[1] );
+		}
+
+		vid = ifrs[ p ].src.match( /\/\/player\.vimeo\.com\/video\/([\d]+)$/ );
+
+		if ( vid && 2 === vid.length ) {
+			add( '_embed[]', 'https://vimeo.com/' + vid[1] );
+		}
+
+		vid = ifrs[ p ].src.match( /\/\/vine\.co\/v\/([^\/]+)\/embed/ );
+
+		if ( vid && 2 === vid.length ) {
+			add( '_embed[]', 'https://vine.co/v/' + vid[1] );
+		}
+	}
+
+	if ( document.title && document.title > 512 ) {
+		add( 't', document.title );
+	}
+
+	if ( selection && selection.length > 512 ) {
+		add( 's', selection );
+	}
+
+	form.setAttribute( 'method', 'POST' );
+	form.setAttribute( 'action', pt_url );
+	form.setAttribute( 'target', target );
+	form.setAttribute( 'style', 'display: none;' );
+
+	windowWidth  = window.outerWidth || document.documentElement.clientWidth || 600;
+	windowHeight = window.outerHeight || document.documentElement.clientHeight || 700;
+
+	windowWidth = ( windowWidth < 800 || windowWidth > 5000 ) ? 600 : ( windowWidth * 0.7 );
+	windowHeight = ( windowHeight < 800 || windowHeight > 3000 ) ? 700 : ( windowHeight * 0.9 );
+
+	window.open( 'about:blank', target, 'width=' + windowWidth + ',height=' + windowHeight );
+
+	document.body.appendChild( form );
+
+	form.submit();
+} )( window, document, top.location.href, window.pt_url );
+( function( window, document, href, pt_url ) {
+	var encodeURI = window.encodeURIComponent,
+		form = document.createElement( 'form' ),
+		head = document.getElementsByTagName( 'head' )[0],
+		img = new Image(),
+		target = '_press_this_app',
+		windowWidth, windowHeight,
+		metas, links, content, imgs, ifrs,
+		vid, selection;
+
+	if ( ! pt_url ) {
+		return;
+	}
+
+	if ( window.getSelection ) {
+		selection = window.getSelection() + '';
+	} else if ( document.getSelection ) {
+		selection = document.getSelection() + '';
+	} else if ( document.selection ) {
+		selection = document.selection.createRange().text;
+	}
+
+	pt_url += ( pt_url.indexOf( '?' ) > -1 ? '&' : '?' ) + 'buster=' + ( new Date().getTime() );
+
+	if ( document.title.length && document.title.length <= 512 ) {
+		pt_url += '&t=' + encodeURI( document.title );
+	}
+
+	if ( selection && selection.length <= 512 ) {
+		pt_url += '&s=' + encodeURI( selection );
+	}
+
+	if ( href.match( /^https?:/ ) ) {
+		pt_url += '&u=' + encodeURI( href );
+	} else {
+		top.location.href = pt_url;
+		return;
+	}
+
+	function add( name, value ) {
+		if ( typeof value === 'undefined' ) {
+			return;
+		}
+
+		var input = document.createElement( 'input' );
+
+		input.name = name;
+		input.value = value;
+		input.type = 'hidden';
+
+		form.appendChild( input );
+	}
+
+	if ( href.match( /\/\/www\.youtube\.com\/watch/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/vimeo\.com\/(.+\/)?([\d]+)$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/soundcloud\.com\/.+$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
+		add( '_embed[]', href );
+	} else if ( href.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
+		add( '_embed[]', href );
+	}
+
+	metas = head.getElementsByTagName( 'meta' ) || [];
+
+	for ( var m = 0; m < metas.length; m++ ) {
+		if ( m >= 50 ) {
+			break;
+		}
+
+		var q = metas[ m ],
+			q_name = q.getAttribute( 'name' ),
+			q_prop = q.getAttribute( 'property' ),
+			q_cont = q.getAttribute( 'content' );
+
+		if ( q_name ) {
+			add( '_meta[' + q_name + ']', q_cont );
+		} else if ( q_prop ) {
+			add( '_meta[' + q_prop + ']', q_cont );
+		}
+	}
+
+	links = head.getElementsByTagName( 'link' ) || [];
+
+	for ( var y = 0; y < links.length; y++ ) {
+		if ( y >= 50 ) {
+			break;
+		}
+
+		var g = links[ y ],
+			g_rel = g.getAttribute( 'rel' );
+
+		if ( g_rel ) {
+			switch ( g_rel ) {
+				case 'canonical':
+				case 'icon':
+				case 'shortlink':
+					add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
+					break;
+				case 'alternate':
+					if ( 'application/json+oembed' === g.getAttribute( 'type' ) ) {
+						add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
+					} else if ( 'handheld' === g.getAttribute( 'media' ) ) {
+						add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
+					}
+			}
+		}
+	}
+
+	if ( document.body.getElementsByClassName ) {
+		content = document.body.getElementsByClassName( 'hfeed' )[0];
+	}
+
+	content = document.getElementById( 'content' ) || content || document.body;
+	imgs = content.getElementsByTagName( 'img' ) || [];
+
+	for ( var n = 0; n < imgs.length; n++ ) {
+		if ( n >= 100 ) {
+			break;
+		}
+
+		if ( imgs[ n ].src.indexOf( 'avatar' ) > -1 || imgs[ n ].className.indexOf( 'avatar' ) > -1 ) {
+			continue;
+		}
+
+		img.src = imgs[ n ].src;
+
+		if ( img.width >= 256 && img.height >= 128 ) {
+			add( '_img[]', img.src );
+		}
+	}
+
+	ifrs = document.body.getElementsByTagName( 'iframe' ) || [];
+
+	for ( var p = 0; p < ifrs.length; p++ ) {
+		if ( p >= 100 ) {
+			break;
+		}
+
+		vid = ifrs[ p ].src.match(/\/\/www\.youtube\.com\/embed\/([^\?]+)\?.+$/);
+
+		if ( vid && 2 === vid.length ) {
+			add( '_embed[]', 'https://www.youtube.com/watch?v=' + vid[1] );
+		}
+
+		vid = ifrs[ p ].src.match( /\/\/player\.vimeo\.com\/video\/([\d]+)$/ );
+
+		if ( vid && 2 === vid.length ) {
+			add( '_embed[]', 'https://vimeo.com/' + vid[1] );
+		}
+
+		vid = ifrs[ p ].src.match( /\/\/vine\.co\/v\/([^\/]+)\/embed/ );
+
+		if ( vid && 2 === vid.length ) {
+			add( '_embed[]', 'https://vine.co/v/' + vid[1] );
+		}
+	}
+
+	if ( document.title && document.title > 512 ) {
+		add( 't', document.title );
+	}
+
+	if ( selection && selection.length > 512 ) {
+		add( 's', selection );
+	}
+
+	form.setAttribute( 'method', 'POST' );
+	form.setAttribute( 'action', pt_url );
+	form.setAttribute( 'target', target );
+	form.setAttribute( 'style', 'display: none;' );
+
+	windowWidth  = window.outerWidth || document.documentElement.clientWidth || 600;
+	windowHeight = window.outerHeight || document.documentElement.clientHeight || 700;
+
+	windowWidth = ( windowWidth < 800 || windowWidth > 5000 ) ? 600 : ( windowWidth * 0.7 );
+	windowHeight = ( windowHeight < 800 || windowHeight > 3000 ) ? 700 : ( windowHeight * 0.9 );
+
+	window.open( 'about:blank', target, 'width=' + windowWidth + ',height=' + windowHeight );
+
+	document.body.appendChild( form );
+
+	form.submit();
+} )( window, document, top.location.href, window.pt_url );
Index: src/wp-admin/js/post.js
===================================================================
--- src/wp-admin/js/post.js	(revision 31531)
+++ src/wp-admin/js/post.js	(working copy)
@@ -7,182 +7,9 @@
 
 window.wp = window.wp || {};
 
-// return an array with any duplicate, whitespace or values removed
-function array_unique_noempty(a) {
-	var out = [];
-	jQuery.each( a, function(key, val) {
-		val = jQuery.trim(val);
-		if ( val && jQuery.inArray(val, out) == -1 )
-			out.push(val);
-		} );
-	return out;
-}
-
-( function($) {
+( function( $ ) {
 	var titleHasFocus = false;
 
-tagBox = {
-	clean : function(tags) {
-		var comma = postL10n.comma;
-		if ( ',' !== comma )
-			tags = tags.replace(new RegExp(comma, 'g'), ',');
-		tags = tags.replace(/\s*,\s*/g, ',').replace(/,+/g, ',').replace(/[,\s]+$/, '').replace(/^[,\s]+/, '');
-		if ( ',' !== comma )
-			tags = tags.replace(/,/g, comma);
-		return tags;
-	},
-
-	parseTags : function(el) {
-		var id = el.id, num = id.split('-check-num-')[1], taxbox = $(el).closest('.tagsdiv'),
-			thetags = taxbox.find('.the-tags'), comma = postL10n.comma,
-			current_tags = thetags.val().split(comma), new_tags = [];
-		delete current_tags[num];
-
-		$.each( current_tags, function(key, val) {
-			val = $.trim(val);
-			if ( val ) {
-				new_tags.push(val);
-			}
-		});
-
-		thetags.val( this.clean( new_tags.join(comma) ) );
-
-		this.quickClicks(taxbox);
-		return false;
-	},
-
-	quickClicks : function(el) {
-		var thetags = $('.the-tags', el),
-			tagchecklist = $('.tagchecklist', el),
-			id = $(el).attr('id'),
-			current_tags, disabled;
-
-		if ( !thetags.length )
-			return;
-
-		disabled = thetags.prop('disabled');
-
-		current_tags = thetags.val().split(postL10n.comma);
-		tagchecklist.empty();
-
-		$.each( current_tags, function( key, val ) {
-			var span, xbutton;
-
-			val = $.trim( val );
-
-			if ( ! val )
-				return;
-
-			// Create a new span, and ensure the text is properly escaped.
-			span = $('<span />').text( val );
-
-			// If tags editing isn't disabled, create the X button.
-			if ( ! disabled ) {
-				xbutton = $( '<a id="' + id + '-check-num-' + key + '" class="ntdelbutton">X</a>' );
-				xbutton.click( function(){ tagBox.parseTags(this); });
-				span.prepend('&nbsp;').prepend( xbutton );
-			}
-
-			// Append the span to the tag list.
-			tagchecklist.append( span );
-		});
-	},
-
-	flushTags : function(el, a, f) {
-		var tagsval, newtags, text,
-			tags = $('.the-tags', el),
-			newtag = $('input.newtag', el),
-			comma = postL10n.comma;
-		a = a || false;
-
-		text = a ? $(a).text() : newtag.val();
-		tagsval = tags.val();
-		newtags = tagsval ? tagsval + comma + text : text;
-
-		newtags = this.clean( newtags );
-		newtags = array_unique_noempty( newtags.split(comma) ).join(comma);
-		tags.val(newtags);
-		this.quickClicks(el);
-
-		if ( !a )
-			newtag.val('');
-		if ( 'undefined' == typeof(f) )
-			newtag.focus();
-
-		return false;
-	},
-
-	get : function(id) {
-		var tax = id.substr(id.indexOf('-')+1);
-
-		$.post(ajaxurl, {'action':'get-tagcloud', 'tax':tax}, function(r, stat) {
-			if ( 0 === r || 'success' != stat )
-				r = wpAjax.broken;
-
-			r = $('<p id="tagcloud-'+tax+'" class="the-tagcloud">'+r+'</p>');
-			$('a', r).click(function(){
-				tagBox.flushTags( $(this).closest('.inside').children('.tagsdiv'), this);
-				return false;
-			});
-
-			$('#'+id).after(r);
-		});
-	},
-
-	init : function() {
-		var t = this, ajaxtag = $('div.ajaxtag');
-
-		$('.tagsdiv').each( function() {
-			tagBox.quickClicks(this);
-		});
-
-		$('input.tagadd', ajaxtag).click(function(){
-			t.flushTags( $(this).closest('.tagsdiv') );
-		});
-
-		$('div.taghint', ajaxtag).click(function(){
-			$(this).css('visibility', 'hidden').parent().siblings('.newtag').focus();
-		});
-
-		$('input.newtag', ajaxtag).blur(function() {
-			if ( '' === this.value )
-				$(this).parent().siblings('.taghint').css('visibility', '');
-		}).focus(function(){
-			$(this).parent().siblings('.taghint').css('visibility', 'hidden');
-		}).keyup(function(e){
-			if ( 13 == e.which ) {
-				tagBox.flushTags( $(this).closest('.tagsdiv') );
-				return false;
-			}
-		}).keypress(function(e){
-			if ( 13 == e.which ) {
-				e.preventDefault();
-				return false;
-			}
-		}).each(function(){
-			var tax = $(this).closest('div.tagsdiv').attr('id');
-			$(this).suggest( ajaxurl + '?action=ajax-tag-search&tax=' + tax, { delay: 500, minchars: 2, multiple: true, multipleSep: postL10n.comma + ' ' } );
-		});
-
-		// save tags on post save/publish
-		$('#post').submit(function(){
-			$('div.tagsdiv').each( function() {
-				tagBox.flushTags(this, false, 1);
-			});
-		});
-
-		// tag cloud
-		$('a.tagcloud-link').click(function(){
-			tagBox.get( $(this).attr('id') );
-			$(this).unbind().click(function(){
-				$(this).siblings('.the-tagcloud').toggle();
-				return false;
-			});
-			return false;
-		});
-	}
-};
-
 commentsBox = {
 	st : 0,
 
@@ -572,11 +399,11 @@
 
 	// multi-taxonomies
 	if ( $('#tagsdiv-post_tag').length ) {
-		tagBox.init();
+		window.tagBox && window.tagBox.init();
 	} else {
 		$('#side-sortables, #normal-sortables, #advanced-sortables').children('div.postbox').each(function(){
 			if ( this.id.indexOf('tagsdiv-') === 0 ) {
-				tagBox.init();
+				window.tagBox && window.tagBox.init();
 				return false;
 			}
 		});
Index: src/wp-admin/js/press-this.js
===================================================================
--- src/wp-admin/js/press-this.js	(revision 0)
+++ src/wp-admin/js/press-this.js	(working copy)
@@ -0,0 +1,4140 @@
+/**
+ * PressThis App
+ *
+ */
+( function( $, window ) {
+	var PressThis = function() {
+		var editor,
+			saveAlert             = false,
+			$div                  = $( '<div>' ),
+			siteConfig            = window.wpPressThisConfig || {},
+			data                  = window.wpPressThisData || {},
+			smallestWidth         = 128,
+			interestingImages	  = getInterestingImages( data ) || [],
+			interestingEmbeds	  = getInterestingEmbeds( data ) || [],
+			hasEmptyTitleStr      = false,
+			suggestedTitleStr     = getSuggestedTitle( data ),
+			suggestedContentStr   = getSuggestedContent( data ),
+			hasSetFocus           = false,
+			catsCache             = [],
+			transitionEndEvent    = ( function() {
+				var style = document.documentElement.style;
+
+				if ( typeof style.transition !== 'undefined' ) {
+					return 'transitionend';
+				}
+
+				if ( typeof style.WebkitTransition !== 'undefined' ) {
+					return 'webkitTransitionEnd';
+				}
+
+				return false;
+			}() );
+
+		/* ***************************************************************
+		 * HELPER FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Emulates our PHP __() gettext function, powered by the strings exported in pressThisL10n.
+		 *
+		 * @param key string Key of the string to be translated, as found in pressThisL10n.
+		 * @returns string Original or translated string, or empty string if no key.
+		 */
+		function __( key ) {
+			if ( key && window.pressThisL10n ) {
+				return window.pressThisL10n[key] || key;
+			}
+
+			return key || '';
+		}
+
+		/**
+		 * Strips HTML tags
+		 *
+		 * @param string string Text to have the HTML tags striped out of.
+		 * @returns string Stripped text.
+		 */
+		function stripTags( string ) {
+			string = string || '';
+
+			return string
+				.replace( /<!--[\s\S]*?(-->|$)/g, '' )
+				.replace( /<(script|style)[^>]*>[\s\S]*?(<\/\1>|$)/ig, '' )
+				.replace( /<\/?[a-z][^>]*>/ig, '' );
+		}
+
+		// TODO: needed?
+		function entityEncode( text ) {
+			return $div.text( text ).html();
+		}
+
+		/**
+		 * Strip HTML tags and entity encode some of the HTML special chars.
+		 *
+		 * @param text string Text.
+		 * @returns string Sanitized text.
+		 */
+		function sanitizeText( text ) {
+			text = stripTags( text );
+
+			return text
+				.replace( /\\/, '' )
+				.replace( /</g, '&lt;' )
+				.replace( />/g, '&gt;' )
+				.replace( /"/g, '&quot;' )
+				.replace( /'/g, '&#039;' );
+		}
+
+		/**
+		 * Allow only HTTP or protocol relative URLs.
+		 *
+		 * @param url string The URL.
+		 * @returns string Processed URL.
+		 */
+		function checkUrl( url ) {
+			url = $.trim( url || '' );
+
+			if ( /^(?:https?:)?\/\//.test( url ) ) {
+				url = stripTags( url );
+				return url.replace( /["\\]+/g, '' );
+			}
+
+			return '';
+		}
+
+		/**
+		 * Gets the source page's canonical link, based on passed location and meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered canonical URL, or empty
+		 */
+		function getCanonicalLink( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var link = '';
+
+			if ( data._links ) {
+				if ( data._links.canonical && data._links.canonical.length ) {
+					link = data._links.canonical;
+				}
+			}
+
+			if ( ! link.length && data.u ) {
+				link = data.u;
+			}
+
+			if ( ! link.length && data._meta ) {
+				if ( data._meta['twitter:url'] && data._meta['twitter:url'].length ) {
+					link = data._meta['twitter:url'];
+				} else if ( data._meta['og:url'] && data._meta['og:url'].length ) {
+					link = data._meta['og:url'];
+				}
+			}
+
+			return decodeURI( link );
+		}
+
+		/**
+		 * Gets the source page's site name, based on passed meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered site name, or empty
+		 */
+		function getSourceSiteName( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var name='';
+
+			if ( data._meta ) {
+				if ( data._meta['og:site_name'] && data._meta['og:site_name'].length ) {
+					name = data._meta['og:site_name'];
+				} else if ( data._meta['application-name'] && data._meta['application-name'].length ) {
+					name = data._meta['application-name'];
+				}
+			}
+
+			return name.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Gets the source page's title, based on passed title and meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered page title, or empty
+		 */
+		function getSuggestedTitle( data ) {
+			if ( ! data || data.length ) {
+				return __( 'newPost' );
+			}
+
+			var title = '';
+
+			if ( data.t ) {
+				title = data.t;
+			}
+
+			if ( ! title.length && data._meta ) {
+				if ( data._meta['twitter:title'] && data._meta['twitter:title'].length ) {
+					title = data._meta['twitter:title'];
+				} else if ( data._meta['og:title'] && data._meta['og:title'].length ) {
+					title = data._meta['og:title'];
+				} else if ( data._meta.title && data._meta.title.length ) {
+					title = data._meta.title;
+				}
+			}
+
+			if ( ! title.length ) {
+				title = __( 'newPost' );
+				hasEmptyTitleStr = true;
+			}
+
+			return title.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Gets the source page's suggested content, based on passed data (description, selection, etc).
+		 * Features a blockquoted excerpt, as well as content attribution, if any.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered content, or empty
+		 */
+		function getSuggestedContent( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var content   = '',
+				title     = getSuggestedTitle( data ),
+				url       = getCanonicalLink( data ),
+				siteName  = getSourceSiteName( data );
+
+			if ( data.s && data.s.length ) {
+				content = data.s;
+			} else if ( data._meta ) {
+				if ( data._meta['twitter:description'] && data._meta['twitter:description'].length ) {
+					content = data._meta['twitter:description'];
+				} else if ( data._meta['og:description'] && data._meta['og:description'].length ) {
+					content = data._meta['og:description'];
+				} else if ( data._meta.description && data._meta.description.length ) {
+					content = data._meta.description;
+				}
+			}
+
+			// Wrap suggested content in blockquote tag, if we have any.
+			content = ( content.length ? '<blockquote class="press-this-suggested-content">' + sanitizeText( content ) + '</blockquote>' : '' );
+
+			// Add a source attribution if there is one available.
+			if ( ( ( title.length && __( 'newPost' ) !== title ) || siteName.length ) && url.length ) {
+				content += '<p class="press-this-suggested-source">';
+				content += __( 'source' );
+				content += ' <cite>';
+				content += __( 'sourceLink').replace( '%1$s', encodeURI( url ) ).replace( '%2$s', sanitizeText( title || siteName ) );
+				content += '</cite></p>';
+			}
+
+			if ( ! content ) {
+				content = '';
+			}
+
+			return content.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Tests if what was passed as an embed URL is deemed to be embeddable in the editor.
+		 *
+		 * @param url string Passed URl, usually from WpPressThis_App.data._embed
+		 * @returns boolean
+		 */
+		function isEmbeddable( url ) {
+			if ( ! url ) {
+				return false;
+			} else if ( url.match( /\/\/(m\.|www\.)?youtube\.com\/watch\?/ ) || url.match( /\/youtu\.be\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/vimeo\.com\/(.+\/)?[\d]+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/soundcloud\.com\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
+				return true;
+			}
+
+			return false;
+		}
+
+		/**
+		 * Tests if what was passed as an image URL is deemed to be interesting enough to offer to the user for selection.
+		 *
+		 * @param src string Passed URl, usually from WpPressThis_App.data._ing
+		 * @returns boolean Test for false
+		 */
+		function isSrcUninterestingPath( src ) {
+			if ( src.match( /\/ad[sx]{1}?\// ) ) {
+				// Ads
+				return true;
+			} else if ( src.match( /(\/share-?this[^\.]+?\.[a-z0-9]{3,4})(\?.*)?$/ ) ) {
+				// Share-this type button
+				return true;
+			} else if ( src.match( /\/(spinner|loading|spacer|blank|rss)\.(gif|jpg|png)/ ) ) {
+				// Loaders, spinners, spacers
+				return true;
+			} else if ( src.match( /\/([^\.\/]+[-_]{1})?(spinner|loading|spacer|blank)s?([-_]{1}[^\.\/]+)?\.[a-z0-9]{3,4}/ ) ) {
+				// Fancy loaders, spinners, spacers
+				return true;
+			} else if ( src.match( /([^\.\/]+[-_]{1})?thumb[^.]*\.(gif|jpg|png)$/ ) ) {
+				// Thumbnails, too small, usually irrelevant to context
+				return true;
+			} else if ( src.match( /\/wp-includes\// ) ) {
+				// Classic WP interface images
+				return true;
+			} else if ( src.match( /[^\d]{1}\d{1,2}x\d+\.(gif|jpg|png)$/ ) ) {
+				// Most often tiny buttons/thumbs (< 100px wide)
+				return true;
+			} else if ( src.indexOf( '/g.gif' ) > -1 ) {
+				// Classic WP stats gif
+				return true;
+			} else if ( src.indexOf( '/pixel.mathtag.com' ) > -1 ) {
+				// See mathtag.com
+				return true;
+			}
+			return false;
+		}
+
+		/**
+		 * Get a list of valid embeds from what was passed via WpPressThis_App.data._embed on page load.
+		 *
+		 * @returns array
+		 */
+		function getInterestingEmbeds() {
+			var embeds             = data._embed || [],
+				interestingEmbeds  = [],
+				alreadySelected    = [];
+
+			if ( embeds.length ) {
+				$.each( embeds, function ( i, src ) {
+					if ( !src || !src.length ) {
+						// Skip: no src value
+						return;
+					} else if ( !isEmbeddable( src ) ) {
+						// Skip: not deemed embeddable
+						return;
+					}
+
+					var schemelessSrc = src.replace( /^https?:/, '' );
+
+					if ( $.inArray( schemelessSrc, alreadySelected ) > -1 ) {
+						// Skip: already shown
+						return;
+					}
+
+					interestingEmbeds.push( src );
+					alreadySelected.push( schemelessSrc );
+				} );
+			}
+
+			return interestingEmbeds;
+		}
+
+		/**
+		 * Get what is likely the most valuable image from what was passed via WpPressThis_App.data._img and WpPressThis_App.data._meta on page load.
+		 *
+		 * @returns array
+		 */
+		function getFeaturedImage( data ) {
+			var featured = '';
+
+			if ( ! data || ! data._meta ) {
+				return '';
+			}
+
+			if ( data._meta['twitter:image0:src'] && data._meta['twitter:image0:src'].length ) {
+				featured = data._meta['twitter:image0:src'];
+			} else if ( data._meta['twitter:image0'] && data._meta['twitter:image0'].length ) {
+				featured = data._meta['twitter:image0'];
+			} else if ( data._meta['twitter:image:src'] && data._meta['twitter:image:src'].length ) {
+				featured = data._meta['twitter:image:src'];
+			} else if ( data._meta['twitter:image'] && data._meta['twitter:image'].length ) {
+				featured = data._meta['twitter:image'];
+			} else if ( data._meta['og:image'] && data._meta['og:image'].length ) {
+				featured = data._meta['og:image'];
+			} else if ( data._meta['og:image:secure_url'] && data._meta['og:image:secure_url'].length ) {
+				featured = data._meta['og:image:secure_url'];
+			}
+
+			featured = checkUrl( featured );
+
+			return ( isSrcUninterestingPath( featured ) ) ? '' : featured;
+		}
+
+		/**
+		 * Get a list of valid images from what was passed via WpPressThis_App.data._img and WpPressThis_App.data._meta on page load.
+		 *
+		 * @returns array
+		 */
+		function getInterestingImages( data ) {
+			var imgs             = data._img || [],
+				featuredPict     = getFeaturedImage( data ) || '',
+				interestingImgs  = [],
+				alreadySelected  = [];
+
+			if ( featuredPict.length ) {
+				interestingImgs.push( featuredPict );
+				alreadySelected.push( featuredPict.replace(/^https?:/, '') );
+			}
+
+			if ( imgs.length ) {
+				$.each( imgs, function ( i, src ) {
+					src = src.replace( /http:\/\/[\d]+\.gravatar\.com\//, 'https://secure.gravatar.com/' );
+					src = checkUrl( src );
+
+					if ( ! src || ! src.length ) {
+						// Skip: no src value
+						return;
+					}
+
+					var schemelessSrc = src.replace( /^https?:/, '' );
+
+					if ( Array.prototype.indexOf && alreadySelected.indexOf( schemelessSrc ) > -1 ) {
+						// Skip: already shown
+						return;
+					} else if ( isSrcUninterestingPath( src ) ) {
+						// Skip: spinner, stat, ad, or spacer pict
+						return;
+					} else if ( src.indexOf( 'avatar' ) > -1 && interestingImgs.length >= 15 ) {
+						// Skip:  some type of avatar and we've already gathered more than 23 diff images to show
+						return;
+					}
+
+					interestingImgs.push( src );
+					alreadySelected.push( schemelessSrc );
+				} );
+			}
+
+			return interestingImgs;
+		}
+
+		/**
+		 * Show UX spinner
+		 */
+		function showSpinner() {
+			$( '#spinner' ).addClass( 'show' );
+			$( '.post-actions button' ).each( function() {
+				$( this ).attr( 'disabled', 'disabled' );
+			} );
+		}
+
+		/**
+		 * Hide UX spinner
+		 */
+		function hideSpinner() {
+			$( '#spinner' ).removeClass( 'show' );
+			$( '.post-actions button' ).each( function() {
+				$( this ).removeAttr( 'disabled' );
+			} );
+		}
+
+		/**
+		 * Submit the post form via AJAX, and redirect to the proper screen if published vs saved as a draft.
+		 *
+		 * @param action string publish|draft
+		 */
+		function submitPost( action ) {
+			saveAlert = false;
+			showSpinner();
+
+			var $form = $( '#pressthis-form' );
+
+			if ( 'publish' === action ) {
+				$( '#post_status' ).val( 'publish' );
+			}
+
+			editor && editor.save();
+
+			$( '#title-field' ).val( sanitizeText( $( '#title-container' ).text() ) );
+
+			// Make sure to flush out the tags with tagBox before saving
+			if ( window.tagBox ) {
+				$( 'div.tagsdiv' ).each( function() {
+					window.tagBox.flushTags( this, false, 1 );
+				} );
+			}
+
+			var data = $form.serialize();
+
+			$.ajax( {
+				type: 'post',
+				url: window.ajaxurl,
+				data: data,
+				success: function( response ) {
+					if ( ! response.success ) {
+						renderError( response.data.errorMessage );
+						hideSpinner();
+					} else if ( response.data.redirect ) {
+						if ( window.opener && siteConfig.redir_in_parent ) {
+							try {
+								window.opener.location.href = response.data.redirect;
+							} catch( er ) {}
+
+							window.self.close();
+						} else {
+							window.location.href = response.data.redirect;
+						}
+					}
+				}
+			} );
+		}
+
+		/**
+		 * Inserts the media a user has selected from the presented list inside the editor, as an image or embed, based on type
+		 *
+		 * @param type string img|embed
+		 * @param src string Source URL
+		 * @param link string Optional destination link, for images (defaults to src)
+		 */
+		function insertSelectedMedia( type, src, link ) {
+			var newContent = '';
+
+			if ( ! editor ) {
+				return;
+			}
+
+			src = checkUrl( src );
+			link = checkUrl( link );
+
+			if ( 'img' === type ) {
+				if ( ! link || ! link.length ) {
+					link = src;
+				}
+
+				newContent = '<a href="' + link + '"><img class="alignnone size-full" src="' + src + '" /></a>\n';
+			} else {
+				newContent = '[embed]' + src + '[/embed]\n';
+			}
+
+			if ( ! hasSetFocus ) {
+				// Append to top of content on 1st media insert
+				editor.setContent( newContent + editor.getContent() );
+			} else {
+				// Or add where the cursor was last positioned in TinyMCE
+				editor.execCommand( 'mceInsertContent', false, newContent );
+			}
+
+			hasSetFocus = true;
+		}
+
+		/**
+		 * Adds the currently selected post format next to the option, in the options panel.
+		 *
+		 * @param format string Post format to be displayed
+		 */
+		function setPostFormatString( format ) {
+			if ( ! format || ! siteConfig || ! siteConfig.post_formats || ! siteConfig.post_formats[ format ] ) {
+				return;
+			}
+			$( '#post-option-post-format' ).text( siteConfig.post_formats[ format ] );
+		}
+
+		/**
+		 * Save a new user-generated category via AJAX
+		 */
+		function saveNewCategory() {
+			var data = {
+				action: 'press-this-add-category',
+				post_id: $( '#post_ID' ).val() || 0,
+				name: $( '#new-category' ).val() || '',
+				new_cat_nonce: $( '#_ajax_nonce-add-category' ).val() || '',
+				parent: $( '#new-category-parent' ).val() || 0
+			};
+
+			$.post( window.ajaxurl, data, function( response ) {
+				if ( ! response.success ) {
+					renderError( response.data.errorMessage );
+				} else {
+					// TODO: change if/when the html changes.
+					var $parent, $ul,
+						$wrap = $( 'ul.categories-select' );
+
+					$.each( response.data, function( i, newCat ) {
+						var $node = $( '<li>' ).attr( 'id', 'category-' + newCat.term_id )
+							.append( $( '<label class="selectit">' ).text( newCat.name )
+								.append( $( '<input type="checkbox" name="post_category[]" checked>' ).attr( 'value', newCat.term_id ) ) );
+
+						if ( newCat.parent ) {
+							if ( ! $ul || ! $ul.length ) {
+								$parent = $wrap.find( '#category-' + newCat.parent );
+								$ul = $parent.find( 'ul.children:first' );
+
+								if ( ! $ul.length ) {
+									$ul = $( '<ul class="children">' ).appendTo( $parent );
+								}
+							}
+
+							$ul.append( $node );
+							// TODO: set focus on
+						} else {
+							$wrap.prepend( $node );
+						}
+					} );
+
+					refreshCatsCache();
+				}
+			} );
+		}
+
+		/* ***************************************************************
+		 * RENDERING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Hide the form letting users enter a URL to be scanned, if a URL was already passed.
+		 */
+		function renderToolsVisibility() {
+			if ( data.u && data.u.match( /^https?:/ ) ) {
+				$( '#scanbar' ).hide();
+			}
+		}
+
+		/**
+		 * Render error notice
+		 *
+		 * @param msg string Notice/error message
+		 * @param error string error|notice CSS class for display
+		 */
+		function renderNotice( msg, error ) {
+			var $alerts = $( '.editor-wrapper div.alerts' ),
+				className = error ? 'is-error' : 'is-notice';
+
+			$alerts.append( $( '<p class="' + className + '">' ).text( msg ) );
+		}
+
+		/**
+		 * Render error notice
+		 *
+		 * @param msg string Error message
+		 */
+		function renderError( msg ) {
+			renderNotice( msg, true );
+		}
+
+		/**
+		 * Render notices on page load, if any already
+		 */
+		function renderStartupNotices() {
+			// Render errors sent in the data, if any
+			if ( data.errors && data.errors.length ) {
+				$.each( data.errors, function( i, msg ) {
+					renderError( msg );
+				} );
+			}
+
+			// Prompt user to upgrade their bookmarklet if there is a version mismatch.
+			if ( data.v && data._version && data.v !== data._version ) {
+				$( '.should-upgrade-bookmarklet' ).removeClass( 'is-hidden' );
+			}
+		}
+
+		/**
+		 * Render the suggested title, if any
+		 */
+		function renderSuggestedTitle() {
+			var suggestedTitle = suggestedTitleStr || '',
+				$title = $( '#title-container' );
+
+			if ( ! hasEmptyTitleStr ) {
+				$( '#title-field' ).val( suggestedTitle );
+				$title.text( suggestedTitle );
+				$( '.post-title-placeholder' ).addClass( 'is-hidden' );
+			}
+
+			$title.on( 'keyup', function() {
+				saveAlert = true;
+			}).on( 'paste', function() {
+				saveAlert = true;
+
+				setTimeout( function() {
+					$title.text( $title.text() );
+				}, 100 );
+			} );
+
+		}
+
+		/**
+		 * Render the suggested content, if any
+		 */
+		function renderSuggestedContent() {
+			if ( ! suggestedContentStr || ! suggestedContentStr.length ) {
+				return;
+			}
+
+			if ( ! editor ) {
+				editor = window.tinymce.get( 'pressthis' );
+			}
+
+			if ( editor ) {
+				editor.setContent( suggestedContentStr );
+				editor.on( 'focus', function() {
+					hasSetFocus = true;
+				} );
+			}
+
+		}
+
+		/**
+		 * Render the detected images and embed for selection, if any
+		 */
+		function renderDetectedMedia() {
+			var mediaContainer = $( '#featured-media-container'),
+				listContainer  = $( '#all-media-container' ),
+				found          = 0;
+
+			listContainer.empty();
+
+			if ( ( interestingEmbeds && interestingEmbeds.length ) || ( interestingImages && interestingImages.length ) ) {
+				listContainer.append( '<h2 class="screen-reader-text">' + __( 'allMediaHeading' ) + '</h2><ul class="wppt-all-media-list"/>' );
+			}
+
+			if ( interestingEmbeds && interestingEmbeds.length ) {
+				$.each( interestingEmbeds, function ( i, src ) {
+					src = checkUrl( src );
+
+					if ( ! isEmbeddable( src ) ) {
+						return;
+					}
+
+					var displaySrc = '',
+						cssClass   = 'suggested-media-thumbnail suggested-media-embed';
+
+					if ( src.indexOf( 'youtube.com/' ) > -1 ) {
+						displaySrc = 'https://i.ytimg.com/vi/' + src.replace( /.+v=([^&]+).*/, '$1' ) + '/hqdefault.jpg';
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'youtu.be/' ) > -1 ) {
+						displaySrc = 'https://i.ytimg.com/vi/' + src.replace( /\/([^\/])$/, '$1' ) + '/hqdefault.jpg';
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'dailymotion.com' ) > -1 ) {
+						displaySrc = src.replace( '/video/', '/thumbnail/video/' );
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'soundcloud.com' ) > -1 ) {
+						cssClass += ' is-audio';
+					} else if ( src.indexOf( 'twitter.com' ) > -1 ) {
+						cssClass += ' is-tweet';
+					} else {
+						cssClass += ' is-video';
+					}
+
+					$( '<li></li>', {
+						'id': 'embed-' + i + '-container',
+						'class': cssClass,
+						'tabindex': '0'
+					} ).css( {
+						'background-image': ( displaySrc.length ) ? 'url(' + displaySrc + ')' : null
+					} ).html(
+						'<span class="screen-reader-text">' + __( 'suggestedEmbedAlt' ).replace( '%d', i + 1 ) + '</span>'
+					).on( 'click keypress', function ( e ) {
+						if ( e.type === 'click' || e.which === 13 ) {
+							insertSelectedMedia( 'embed',src );
+						}
+					} ).appendTo( '.wppt-all-media-list', listContainer );
+
+					found++;
+				} );
+			}
+
+			if ( interestingImages && interestingImages.length ) {
+				$.each( interestingImages, function ( i, src ) {
+					src = checkUrl( src );
+
+					var displaySrc = src.replace(/^(http[^\?]+)(\?.*)?$/, '$1');
+					if ( src.indexOf( 'files.wordpress.com/' ) > -1 ) {
+						displaySrc = displaySrc.replace(/\?.*$/, '') + '?w=' + smallestWidth;
+					} else if ( src.indexOf( 'gravatar.com/' ) > -1 ) {
+						displaySrc = displaySrc.replace( /\?.*$/, '' ) + '?s=' + smallestWidth;
+					} else {
+						displaySrc = src;
+					}
+
+					$( '<li></li>', {
+						'id': 'img-' + i + '-container',
+						'class': 'suggested-media-thumbnail is-image',
+						'tabindex': '0'
+					} ).css( {
+						'background-image': 'url(' + displaySrc + ')'
+					} ).html(
+						'<span class="screen-reader-text">' +__( 'suggestedImgAlt' ).replace( '%d', i + 1 ) + '</span>'
+					).on( 'click keypress', function ( e ) {
+						if ( e.type === 'click' || e.which === 13 ) {
+							insertSelectedMedia( 'img', src, data.u );
+						}
+					} ).appendTo( '.wppt-all-media-list', listContainer );
+
+					found++;
+				} );
+			}
+
+			if ( ! found ) {
+				mediaContainer.removeClass( 'all-media-visible' ).addClass( 'no-media');
+				return;
+			}
+
+			mediaContainer.removeClass( 'no-media' ).addClass( 'all-media-visible' );
+		}
+
+		/* ***************************************************************
+		 * MONITORING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Interactive navigation behavior for the options modal (post format, tags, categories)
+		 */
+		function monitorOptionsModal() {
+			var isOffScreen   = 'is-off-screen',
+				isHidden      = 'is-hidden',
+				$postOptions  = $( '.post-options' ),
+				$postOption   = $( '.post-option' ),
+				$settingModal = $( '.setting-modal' ),
+				$modalClose   = $( '.modal-close' );
+
+			$postOption.on( 'click', function( event ) {
+				var index = $( this ).index(),
+					$targetSettingModal = $settingModal.eq( index );
+
+				event.preventDefault();
+
+				$postOptions
+					.addClass( isOffScreen )
+					.one( transitionEndEvent, function() {
+						$( this ).addClass( isHidden );
+					} );
+
+				$targetSettingModal
+					.removeClass( isOffScreen + ' ' + isHidden )
+					.one( transitionEndEvent, function() {
+						$( this ).find( $modalClose ).focus();
+					} );
+			} );
+
+			$modalClose.on( 'click', function( event ) {
+				var $targetSettingModal = $( this ).parent(),
+					index = $targetSettingModal.index();
+
+				event.preventDefault();
+
+				$postOptions
+					.removeClass( isOffScreen + ' ' + isHidden );
+
+				$targetSettingModal
+					.addClass( isOffScreen )
+					.one( transitionEndEvent, function() {
+						$( this ).addClass( isHidden );
+					} );
+
+				// For browser that don't support transitionend.
+				if ( ! transitionEndEvent ) {
+					setTimeout( function() {
+						$targetSettingModal.addClass( isHidden );
+					}, 350 );
+				}
+
+				$postOption.eq( index - 1 ).focus();
+			} );
+		}
+
+		/**
+		 * Interactive behavior for the sidebar toggle, to show the options modals
+		 */
+		function monitorSidebarToggle() {
+			var $optOpen  = $( '.options-open' ),
+				$optClose = $( '.options-close' ),
+				$postOption = $( '.post-option' ),
+				$sidebar = $( '.options-panel' ),
+				$postActions = $( '.press-this-actions' ),
+				$scanbar = $( '#scanbar' ),
+				isOffScreen = 'is-off-screen',
+				isHidden = 'is-hidden',
+				ifOffHidden = isOffScreen + ' ' + isHidden;
+
+			$optOpen.on( 'click', function(){
+				$optOpen.addClass( isHidden );
+				$optClose.removeClass( isHidden );
+				$postActions.addClass( isHidden );
+				$scanbar.addClass( isHidden );
+
+				$sidebar
+					.removeClass( ifOffHidden )
+					.one( 'transitionend', function() {
+						$postOption.eq( 0 ).focus();
+					} );
+			} );
+
+			$optClose.on( 'click', function(){
+				$optClose.addClass( isHidden );
+				$optOpen.removeClass( isHidden );
+				$postActions.removeClass( isHidden );
+				$scanbar.removeClass( isHidden );
+
+				$sidebar
+					.addClass( isOffScreen )
+					.one( 'transitionend', function() {
+						$( this ).addClass( isHidden );
+						// Reset to options list
+						$( '.post-options' ).removeClass( ifOffHidden );
+						$( '.setting-modal').addClass( ifOffHidden );
+					} );
+			} );
+		}
+
+		/**
+		 * Interactive behavior for the post title's field placeholder
+		 */
+		function monitorPlaceholder() {
+			var $selector = $( '#title-container'),
+				$placeholder = $('.post-title-placeholder');
+
+			$selector.on( 'focus', function() {
+				$placeholder.addClass('is-hidden');
+			} );
+
+			$selector.on( 'blur', function() {
+				var textLength = $( this ).text().length;
+
+				if ( ! textLength ) {
+					$placeholder.removeClass('is-hidden');
+				}
+			} );
+		}
+
+		/* ***************************************************************
+		 * PROCESSING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Calls all the rendring related functions to happen on page load
+		 */
+		function render(){
+			// We're on!
+			renderToolsVisibility();
+			renderSuggestedTitle();
+			renderDetectedMedia();
+			$( document ).on( 'tinymce-editor-init', renderSuggestedContent );
+			renderStartupNotices();
+		}
+
+		/**
+		 * Set app events and other state monitoring related code.
+		 */
+		function monitor(){
+			$( '#current-site a').click( function( e ) {
+				e.preventDefault();
+			} );
+
+			// Publish and Draft buttons and submit
+
+			$( '#draft-field' ).on( 'click', function() {
+				submitPost( 'draft' );
+			} );
+
+			$( '#publish-field' ).on( 'click', function() {
+				submitPost( 'publish' );
+			} );
+
+			monitorOptionsModal();
+			monitorSidebarToggle();
+			monitorPlaceholder();
+
+			$( '#post-formats-select input' ).on( 'change', function() {
+				var $this = $( this );
+
+				if ( $this.is( ':checked' ) ) {
+					setPostFormatString( $this.attr( 'id' ).replace( /^post-format-(.+)$/, '$1' ) );
+				}
+			} );
+
+			// Needs more work, doesn't detect when the other JS changes the value of #tax-input-post_tag
+			$( '#tax-input-post_tag' ).on( 'change', function() {
+				var val =  $( this ).val();
+				$( '#post-option-tags' ).text( ( val.length ) ? val.replace( /,([^\s])/g, ', $1' ) : '' );
+			} );
+
+			$( window ).on( 'beforeunload.press-this', function() {
+				if ( saveAlert || ( editor && editor.isDirty() ) ) {
+					return __( 'saveAlert' );
+				}
+			} );
+
+			$( 'button.add-cat-toggle' ).on( 'click.press-this', function() {
+				$( this ).toggleClass( 'is-toggled' );
+				$( '.setting-modal .add-category' ).toggleClass( 'is-hidden' );
+				$( '.categories-search-wrapper' ).toggleClass( 'is-hidden' );
+			} );
+
+			$( 'button.add-cat-submit' ).on( 'click.press-this', saveNewCategory );
+
+			$( '.categories-search' ).on( 'keyup', function() {
+				var search = $( this ).val().toLowerCase() || '';
+
+				// Don't search when less thasn 3 extended ASCII chars
+				if ( /[\x20-\xFF]+/.test( search ) && search.length < 2 ) {
+					return;
+				}
+
+				$.each( catsCache, function( i, cat ) {
+					cat.node.removeClass( 'is-hidden searched-parent' );
+				} );
+
+				if ( search ) {
+					$.each( catsCache, function( i, cat ) {
+						if ( cat.text.indexOf( search ) === -1 ) {
+							cat.node.addClass( 'is-hidden' );
+						} else {
+							cat.parents.addClass( 'searched-parent' );
+						}
+					} );
+				}
+			} );
+
+			return true;
+		}
+
+		function refreshCatsCache() {
+			$( '.categories-select' ).find( 'li' ).each( function() {
+				var $this = $( this );
+
+				catsCache.push( {
+					node: $this,
+					parents: $this.parents( 'li' ),
+					text: $this.children( 'label' ).text().toLowerCase()
+				} );
+			} );
+		}
+
+		// Let's go!
+		$( document ).ready( function() {
+			render();
+			monitor();
+			refreshCatsCache();
+		});
+
+		// Expose public methods
+		// TODO: which are needed?
+		return {
+			renderNotice: renderNotice,
+			renderError: renderError
+		};
+	}
+
+	window.wp = window.wp || {};
+	window.wp.pressThis = new PressThis();
+
+}( jQuery, window ));
+/**
+ * PressThis App
+ *
+ */
+( function( $, window ) {
+	var PressThis = function() {
+		var editor,
+			saveAlert             = false,
+			$div                  = $( '<div>' ),
+			siteConfig            = window.wpPressThisConfig || {},
+			data                  = window.wpPressThisData || {},
+			smallestWidth         = 128,
+			interestingImages	  = getInterestingImages( data ) || [],
+			interestingEmbeds	  = getInterestingEmbeds( data ) || [],
+			hasEmptyTitleStr      = false,
+			suggestedTitleStr     = getSuggestedTitle( data ),
+			suggestedContentStr   = getSuggestedContent( data ),
+			hasSetFocus           = false,
+			catsCache             = [],
+			transitionEndEvent    = ( function() {
+				var style = document.documentElement.style;
+
+				if ( typeof style.transition !== 'undefined' ) {
+					return 'transitionend';
+				}
+
+				if ( typeof style.WebkitTransition !== 'undefined' ) {
+					return 'webkitTransitionEnd';
+				}
+
+				return false;
+			}() );
+
+		/* ***************************************************************
+		 * HELPER FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Emulates our PHP __() gettext function, powered by the strings exported in pressThisL10n.
+		 *
+		 * @param key string Key of the string to be translated, as found in pressThisL10n.
+		 * @returns string Original or translated string, or empty string if no key.
+		 */
+		function __( key ) {
+			if ( key && window.pressThisL10n ) {
+				return window.pressThisL10n[key] || key;
+			}
+
+			return key || '';
+		}
+
+		/**
+		 * Strips HTML tags
+		 *
+		 * @param string string Text to have the HTML tags striped out of.
+		 * @returns string Stripped text.
+		 */
+		function stripTags( string ) {
+			string = string || '';
+
+			return string
+				.replace( /<!--[\s\S]*?(-->|$)/g, '' )
+				.replace( /<(script|style)[^>]*>[\s\S]*?(<\/\1>|$)/ig, '' )
+				.replace( /<\/?[a-z][^>]*>/ig, '' );
+		}
+
+		// TODO: needed?
+		function entityEncode( text ) {
+			return $div.text( text ).html();
+		}
+
+		/**
+		 * Strip HTML tags and entity encode some of the HTML special chars.
+		 *
+		 * @param text string Text.
+		 * @returns string Sanitized text.
+		 */
+		function sanitizeText( text ) {
+			text = stripTags( text );
+
+			return text
+				.replace( /\\/, '' )
+				.replace( /</g, '&lt;' )
+				.replace( />/g, '&gt;' )
+				.replace( /"/g, '&quot;' )
+				.replace( /'/g, '&#039;' );
+		}
+
+		/**
+		 * Allow only HTTP or protocol relative URLs.
+		 *
+		 * @param url string The URL.
+		 * @returns string Processed URL.
+		 */
+		function checkUrl( url ) {
+			url = $.trim( url || '' );
+
+			if ( /^(?:https?:)?\/\//.test( url ) ) {
+				url = stripTags( url );
+				return url.replace( /["\\]+/g, '' );
+			}
+
+			return '';
+		}
+
+		/**
+		 * Gets the source page's canonical link, based on passed location and meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered canonical URL, or empty
+		 */
+		function getCanonicalLink( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var link = '';
+
+			if ( data._links ) {
+				if ( data._links.canonical && data._links.canonical.length ) {
+					link = data._links.canonical;
+				}
+			}
+
+			if ( ! link.length && data.u ) {
+				link = data.u;
+			}
+
+			if ( ! link.length && data._meta ) {
+				if ( data._meta['twitter:url'] && data._meta['twitter:url'].length ) {
+					link = data._meta['twitter:url'];
+				} else if ( data._meta['og:url'] && data._meta['og:url'].length ) {
+					link = data._meta['og:url'];
+				}
+			}
+
+			return decodeURI( link );
+		}
+
+		/**
+		 * Gets the source page's site name, based on passed meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered site name, or empty
+		 */
+		function getSourceSiteName( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var name='';
+
+			if ( data._meta ) {
+				if ( data._meta['og:site_name'] && data._meta['og:site_name'].length ) {
+					name = data._meta['og:site_name'];
+				} else if ( data._meta['application-name'] && data._meta['application-name'].length ) {
+					name = data._meta['application-name'];
+				}
+			}
+
+			return name.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Gets the source page's title, based on passed title and meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered page title, or empty
+		 */
+		function getSuggestedTitle( data ) {
+			if ( ! data || data.length ) {
+				return __( 'newPost' );
+			}
+
+			var title = '';
+
+			if ( data.t ) {
+				title = data.t;
+			}
+
+			if ( ! title.length && data._meta ) {
+				if ( data._meta['twitter:title'] && data._meta['twitter:title'].length ) {
+					title = data._meta['twitter:title'];
+				} else if ( data._meta['og:title'] && data._meta['og:title'].length ) {
+					title = data._meta['og:title'];
+				} else if ( data._meta.title && data._meta.title.length ) {
+					title = data._meta.title;
+				}
+			}
+
+			if ( ! title.length ) {
+				title = __( 'newPost' );
+				hasEmptyTitleStr = true;
+			}
+
+			return title.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Gets the source page's suggested content, based on passed data (description, selection, etc).
+		 * Features a blockquoted excerpt, as well as content attribution, if any.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered content, or empty
+		 */
+		function getSuggestedContent( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var content   = '',
+				title     = getSuggestedTitle( data ),
+				url       = getCanonicalLink( data ),
+				siteName  = getSourceSiteName( data );
+
+			if ( data.s && data.s.length ) {
+				content = data.s;
+			} else if ( data._meta ) {
+				if ( data._meta['twitter:description'] && data._meta['twitter:description'].length ) {
+					content = data._meta['twitter:description'];
+				} else if ( data._meta['og:description'] && data._meta['og:description'].length ) {
+					content = data._meta['og:description'];
+				} else if ( data._meta.description && data._meta.description.length ) {
+					content = data._meta.description;
+				}
+			}
+
+			// Wrap suggested content in blockquote tag, if we have any.
+			content = ( content.length ? '<blockquote class="press-this-suggested-content">' + sanitizeText( content ) + '</blockquote>' : '' );
+
+			// Add a source attribution if there is one available.
+			if ( ( ( title.length && __( 'newPost' ) !== title ) || siteName.length ) && url.length ) {
+				content += '<p class="press-this-suggested-source">';
+				content += __( 'source' );
+				content += ' <cite>';
+				content += __( 'sourceLink').replace( '%1$s', encodeURI( url ) ).replace( '%2$s', sanitizeText( title || siteName ) );
+				content += '</cite></p>';
+			}
+
+			if ( ! content ) {
+				content = '';
+			}
+
+			return content.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Tests if what was passed as an embed URL is deemed to be embeddable in the editor.
+		 *
+		 * @param url string Passed URl, usually from WpPressThis_App.data._embed
+		 * @returns boolean
+		 */
+		function isEmbeddable( url ) {
+			if ( ! url ) {
+				return false;
+			} else if ( url.match( /\/\/(m\.|www\.)?youtube\.com\/watch\?/ ) || url.match( /\/youtu\.be\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/vimeo\.com\/(.+\/)?[\d]+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/soundcloud\.com\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
+				return true;
+			}
+
+			return false;
+		}
+
+		/**
+		 * Tests if what was passed as an image URL is deemed to be interesting enough to offer to the user for selection.
+		 *
+		 * @param src string Passed URl, usually from WpPressThis_App.data._ing
+		 * @returns boolean Test for false
+		 */
+		function isSrcUninterestingPath( src ) {
+			if ( src.match( /\/ad[sx]{1}?\// ) ) {
+				// Ads
+				return true;
+			} else if ( src.match( /(\/share-?this[^\.]+?\.[a-z0-9]{3,4})(\?.*)?$/ ) ) {
+				// Share-this type button
+				return true;
+			} else if ( src.match( /\/(spinner|loading|spacer|blank|rss)\.(gif|jpg|png)/ ) ) {
+				// Loaders, spinners, spacers
+				return true;
+			} else if ( src.match( /\/([^\.\/]+[-_]{1})?(spinner|loading|spacer|blank)s?([-_]{1}[^\.\/]+)?\.[a-z0-9]{3,4}/ ) ) {
+				// Fancy loaders, spinners, spacers
+				return true;
+			} else if ( src.match( /([^\.\/]+[-_]{1})?thumb[^.]*\.(gif|jpg|png)$/ ) ) {
+				// Thumbnails, too small, usually irrelevant to context
+				return true;
+			} else if ( src.match( /\/wp-includes\// ) ) {
+				// Classic WP interface images
+				return true;
+			} else if ( src.match( /[^\d]{1}\d{1,2}x\d+\.(gif|jpg|png)$/ ) ) {
+				// Most often tiny buttons/thumbs (< 100px wide)
+				return true;
+			} else if ( src.indexOf( '/g.gif' ) > -1 ) {
+				// Classic WP stats gif
+				return true;
+			} else if ( src.indexOf( '/pixel.mathtag.com' ) > -1 ) {
+				// See mathtag.com
+				return true;
+			}
+			return false;
+		}
+
+		/**
+		 * Get a list of valid embeds from what was passed via WpPressThis_App.data._embed on page load.
+		 *
+		 * @returns array
+		 */
+		function getInterestingEmbeds() {
+			var embeds             = data._embed || [],
+				interestingEmbeds  = [],
+				alreadySelected    = [];
+
+			if ( embeds.length ) {
+				$.each( embeds, function ( i, src ) {
+					if ( !src || !src.length ) {
+						// Skip: no src value
+						return;
+					} else if ( !isEmbeddable( src ) ) {
+						// Skip: not deemed embeddable
+						return;
+					}
+
+					var schemelessSrc = src.replace( /^https?:/, '' );
+
+					if ( $.inArray( schemelessSrc, alreadySelected ) > -1 ) {
+						// Skip: already shown
+						return;
+					}
+
+					interestingEmbeds.push( src );
+					alreadySelected.push( schemelessSrc );
+				} );
+			}
+
+			return interestingEmbeds;
+		}
+
+		/**
+		 * Get what is likely the most valuable image from what was passed via WpPressThis_App.data._img and WpPressThis_App.data._meta on page load.
+		 *
+		 * @returns array
+		 */
+		function getFeaturedImage( data ) {
+			var featured = '';
+
+			if ( ! data || ! data._meta ) {
+				return '';
+			}
+
+			if ( data._meta['twitter:image0:src'] && data._meta['twitter:image0:src'].length ) {
+				featured = data._meta['twitter:image0:src'];
+			} else if ( data._meta['twitter:image0'] && data._meta['twitter:image0'].length ) {
+				featured = data._meta['twitter:image0'];
+			} else if ( data._meta['twitter:image:src'] && data._meta['twitter:image:src'].length ) {
+				featured = data._meta['twitter:image:src'];
+			} else if ( data._meta['twitter:image'] && data._meta['twitter:image'].length ) {
+				featured = data._meta['twitter:image'];
+			} else if ( data._meta['og:image'] && data._meta['og:image'].length ) {
+				featured = data._meta['og:image'];
+			} else if ( data._meta['og:image:secure_url'] && data._meta['og:image:secure_url'].length ) {
+				featured = data._meta['og:image:secure_url'];
+			}
+
+			featured = checkUrl( featured );
+
+			return ( isSrcUninterestingPath( featured ) ) ? '' : featured;
+		}
+
+		/**
+		 * Get a list of valid images from what was passed via WpPressThis_App.data._img and WpPressThis_App.data._meta on page load.
+		 *
+		 * @returns array
+		 */
+		function getInterestingImages( data ) {
+			var imgs             = data._img || [],
+				featuredPict     = getFeaturedImage( data ) || '',
+				interestingImgs  = [],
+				alreadySelected  = [];
+
+			if ( featuredPict.length ) {
+				interestingImgs.push( featuredPict );
+				alreadySelected.push( featuredPict.replace(/^https?:/, '') );
+			}
+
+			if ( imgs.length ) {
+				$.each( imgs, function ( i, src ) {
+					src = src.replace( /http:\/\/[\d]+\.gravatar\.com\//, 'https://secure.gravatar.com/' );
+					src = checkUrl( src );
+
+					if ( ! src || ! src.length ) {
+						// Skip: no src value
+						return;
+					}
+
+					var schemelessSrc = src.replace( /^https?:/, '' );
+
+					if ( Array.prototype.indexOf && alreadySelected.indexOf( schemelessSrc ) > -1 ) {
+						// Skip: already shown
+						return;
+					} else if ( isSrcUninterestingPath( src ) ) {
+						// Skip: spinner, stat, ad, or spacer pict
+						return;
+					} else if ( src.indexOf( 'avatar' ) > -1 && interestingImgs.length >= 15 ) {
+						// Skip:  some type of avatar and we've already gathered more than 23 diff images to show
+						return;
+					}
+
+					interestingImgs.push( src );
+					alreadySelected.push( schemelessSrc );
+				} );
+			}
+
+			return interestingImgs;
+		}
+
+		/**
+		 * Show UX spinner
+		 */
+		function showSpinner() {
+			$( '#spinner' ).addClass( 'show' );
+			$( '.post-actions button' ).each( function() {
+				$( this ).attr( 'disabled', 'disabled' );
+			} );
+		}
+
+		/**
+		 * Hide UX spinner
+		 */
+		function hideSpinner() {
+			$( '#spinner' ).removeClass( 'show' );
+			$( '.post-actions button' ).each( function() {
+				$( this ).removeAttr( 'disabled' );
+			} );
+		}
+
+		/**
+		 * Submit the post form via AJAX, and redirect to the proper screen if published vs saved as a draft.
+		 *
+		 * @param action string publish|draft
+		 */
+		function submitPost( action ) {
+			saveAlert = false;
+			showSpinner();
+
+			var $form = $( '#pressthis-form' );
+
+			if ( 'publish' === action ) {
+				$( '#post_status' ).val( 'publish' );
+			}
+
+			editor && editor.save();
+
+			$( '#title-field' ).val( sanitizeText( $( '#title-container' ).text() ) );
+
+			// Make sure to flush out the tags with tagBox before saving
+			if ( window.tagBox ) {
+				$( 'div.tagsdiv' ).each( function() {
+					window.tagBox.flushTags( this, false, 1 );
+				} );
+			}
+
+			var data = $form.serialize();
+
+			$.ajax( {
+				type: 'post',
+				url: window.ajaxurl,
+				data: data,
+				success: function( response ) {
+					if ( ! response.success ) {
+						renderError( response.data.errorMessage );
+						hideSpinner();
+					} else if ( response.data.redirect ) {
+						if ( window.opener && siteConfig.redir_in_parent ) {
+							try {
+								window.opener.location.href = response.data.redirect;
+							} catch( er ) {}
+
+							window.self.close();
+						} else {
+							window.location.href = response.data.redirect;
+						}
+					}
+				}
+			} );
+		}
+
+		/**
+		 * Inserts the media a user has selected from the presented list inside the editor, as an image or embed, based on type
+		 *
+		 * @param type string img|embed
+		 * @param src string Source URL
+		 * @param link string Optional destination link, for images (defaults to src)
+		 */
+		function insertSelectedMedia( type, src, link ) {
+			var newContent = '';
+
+			if ( ! editor ) {
+				return;
+			}
+
+			src = checkUrl( src );
+			link = checkUrl( link );
+
+			if ( 'img' === type ) {
+				if ( ! link || ! link.length ) {
+					link = src;
+				}
+
+				newContent = '<a href="' + link + '"><img class="alignnone size-full" src="' + src + '" /></a>\n';
+			} else {
+				newContent = '[embed]' + src + '[/embed]\n';
+			}
+
+			if ( ! hasSetFocus ) {
+				// Append to top of content on 1st media insert
+				editor.setContent( newContent + editor.getContent() );
+			} else {
+				// Or add where the cursor was last positioned in TinyMCE
+				editor.execCommand( 'mceInsertContent', false, newContent );
+			}
+
+			hasSetFocus = true;
+		}
+
+		/**
+		 * Adds the currently selected post format next to the option, in the options panel.
+		 *
+		 * @param format string Post format to be displayed
+		 */
+		function setPostFormatString( format ) {
+			if ( ! format || ! siteConfig || ! siteConfig.post_formats || ! siteConfig.post_formats[ format ] ) {
+				return;
+			}
+			$( '#post-option-post-format' ).text( siteConfig.post_formats[ format ] );
+		}
+
+		/**
+		 * Save a new user-generated category via AJAX
+		 */
+		function saveNewCategory() {
+			var data = {
+				action: 'press-this-add-category',
+				post_id: $( '#post_ID' ).val() || 0,
+				name: $( '#new-category' ).val() || '',
+				new_cat_nonce: $( '#_ajax_nonce-add-category' ).val() || '',
+				parent: $( '#new-category-parent' ).val() || 0
+			};
+
+			$.post( window.ajaxurl, data, function( response ) {
+				if ( ! response.success ) {
+					renderError( response.data.errorMessage );
+				} else {
+					// TODO: change if/when the html changes.
+					var $parent, $ul,
+						$wrap = $( 'ul.categories-select' );
+
+					$.each( response.data, function( i, newCat ) {
+						var $node = $( '<li>' ).attr( 'id', 'category-' + newCat.term_id )
+							.append( $( '<label class="selectit">' ).text( newCat.name )
+								.append( $( '<input type="checkbox" name="post_category[]" checked>' ).attr( 'value', newCat.term_id ) ) );
+
+						if ( newCat.parent ) {
+							if ( ! $ul || ! $ul.length ) {
+								$parent = $wrap.find( '#category-' + newCat.parent );
+								$ul = $parent.find( 'ul.children:first' );
+
+								if ( ! $ul.length ) {
+									$ul = $( '<ul class="children">' ).appendTo( $parent );
+								}
+							}
+
+							$ul.append( $node );
+							// TODO: set focus on
+						} else {
+							$wrap.prepend( $node );
+						}
+					} );
+
+					refreshCatsCache();
+				}
+			} );
+		}
+
+		/* ***************************************************************
+		 * RENDERING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Hide the form letting users enter a URL to be scanned, if a URL was already passed.
+		 */
+		function renderToolsVisibility() {
+			if ( data.u && data.u.match( /^https?:/ ) ) {
+				$( '#scanbar' ).hide();
+			}
+		}
+
+		/**
+		 * Render error notice
+		 *
+		 * @param msg string Notice/error message
+		 * @param error string error|notice CSS class for display
+		 */
+		function renderNotice( msg, error ) {
+			var $alerts = $( '.editor-wrapper div.alerts' ),
+				className = error ? 'is-error' : 'is-notice';
+
+			$alerts.append( $( '<p class="' + className + '">' ).text( msg ) );
+		}
+
+		/**
+		 * Render error notice
+		 *
+		 * @param msg string Error message
+		 */
+		function renderError( msg ) {
+			renderNotice( msg, true );
+		}
+
+		/**
+		 * Render notices on page load, if any already
+		 */
+		function renderStartupNotices() {
+			// Render errors sent in the data, if any
+			if ( data.errors && data.errors.length ) {
+				$.each( data.errors, function( i, msg ) {
+					renderError( msg );
+				} );
+			}
+
+			// Prompt user to upgrade their bookmarklet if there is a version mismatch.
+			if ( data.v && data._version && data.v !== data._version ) {
+				$( '.should-upgrade-bookmarklet' ).removeClass( 'is-hidden' );
+			}
+		}
+
+		/**
+		 * Render the suggested title, if any
+		 */
+		function renderSuggestedTitle() {
+			var suggestedTitle = suggestedTitleStr || '',
+				$title = $( '#title-container' );
+
+			if ( ! hasEmptyTitleStr ) {
+				$( '#title-field' ).val( suggestedTitle );
+				$title.text( suggestedTitle );
+				$( '.post-title-placeholder' ).addClass( 'is-hidden' );
+			}
+
+			$title.on( 'keyup', function() {
+				saveAlert = true;
+			}).on( 'paste', function() {
+				saveAlert = true;
+
+				setTimeout( function() {
+					$title.text( $title.text() );
+				}, 100 );
+			} );
+
+		}
+
+		/**
+		 * Render the suggested content, if any
+		 */
+		function renderSuggestedContent() {
+			if ( ! suggestedContentStr || ! suggestedContentStr.length ) {
+				return;
+			}
+
+			if ( ! editor ) {
+				editor = window.tinymce.get( 'pressthis' );
+			}
+
+			if ( editor ) {
+				editor.setContent( suggestedContentStr );
+				editor.on( 'focus', function() {
+					hasSetFocus = true;
+				} );
+			}
+
+		}
+
+		/**
+		 * Render the detected images and embed for selection, if any
+		 */
+		function renderDetectedMedia() {
+			var mediaContainer = $( '#featured-media-container'),
+				listContainer  = $( '#all-media-container' ),
+				found          = 0;
+
+			listContainer.empty();
+
+			if ( ( interestingEmbeds && interestingEmbeds.length ) || ( interestingImages && interestingImages.length ) ) {
+				listContainer.append( '<h2 class="screen-reader-text">' + __( 'allMediaHeading' ) + '</h2><ul class="wppt-all-media-list"/>' );
+			}
+
+			if ( interestingEmbeds && interestingEmbeds.length ) {
+				$.each( interestingEmbeds, function ( i, src ) {
+					src = checkUrl( src );
+
+					if ( ! isEmbeddable( src ) ) {
+						return;
+					}
+
+					var displaySrc = '',
+						cssClass   = 'suggested-media-thumbnail suggested-media-embed';
+
+					if ( src.indexOf( 'youtube.com/' ) > -1 ) {
+						displaySrc = 'https://i.ytimg.com/vi/' + src.replace( /.+v=([^&]+).*/, '$1' ) + '/hqdefault.jpg';
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'youtu.be/' ) > -1 ) {
+						displaySrc = 'https://i.ytimg.com/vi/' + src.replace( /\/([^\/])$/, '$1' ) + '/hqdefault.jpg';
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'dailymotion.com' ) > -1 ) {
+						displaySrc = src.replace( '/video/', '/thumbnail/video/' );
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'soundcloud.com' ) > -1 ) {
+						cssClass += ' is-audio';
+					} else if ( src.indexOf( 'twitter.com' ) > -1 ) {
+						cssClass += ' is-tweet';
+					} else {
+						cssClass += ' is-video';
+					}
+
+					$( '<li></li>', {
+						'id': 'embed-' + i + '-container',
+						'class': cssClass,
+						'tabindex': '0'
+					} ).css( {
+						'background-image': ( displaySrc.length ) ? 'url(' + displaySrc + ')' : null
+					} ).html(
+						'<span class="screen-reader-text">' + __( 'suggestedEmbedAlt' ).replace( '%d', i + 1 ) + '</span>'
+					).on( 'click keypress', function ( e ) {
+						if ( e.type === 'click' || e.which === 13 ) {
+							insertSelectedMedia( 'embed',src );
+						}
+					} ).appendTo( '.wppt-all-media-list', listContainer );
+
+					found++;
+				} );
+			}
+
+			if ( interestingImages && interestingImages.length ) {
+				$.each( interestingImages, function ( i, src ) {
+					src = checkUrl( src );
+
+					var displaySrc = src.replace(/^(http[^\?]+)(\?.*)?$/, '$1');
+					if ( src.indexOf( 'files.wordpress.com/' ) > -1 ) {
+						displaySrc = displaySrc.replace(/\?.*$/, '') + '?w=' + smallestWidth;
+					} else if ( src.indexOf( 'gravatar.com/' ) > -1 ) {
+						displaySrc = displaySrc.replace( /\?.*$/, '' ) + '?s=' + smallestWidth;
+					} else {
+						displaySrc = src;
+					}
+
+					$( '<li></li>', {
+						'id': 'img-' + i + '-container',
+						'class': 'suggested-media-thumbnail is-image',
+						'tabindex': '0'
+					} ).css( {
+						'background-image': 'url(' + displaySrc + ')'
+					} ).html(
+						'<span class="screen-reader-text">' +__( 'suggestedImgAlt' ).replace( '%d', i + 1 ) + '</span>'
+					).on( 'click keypress', function ( e ) {
+						if ( e.type === 'click' || e.which === 13 ) {
+							insertSelectedMedia( 'img', src, data.u );
+						}
+					} ).appendTo( '.wppt-all-media-list', listContainer );
+
+					found++;
+				} );
+			}
+
+			if ( ! found ) {
+				mediaContainer.removeClass( 'all-media-visible' ).addClass( 'no-media');
+				return;
+			}
+
+			mediaContainer.removeClass( 'no-media' ).addClass( 'all-media-visible' );
+		}
+
+		/* ***************************************************************
+		 * MONITORING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Interactive navigation behavior for the options modal (post format, tags, categories)
+		 */
+		function monitorOptionsModal() {
+			var isOffScreen   = 'is-off-screen',
+				isHidden      = 'is-hidden',
+				$postOptions  = $( '.post-options' ),
+				$postOption   = $( '.post-option' ),
+				$settingModal = $( '.setting-modal' ),
+				$modalClose   = $( '.modal-close' );
+
+			$postOption.on( 'click', function( event ) {
+				var index = $( this ).index(),
+					$targetSettingModal = $settingModal.eq( index );
+
+				event.preventDefault();
+
+				$postOptions
+					.addClass( isOffScreen )
+					.one( transitionEndEvent, function() {
+						$( this ).addClass( isHidden );
+					} );
+
+				$targetSettingModal
+					.removeClass( isOffScreen + ' ' + isHidden )
+					.one( transitionEndEvent, function() {
+						$( this ).find( $modalClose ).focus();
+					} );
+			} );
+
+			$modalClose.on( 'click', function( event ) {
+				var $targetSettingModal = $( this ).parent(),
+					index = $targetSettingModal.index();
+
+				event.preventDefault();
+
+				$postOptions
+					.removeClass( isOffScreen + ' ' + isHidden );
+
+				$targetSettingModal
+					.addClass( isOffScreen )
+					.one( transitionEndEvent, function() {
+						$( this ).addClass( isHidden );
+					} );
+
+				// For browser that don't support transitionend.
+				if ( ! transitionEndEvent ) {
+					setTimeout( function() {
+						$targetSettingModal.addClass( isHidden );
+					}, 350 );
+				}
+
+				$postOption.eq( index - 1 ).focus();
+			} );
+		}
+
+		/**
+		 * Interactive behavior for the sidebar toggle, to show the options modals
+		 */
+		function monitorSidebarToggle() {
+			var $optOpen  = $( '.options-open' ),
+				$optClose = $( '.options-close' ),
+				$postOption = $( '.post-option' ),
+				$sidebar = $( '.options-panel' ),
+				$postActions = $( '.press-this-actions' ),
+				$scanbar = $( '#scanbar' ),
+				isOffScreen = 'is-off-screen',
+				isHidden = 'is-hidden',
+				ifOffHidden = isOffScreen + ' ' + isHidden;
+
+			$optOpen.on( 'click', function(){
+				$optOpen.addClass( isHidden );
+				$optClose.removeClass( isHidden );
+				$postActions.addClass( isHidden );
+				$scanbar.addClass( isHidden );
+
+				$sidebar
+					.removeClass( ifOffHidden )
+					.one( 'transitionend', function() {
+						$postOption.eq( 0 ).focus();
+					} );
+			} );
+
+			$optClose.on( 'click', function(){
+				$optClose.addClass( isHidden );
+				$optOpen.removeClass( isHidden );
+				$postActions.removeClass( isHidden );
+				$scanbar.removeClass( isHidden );
+
+				$sidebar
+					.addClass( isOffScreen )
+					.one( 'transitionend', function() {
+						$( this ).addClass( isHidden );
+						// Reset to options list
+						$( '.post-options' ).removeClass( ifOffHidden );
+						$( '.setting-modal').addClass( ifOffHidden );
+					} );
+			} );
+		}
+
+		/**
+		 * Interactive behavior for the post title's field placeholder
+		 */
+		function monitorPlaceholder() {
+			var $selector = $( '#title-container'),
+				$placeholder = $('.post-title-placeholder');
+
+			$selector.on( 'focus', function() {
+				$placeholder.addClass('is-hidden');
+			} );
+
+			$selector.on( 'blur', function() {
+				var textLength = $( this ).text().length;
+
+				if ( ! textLength ) {
+					$placeholder.removeClass('is-hidden');
+				}
+			} );
+		}
+
+		/* ***************************************************************
+		 * PROCESSING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Calls all the rendring related functions to happen on page load
+		 */
+		function render(){
+			// We're on!
+			renderToolsVisibility();
+			renderSuggestedTitle();
+			renderDetectedMedia();
+			$( document ).on( 'tinymce-editor-init', renderSuggestedContent );
+			renderStartupNotices();
+		}
+
+		/**
+		 * Set app events and other state monitoring related code.
+		 */
+		function monitor(){
+			$( '#current-site a').click( function( e ) {
+				e.preventDefault();
+			} );
+
+			// Publish and Draft buttons and submit
+
+			$( '#draft-field' ).on( 'click', function() {
+				submitPost( 'draft' );
+			} );
+
+			$( '#publish-field' ).on( 'click', function() {
+				submitPost( 'publish' );
+			} );
+
+			monitorOptionsModal();
+			monitorSidebarToggle();
+			monitorPlaceholder();
+
+			$( '#post-formats-select input' ).on( 'change', function() {
+				var $this = $( this );
+
+				if ( $this.is( ':checked' ) ) {
+					setPostFormatString( $this.attr( 'id' ).replace( /^post-format-(.+)$/, '$1' ) );
+				}
+			} );
+
+			// Needs more work, doesn't detect when the other JS changes the value of #tax-input-post_tag
+			$( '#tax-input-post_tag' ).on( 'change', function() {
+				var val =  $( this ).val();
+				$( '#post-option-tags' ).text( ( val.length ) ? val.replace( /,([^\s])/g, ', $1' ) : '' );
+			} );
+
+			$( window ).on( 'beforeunload.press-this', function() {
+				if ( saveAlert || ( editor && editor.isDirty() ) ) {
+					return __( 'saveAlert' );
+				}
+			} );
+
+			$( 'button.add-cat-toggle' ).on( 'click.press-this', function() {
+				$( this ).toggleClass( 'is-toggled' );
+				$( '.setting-modal .add-category' ).toggleClass( 'is-hidden' );
+				$( '.categories-search-wrapper' ).toggleClass( 'is-hidden' );
+			} );
+
+			$( 'button.add-cat-submit' ).on( 'click.press-this', saveNewCategory );
+
+			$( '.categories-search' ).on( 'keyup', function() {
+				var search = $( this ).val().toLowerCase() || '';
+
+				// Don't search when less thasn 3 extended ASCII chars
+				if ( /[\x20-\xFF]+/.test( search ) && search.length < 2 ) {
+					return;
+				}
+
+				$.each( catsCache, function( i, cat ) {
+					cat.node.removeClass( 'is-hidden searched-parent' );
+				} );
+
+				if ( search ) {
+					$.each( catsCache, function( i, cat ) {
+						if ( cat.text.indexOf( search ) === -1 ) {
+							cat.node.addClass( 'is-hidden' );
+						} else {
+							cat.parents.addClass( 'searched-parent' );
+						}
+					} );
+				}
+			} );
+
+			return true;
+		}
+
+		function refreshCatsCache() {
+			$( '.categories-select' ).find( 'li' ).each( function() {
+				var $this = $( this );
+
+				catsCache.push( {
+					node: $this,
+					parents: $this.parents( 'li' ),
+					text: $this.children( 'label' ).text().toLowerCase()
+				} );
+			} );
+		}
+
+		// Let's go!
+		$( document ).ready( function() {
+			render();
+			monitor();
+			refreshCatsCache();
+		});
+
+		// Expose public methods
+		// TODO: which are needed?
+		return {
+			renderNotice: renderNotice,
+			renderError: renderError
+		};
+	}
+
+	window.wp = window.wp || {};
+	window.wp.pressThis = new PressThis();
+
+}( jQuery, window ));
+/**
+ * PressThis App
+ *
+ */
+( function( $, window ) {
+	var PressThis = function() {
+		var editor,
+			saveAlert             = false,
+			$div                  = $( '<div>' ),
+			siteConfig            = window.wpPressThisConfig || {},
+			data                  = window.wpPressThisData || {},
+			smallestWidth         = 128,
+			interestingImages	  = getInterestingImages( data ) || [],
+			interestingEmbeds	  = getInterestingEmbeds( data ) || [],
+			hasEmptyTitleStr      = false,
+			suggestedTitleStr     = getSuggestedTitle( data ),
+			suggestedContentStr   = getSuggestedContent( data ),
+			hasSetFocus           = false,
+			catsCache             = [],
+			transitionEndEvent    = ( function() {
+				var style = document.documentElement.style;
+
+				if ( typeof style.transition !== 'undefined' ) {
+					return 'transitionend';
+				}
+
+				if ( typeof style.WebkitTransition !== 'undefined' ) {
+					return 'webkitTransitionEnd';
+				}
+
+				return false;
+			}() );
+
+		/* ***************************************************************
+		 * HELPER FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Emulates our PHP __() gettext function, powered by the strings exported in pressThisL10n.
+		 *
+		 * @param key string Key of the string to be translated, as found in pressThisL10n.
+		 * @returns string Original or translated string, or empty string if no key.
+		 */
+		function __( key ) {
+			if ( key && window.pressThisL10n ) {
+				return window.pressThisL10n[key] || key;
+			}
+
+			return key || '';
+		}
+
+		/**
+		 * Strips HTML tags
+		 *
+		 * @param string string Text to have the HTML tags striped out of.
+		 * @returns string Stripped text.
+		 */
+		function stripTags( string ) {
+			string = string || '';
+
+			return string
+				.replace( /<!--[\s\S]*?(-->|$)/g, '' )
+				.replace( /<(script|style)[^>]*>[\s\S]*?(<\/\1>|$)/ig, '' )
+				.replace( /<\/?[a-z][^>]*>/ig, '' );
+		}
+
+		// TODO: needed?
+		function entityEncode( text ) {
+			return $div.text( text ).html();
+		}
+
+		/**
+		 * Strip HTML tags and entity encode some of the HTML special chars.
+		 *
+		 * @param text string Text.
+		 * @returns string Sanitized text.
+		 */
+		function sanitizeText( text ) {
+			text = stripTags( text );
+
+			return text
+				.replace( /\\/, '' )
+				.replace( /</g, '&lt;' )
+				.replace( />/g, '&gt;' )
+				.replace( /"/g, '&quot;' )
+				.replace( /'/g, '&#039;' );
+		}
+
+		/**
+		 * Allow only HTTP or protocol relative URLs.
+		 *
+		 * @param url string The URL.
+		 * @returns string Processed URL.
+		 */
+		function checkUrl( url ) {
+			url = $.trim( url || '' );
+
+			if ( /^(?:https?:)?\/\//.test( url ) ) {
+				url = stripTags( url );
+				return url.replace( /["\\]+/g, '' );
+			}
+
+			return '';
+		}
+
+		/**
+		 * Gets the source page's canonical link, based on passed location and meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered canonical URL, or empty
+		 */
+		function getCanonicalLink( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var link = '';
+
+			if ( data._links ) {
+				if ( data._links.canonical && data._links.canonical.length ) {
+					link = data._links.canonical;
+				}
+			}
+
+			if ( ! link.length && data.u ) {
+				link = data.u;
+			}
+
+			if ( ! link.length && data._meta ) {
+				if ( data._meta['twitter:url'] && data._meta['twitter:url'].length ) {
+					link = data._meta['twitter:url'];
+				} else if ( data._meta['og:url'] && data._meta['og:url'].length ) {
+					link = data._meta['og:url'];
+				}
+			}
+
+			return decodeURI( link );
+		}
+
+		/**
+		 * Gets the source page's site name, based on passed meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered site name, or empty
+		 */
+		function getSourceSiteName( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var name='';
+
+			if ( data._meta ) {
+				if ( data._meta['og:site_name'] && data._meta['og:site_name'].length ) {
+					name = data._meta['og:site_name'];
+				} else if ( data._meta['application-name'] && data._meta['application-name'].length ) {
+					name = data._meta['application-name'];
+				}
+			}
+
+			return name.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Gets the source page's title, based on passed title and meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered page title, or empty
+		 */
+		function getSuggestedTitle( data ) {
+			if ( ! data || data.length ) {
+				return __( 'newPost' );
+			}
+
+			var title = '';
+
+			if ( data.t ) {
+				title = data.t;
+			}
+
+			if ( ! title.length && data._meta ) {
+				if ( data._meta['twitter:title'] && data._meta['twitter:title'].length ) {
+					title = data._meta['twitter:title'];
+				} else if ( data._meta['og:title'] && data._meta['og:title'].length ) {
+					title = data._meta['og:title'];
+				} else if ( data._meta.title && data._meta.title.length ) {
+					title = data._meta.title;
+				}
+			}
+
+			if ( ! title.length ) {
+				title = __( 'newPost' );
+				hasEmptyTitleStr = true;
+			}
+
+			return title.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Gets the source page's suggested content, based on passed data (description, selection, etc).
+		 * Features a blockquoted excerpt, as well as content attribution, if any.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered content, or empty
+		 */
+		function getSuggestedContent( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var content   = '',
+				title     = getSuggestedTitle( data ),
+				url       = getCanonicalLink( data ),
+				siteName  = getSourceSiteName( data );
+
+			if ( data.s && data.s.length ) {
+				content = data.s;
+			} else if ( data._meta ) {
+				if ( data._meta['twitter:description'] && data._meta['twitter:description'].length ) {
+					content = data._meta['twitter:description'];
+				} else if ( data._meta['og:description'] && data._meta['og:description'].length ) {
+					content = data._meta['og:description'];
+				} else if ( data._meta.description && data._meta.description.length ) {
+					content = data._meta.description;
+				}
+			}
+
+			// Wrap suggested content in blockquote tag, if we have any.
+			content = ( content.length ? '<blockquote class="press-this-suggested-content">' + sanitizeText( content ) + '</blockquote>' : '' );
+
+			// Add a source attribution if there is one available.
+			if ( ( ( title.length && __( 'newPost' ) !== title ) || siteName.length ) && url.length ) {
+				content += '<p class="press-this-suggested-source">';
+				content += __( 'source' );
+				content += ' <cite>';
+				content += __( 'sourceLink').replace( '%1$s', encodeURI( url ) ).replace( '%2$s', sanitizeText( title || siteName ) );
+				content += '</cite></p>';
+			}
+
+			if ( ! content ) {
+				content = '';
+			}
+
+			return content.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Tests if what was passed as an embed URL is deemed to be embeddable in the editor.
+		 *
+		 * @param url string Passed URl, usually from WpPressThis_App.data._embed
+		 * @returns boolean
+		 */
+		function isEmbeddable( url ) {
+			if ( ! url ) {
+				return false;
+			} else if ( url.match( /\/\/(m\.|www\.)?youtube\.com\/watch\?/ ) || url.match( /\/youtu\.be\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/vimeo\.com\/(.+\/)?[\d]+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/soundcloud\.com\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
+				return true;
+			}
+
+			return false;
+		}
+
+		/**
+		 * Tests if what was passed as an image URL is deemed to be interesting enough to offer to the user for selection.
+		 *
+		 * @param src string Passed URl, usually from WpPressThis_App.data._ing
+		 * @returns boolean Test for false
+		 */
+		function isSrcUninterestingPath( src ) {
+			if ( src.match( /\/ad[sx]{1}?\// ) ) {
+				// Ads
+				return true;
+			} else if ( src.match( /(\/share-?this[^\.]+?\.[a-z0-9]{3,4})(\?.*)?$/ ) ) {
+				// Share-this type button
+				return true;
+			} else if ( src.match( /\/(spinner|loading|spacer|blank|rss)\.(gif|jpg|png)/ ) ) {
+				// Loaders, spinners, spacers
+				return true;
+			} else if ( src.match( /\/([^\.\/]+[-_]{1})?(spinner|loading|spacer|blank)s?([-_]{1}[^\.\/]+)?\.[a-z0-9]{3,4}/ ) ) {
+				// Fancy loaders, spinners, spacers
+				return true;
+			} else if ( src.match( /([^\.\/]+[-_]{1})?thumb[^.]*\.(gif|jpg|png)$/ ) ) {
+				// Thumbnails, too small, usually irrelevant to context
+				return true;
+			} else if ( src.match( /\/wp-includes\// ) ) {
+				// Classic WP interface images
+				return true;
+			} else if ( src.match( /[^\d]{1}\d{1,2}x\d+\.(gif|jpg|png)$/ ) ) {
+				// Most often tiny buttons/thumbs (< 100px wide)
+				return true;
+			} else if ( src.indexOf( '/g.gif' ) > -1 ) {
+				// Classic WP stats gif
+				return true;
+			} else if ( src.indexOf( '/pixel.mathtag.com' ) > -1 ) {
+				// See mathtag.com
+				return true;
+			}
+			return false;
+		}
+
+		/**
+		 * Get a list of valid embeds from what was passed via WpPressThis_App.data._embed on page load.
+		 *
+		 * @returns array
+		 */
+		function getInterestingEmbeds() {
+			var embeds             = data._embed || [],
+				interestingEmbeds  = [],
+				alreadySelected    = [];
+
+			if ( embeds.length ) {
+				$.each( embeds, function ( i, src ) {
+					if ( !src || !src.length ) {
+						// Skip: no src value
+						return;
+					} else if ( !isEmbeddable( src ) ) {
+						// Skip: not deemed embeddable
+						return;
+					}
+
+					var schemelessSrc = src.replace( /^https?:/, '' );
+
+					if ( $.inArray( schemelessSrc, alreadySelected ) > -1 ) {
+						// Skip: already shown
+						return;
+					}
+
+					interestingEmbeds.push( src );
+					alreadySelected.push( schemelessSrc );
+				} );
+			}
+
+			return interestingEmbeds;
+		}
+
+		/**
+		 * Get what is likely the most valuable image from what was passed via WpPressThis_App.data._img and WpPressThis_App.data._meta on page load.
+		 *
+		 * @returns array
+		 */
+		function getFeaturedImage( data ) {
+			var featured = '';
+
+			if ( ! data || ! data._meta ) {
+				return '';
+			}
+
+			if ( data._meta['twitter:image0:src'] && data._meta['twitter:image0:src'].length ) {
+				featured = data._meta['twitter:image0:src'];
+			} else if ( data._meta['twitter:image0'] && data._meta['twitter:image0'].length ) {
+				featured = data._meta['twitter:image0'];
+			} else if ( data._meta['twitter:image:src'] && data._meta['twitter:image:src'].length ) {
+				featured = data._meta['twitter:image:src'];
+			} else if ( data._meta['twitter:image'] && data._meta['twitter:image'].length ) {
+				featured = data._meta['twitter:image'];
+			} else if ( data._meta['og:image'] && data._meta['og:image'].length ) {
+				featured = data._meta['og:image'];
+			} else if ( data._meta['og:image:secure_url'] && data._meta['og:image:secure_url'].length ) {
+				featured = data._meta['og:image:secure_url'];
+			}
+
+			featured = checkUrl( featured );
+
+			return ( isSrcUninterestingPath( featured ) ) ? '' : featured;
+		}
+
+		/**
+		 * Get a list of valid images from what was passed via WpPressThis_App.data._img and WpPressThis_App.data._meta on page load.
+		 *
+		 * @returns array
+		 */
+		function getInterestingImages( data ) {
+			var imgs             = data._img || [],
+				featuredPict     = getFeaturedImage( data ) || '',
+				interestingImgs  = [],
+				alreadySelected  = [];
+
+			if ( featuredPict.length ) {
+				interestingImgs.push( featuredPict );
+				alreadySelected.push( featuredPict.replace(/^https?:/, '') );
+			}
+
+			if ( imgs.length ) {
+				$.each( imgs, function ( i, src ) {
+					src = src.replace( /http:\/\/[\d]+\.gravatar\.com\//, 'https://secure.gravatar.com/' );
+					src = checkUrl( src );
+
+					if ( ! src || ! src.length ) {
+						// Skip: no src value
+						return;
+					}
+
+					var schemelessSrc = src.replace( /^https?:/, '' );
+
+					if ( Array.prototype.indexOf && alreadySelected.indexOf( schemelessSrc ) > -1 ) {
+						// Skip: already shown
+						return;
+					} else if ( isSrcUninterestingPath( src ) ) {
+						// Skip: spinner, stat, ad, or spacer pict
+						return;
+					} else if ( src.indexOf( 'avatar' ) > -1 && interestingImgs.length >= 15 ) {
+						// Skip:  some type of avatar and we've already gathered more than 23 diff images to show
+						return;
+					}
+
+					interestingImgs.push( src );
+					alreadySelected.push( schemelessSrc );
+				} );
+			}
+
+			return interestingImgs;
+		}
+
+		/**
+		 * Show UX spinner
+		 */
+		function showSpinner() {
+			$( '#spinner' ).addClass( 'show' );
+			$( '.post-actions button' ).each( function() {
+				$( this ).attr( 'disabled', 'disabled' );
+			} );
+		}
+
+		/**
+		 * Hide UX spinner
+		 */
+		function hideSpinner() {
+			$( '#spinner' ).removeClass( 'show' );
+			$( '.post-actions button' ).each( function() {
+				$( this ).removeAttr( 'disabled' );
+			} );
+		}
+
+		/**
+		 * Submit the post form via AJAX, and redirect to the proper screen if published vs saved as a draft.
+		 *
+		 * @param action string publish|draft
+		 */
+		function submitPost( action ) {
+			saveAlert = false;
+			showSpinner();
+
+			var $form = $( '#pressthis-form' );
+
+			if ( 'publish' === action ) {
+				$( '#post_status' ).val( 'publish' );
+			}
+
+			editor && editor.save();
+
+			$( '#title-field' ).val( sanitizeText( $( '#title-container' ).text() ) );
+
+			// Make sure to flush out the tags with tagBox before saving
+			if ( window.tagBox ) {
+				$( 'div.tagsdiv' ).each( function() {
+					window.tagBox.flushTags( this, false, 1 );
+				} );
+			}
+
+			var data = $form.serialize();
+
+			$.ajax( {
+				type: 'post',
+				url: window.ajaxurl,
+				data: data,
+				success: function( response ) {
+					if ( ! response.success ) {
+						renderError( response.data.errorMessage );
+						hideSpinner();
+					} else if ( response.data.redirect ) {
+						if ( window.opener && siteConfig.redir_in_parent ) {
+							try {
+								window.opener.location.href = response.data.redirect;
+							} catch( er ) {}
+
+							window.self.close();
+						} else {
+							window.location.href = response.data.redirect;
+						}
+					}
+				}
+			} );
+		}
+
+		/**
+		 * Inserts the media a user has selected from the presented list inside the editor, as an image or embed, based on type
+		 *
+		 * @param type string img|embed
+		 * @param src string Source URL
+		 * @param link string Optional destination link, for images (defaults to src)
+		 */
+		function insertSelectedMedia( type, src, link ) {
+			var newContent = '';
+
+			if ( ! editor ) {
+				return;
+			}
+
+			src = checkUrl( src );
+			link = checkUrl( link );
+
+			if ( 'img' === type ) {
+				if ( ! link || ! link.length ) {
+					link = src;
+				}
+
+				newContent = '<a href="' + link + '"><img class="alignnone size-full" src="' + src + '" /></a>\n';
+			} else {
+				newContent = '[embed]' + src + '[/embed]\n';
+			}
+
+			if ( ! hasSetFocus ) {
+				// Append to top of content on 1st media insert
+				editor.setContent( newContent + editor.getContent() );
+			} else {
+				// Or add where the cursor was last positioned in TinyMCE
+				editor.execCommand( 'mceInsertContent', false, newContent );
+			}
+
+			hasSetFocus = true;
+		}
+
+		/**
+		 * Adds the currently selected post format next to the option, in the options panel.
+		 *
+		 * @param format string Post format to be displayed
+		 */
+		function setPostFormatString( format ) {
+			if ( ! format || ! siteConfig || ! siteConfig.post_formats || ! siteConfig.post_formats[ format ] ) {
+				return;
+			}
+			$( '#post-option-post-format' ).text( siteConfig.post_formats[ format ] );
+		}
+
+		/**
+		 * Save a new user-generated category via AJAX
+		 */
+		function saveNewCategory() {
+			var data = {
+				action: 'press-this-add-category',
+				post_id: $( '#post_ID' ).val() || 0,
+				name: $( '#new-category' ).val() || '',
+				new_cat_nonce: $( '#_ajax_nonce-add-category' ).val() || '',
+				parent: $( '#new-category-parent' ).val() || 0
+			};
+
+			$.post( window.ajaxurl, data, function( response ) {
+				if ( ! response.success ) {
+					renderError( response.data.errorMessage );
+				} else {
+					// TODO: change if/when the html changes.
+					var $parent, $ul,
+						$wrap = $( 'ul.categories-select' );
+
+					$.each( response.data, function( i, newCat ) {
+						var $node = $( '<li>' ).attr( 'id', 'category-' + newCat.term_id )
+							.append( $( '<label class="selectit">' ).text( newCat.name )
+								.append( $( '<input type="checkbox" name="post_category[]" checked>' ).attr( 'value', newCat.term_id ) ) );
+
+						if ( newCat.parent ) {
+							if ( ! $ul || ! $ul.length ) {
+								$parent = $wrap.find( '#category-' + newCat.parent );
+								$ul = $parent.find( 'ul.children:first' );
+
+								if ( ! $ul.length ) {
+									$ul = $( '<ul class="children">' ).appendTo( $parent );
+								}
+							}
+
+							$ul.append( $node );
+							// TODO: set focus on
+						} else {
+							$wrap.prepend( $node );
+						}
+					} );
+
+					refreshCatsCache();
+				}
+			} );
+		}
+
+		/* ***************************************************************
+		 * RENDERING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Hide the form letting users enter a URL to be scanned, if a URL was already passed.
+		 */
+		function renderToolsVisibility() {
+			if ( data.u && data.u.match( /^https?:/ ) ) {
+				$( '#scanbar' ).hide();
+			}
+		}
+
+		/**
+		 * Render error notice
+		 *
+		 * @param msg string Notice/error message
+		 * @param error string error|notice CSS class for display
+		 */
+		function renderNotice( msg, error ) {
+			var $alerts = $( '.editor-wrapper div.alerts' ),
+				className = error ? 'is-error' : 'is-notice';
+
+			$alerts.append( $( '<p class="' + className + '">' ).text( msg ) );
+		}
+
+		/**
+		 * Render error notice
+		 *
+		 * @param msg string Error message
+		 */
+		function renderError( msg ) {
+			renderNotice( msg, true );
+		}
+
+		/**
+		 * Render notices on page load, if any already
+		 */
+		function renderStartupNotices() {
+			// Render errors sent in the data, if any
+			if ( data.errors && data.errors.length ) {
+				$.each( data.errors, function( i, msg ) {
+					renderError( msg );
+				} );
+			}
+
+			// Prompt user to upgrade their bookmarklet if there is a version mismatch.
+			if ( data.v && data._version && data.v !== data._version ) {
+				$( '.should-upgrade-bookmarklet' ).removeClass( 'is-hidden' );
+			}
+		}
+
+		/**
+		 * Render the suggested title, if any
+		 */
+		function renderSuggestedTitle() {
+			var suggestedTitle = suggestedTitleStr || '',
+				$title = $( '#title-container' );
+
+			if ( ! hasEmptyTitleStr ) {
+				$( '#title-field' ).val( suggestedTitle );
+				$title.text( suggestedTitle );
+				$( '.post-title-placeholder' ).addClass( 'is-hidden' );
+			}
+
+			$title.on( 'keyup', function() {
+				saveAlert = true;
+			}).on( 'paste', function() {
+				saveAlert = true;
+
+				setTimeout( function() {
+					$title.text( $title.text() );
+				}, 100 );
+			} );
+
+		}
+
+		/**
+		 * Render the suggested content, if any
+		 */
+		function renderSuggestedContent() {
+			if ( ! suggestedContentStr || ! suggestedContentStr.length ) {
+				return;
+			}
+
+			if ( ! editor ) {
+				editor = window.tinymce.get( 'pressthis' );
+			}
+
+			if ( editor ) {
+				editor.setContent( suggestedContentStr );
+				editor.on( 'focus', function() {
+					hasSetFocus = true;
+				} );
+			}
+
+		}
+
+		/**
+		 * Render the detected images and embed for selection, if any
+		 */
+		function renderDetectedMedia() {
+			var mediaContainer = $( '#featured-media-container'),
+				listContainer  = $( '#all-media-container' ),
+				found          = 0;
+
+			listContainer.empty();
+
+			if ( ( interestingEmbeds && interestingEmbeds.length ) || ( interestingImages && interestingImages.length ) ) {
+				listContainer.append( '<h2 class="screen-reader-text">' + __( 'allMediaHeading' ) + '</h2><ul class="wppt-all-media-list"/>' );
+			}
+
+			if ( interestingEmbeds && interestingEmbeds.length ) {
+				$.each( interestingEmbeds, function ( i, src ) {
+					src = checkUrl( src );
+
+					if ( ! isEmbeddable( src ) ) {
+						return;
+					}
+
+					var displaySrc = '',
+						cssClass   = 'suggested-media-thumbnail suggested-media-embed';
+
+					if ( src.indexOf( 'youtube.com/' ) > -1 ) {
+						displaySrc = 'https://i.ytimg.com/vi/' + src.replace( /.+v=([^&]+).*/, '$1' ) + '/hqdefault.jpg';
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'youtu.be/' ) > -1 ) {
+						displaySrc = 'https://i.ytimg.com/vi/' + src.replace( /\/([^\/])$/, '$1' ) + '/hqdefault.jpg';
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'dailymotion.com' ) > -1 ) {
+						displaySrc = src.replace( '/video/', '/thumbnail/video/' );
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'soundcloud.com' ) > -1 ) {
+						cssClass += ' is-audio';
+					} else if ( src.indexOf( 'twitter.com' ) > -1 ) {
+						cssClass += ' is-tweet';
+					} else {
+						cssClass += ' is-video';
+					}
+
+					$( '<li></li>', {
+						'id': 'embed-' + i + '-container',
+						'class': cssClass,
+						'tabindex': '0'
+					} ).css( {
+						'background-image': ( displaySrc.length ) ? 'url(' + displaySrc + ')' : null
+					} ).html(
+						'<span class="screen-reader-text">' + __( 'suggestedEmbedAlt' ).replace( '%d', i + 1 ) + '</span>'
+					).on( 'click keypress', function ( e ) {
+						if ( e.type === 'click' || e.which === 13 ) {
+							insertSelectedMedia( 'embed',src );
+						}
+					} ).appendTo( '.wppt-all-media-list', listContainer );
+
+					found++;
+				} );
+			}
+
+			if ( interestingImages && interestingImages.length ) {
+				$.each( interestingImages, function ( i, src ) {
+					src = checkUrl( src );
+
+					var displaySrc = src.replace(/^(http[^\?]+)(\?.*)?$/, '$1');
+					if ( src.indexOf( 'files.wordpress.com/' ) > -1 ) {
+						displaySrc = displaySrc.replace(/\?.*$/, '') + '?w=' + smallestWidth;
+					} else if ( src.indexOf( 'gravatar.com/' ) > -1 ) {
+						displaySrc = displaySrc.replace( /\?.*$/, '' ) + '?s=' + smallestWidth;
+					} else {
+						displaySrc = src;
+					}
+
+					$( '<li></li>', {
+						'id': 'img-' + i + '-container',
+						'class': 'suggested-media-thumbnail is-image',
+						'tabindex': '0'
+					} ).css( {
+						'background-image': 'url(' + displaySrc + ')'
+					} ).html(
+						'<span class="screen-reader-text">' +__( 'suggestedImgAlt' ).replace( '%d', i + 1 ) + '</span>'
+					).on( 'click keypress', function ( e ) {
+						if ( e.type === 'click' || e.which === 13 ) {
+							insertSelectedMedia( 'img', src, data.u );
+						}
+					} ).appendTo( '.wppt-all-media-list', listContainer );
+
+					found++;
+				} );
+			}
+
+			if ( ! found ) {
+				mediaContainer.removeClass( 'all-media-visible' ).addClass( 'no-media');
+				return;
+			}
+
+			mediaContainer.removeClass( 'no-media' ).addClass( 'all-media-visible' );
+		}
+
+		/* ***************************************************************
+		 * MONITORING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Interactive navigation behavior for the options modal (post format, tags, categories)
+		 */
+		function monitorOptionsModal() {
+			var isOffScreen   = 'is-off-screen',
+				isHidden      = 'is-hidden',
+				$postOptions  = $( '.post-options' ),
+				$postOption   = $( '.post-option' ),
+				$settingModal = $( '.setting-modal' ),
+				$modalClose   = $( '.modal-close' );
+
+			$postOption.on( 'click', function( event ) {
+				var index = $( this ).index(),
+					$targetSettingModal = $settingModal.eq( index );
+
+				event.preventDefault();
+
+				$postOptions
+					.addClass( isOffScreen )
+					.one( transitionEndEvent, function() {
+						$( this ).addClass( isHidden );
+					} );
+
+				$targetSettingModal
+					.removeClass( isOffScreen + ' ' + isHidden )
+					.one( transitionEndEvent, function() {
+						$( this ).find( $modalClose ).focus();
+					} );
+			} );
+
+			$modalClose.on( 'click', function( event ) {
+				var $targetSettingModal = $( this ).parent(),
+					index = $targetSettingModal.index();
+
+				event.preventDefault();
+
+				$postOptions
+					.removeClass( isOffScreen + ' ' + isHidden );
+
+				$targetSettingModal
+					.addClass( isOffScreen )
+					.one( transitionEndEvent, function() {
+						$( this ).addClass( isHidden );
+					} );
+
+				// For browser that don't support transitionend.
+				if ( ! transitionEndEvent ) {
+					setTimeout( function() {
+						$targetSettingModal.addClass( isHidden );
+					}, 350 );
+				}
+
+				$postOption.eq( index - 1 ).focus();
+			} );
+		}
+
+		/**
+		 * Interactive behavior for the sidebar toggle, to show the options modals
+		 */
+		function monitorSidebarToggle() {
+			var $optOpen  = $( '.options-open' ),
+				$optClose = $( '.options-close' ),
+				$postOption = $( '.post-option' ),
+				$sidebar = $( '.options-panel' ),
+				$postActions = $( '.press-this-actions' ),
+				$scanbar = $( '#scanbar' ),
+				isOffScreen = 'is-off-screen',
+				isHidden = 'is-hidden',
+				ifOffHidden = isOffScreen + ' ' + isHidden;
+
+			$optOpen.on( 'click', function(){
+				$optOpen.addClass( isHidden );
+				$optClose.removeClass( isHidden );
+				$postActions.addClass( isHidden );
+				$scanbar.addClass( isHidden );
+
+				$sidebar
+					.removeClass( ifOffHidden )
+					.one( 'transitionend', function() {
+						$postOption.eq( 0 ).focus();
+					} );
+			} );
+
+			$optClose.on( 'click', function(){
+				$optClose.addClass( isHidden );
+				$optOpen.removeClass( isHidden );
+				$postActions.removeClass( isHidden );
+				$scanbar.removeClass( isHidden );
+
+				$sidebar
+					.addClass( isOffScreen )
+					.one( 'transitionend', function() {
+						$( this ).addClass( isHidden );
+						// Reset to options list
+						$( '.post-options' ).removeClass( ifOffHidden );
+						$( '.setting-modal').addClass( ifOffHidden );
+					} );
+			} );
+		}
+
+		/**
+		 * Interactive behavior for the post title's field placeholder
+		 */
+		function monitorPlaceholder() {
+			var $selector = $( '#title-container'),
+				$placeholder = $('.post-title-placeholder');
+
+			$selector.on( 'focus', function() {
+				$placeholder.addClass('is-hidden');
+			} );
+
+			$selector.on( 'blur', function() {
+				var textLength = $( this ).text().length;
+
+				if ( ! textLength ) {
+					$placeholder.removeClass('is-hidden');
+				}
+			} );
+		}
+
+		/* ***************************************************************
+		 * PROCESSING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Calls all the rendring related functions to happen on page load
+		 */
+		function render(){
+			// We're on!
+			renderToolsVisibility();
+			renderSuggestedTitle();
+			renderDetectedMedia();
+			$( document ).on( 'tinymce-editor-init', renderSuggestedContent );
+			renderStartupNotices();
+		}
+
+		/**
+		 * Set app events and other state monitoring related code.
+		 */
+		function monitor(){
+			$( '#current-site a').click( function( e ) {
+				e.preventDefault();
+			} );
+
+			// Publish and Draft buttons and submit
+
+			$( '#draft-field' ).on( 'click', function() {
+				submitPost( 'draft' );
+			} );
+
+			$( '#publish-field' ).on( 'click', function() {
+				submitPost( 'publish' );
+			} );
+
+			monitorOptionsModal();
+			monitorSidebarToggle();
+			monitorPlaceholder();
+
+			$( '#post-formats-select input' ).on( 'change', function() {
+				var $this = $( this );
+
+				if ( $this.is( ':checked' ) ) {
+					setPostFormatString( $this.attr( 'id' ).replace( /^post-format-(.+)$/, '$1' ) );
+				}
+			} );
+
+			// Needs more work, doesn't detect when the other JS changes the value of #tax-input-post_tag
+			$( '#tax-input-post_tag' ).on( 'change', function() {
+				var val =  $( this ).val();
+				$( '#post-option-tags' ).text( ( val.length ) ? val.replace( /,([^\s])/g, ', $1' ) : '' );
+			} );
+
+			$( window ).on( 'beforeunload.press-this', function() {
+				if ( saveAlert || ( editor && editor.isDirty() ) ) {
+					return __( 'saveAlert' );
+				}
+			} );
+
+			$( 'button.add-cat-toggle' ).on( 'click.press-this', function() {
+				$( this ).toggleClass( 'is-toggled' );
+				$( '.setting-modal .add-category' ).toggleClass( 'is-hidden' );
+				$( '.categories-search-wrapper' ).toggleClass( 'is-hidden' );
+			} );
+
+			$( 'button.add-cat-submit' ).on( 'click.press-this', saveNewCategory );
+
+			$( '.categories-search' ).on( 'keyup', function() {
+				var search = $( this ).val().toLowerCase() || '';
+
+				// Don't search when less thasn 3 extended ASCII chars
+				if ( /[\x20-\xFF]+/.test( search ) && search.length < 2 ) {
+					return;
+				}
+
+				$.each( catsCache, function( i, cat ) {
+					cat.node.removeClass( 'is-hidden searched-parent' );
+				} );
+
+				if ( search ) {
+					$.each( catsCache, function( i, cat ) {
+						if ( cat.text.indexOf( search ) === -1 ) {
+							cat.node.addClass( 'is-hidden' );
+						} else {
+							cat.parents.addClass( 'searched-parent' );
+						}
+					} );
+				}
+			} );
+
+			return true;
+		}
+
+		function refreshCatsCache() {
+			$( '.categories-select' ).find( 'li' ).each( function() {
+				var $this = $( this );
+
+				catsCache.push( {
+					node: $this,
+					parents: $this.parents( 'li' ),
+					text: $this.children( 'label' ).text().toLowerCase()
+				} );
+			} );
+		}
+
+		// Let's go!
+		$( document ).ready( function() {
+			render();
+			monitor();
+			refreshCatsCache();
+		});
+
+		// Expose public methods
+		// TODO: which are needed?
+		return {
+			renderNotice: renderNotice,
+			renderError: renderError
+		};
+	}
+
+	window.wp = window.wp || {};
+	window.wp.pressThis = new PressThis();
+
+}( jQuery, window ));
+/**
+ * PressThis App
+ *
+ */
+( function( $, window ) {
+	var PressThis = function() {
+		var editor,
+			saveAlert             = false,
+			$div                  = $( '<div>' ),
+			siteConfig            = window.wpPressThisConfig || {},
+			data                  = window.wpPressThisData || {},
+			smallestWidth         = 128,
+			interestingImages	  = getInterestingImages( data ) || [],
+			interestingEmbeds	  = getInterestingEmbeds( data ) || [],
+			hasEmptyTitleStr      = false,
+			suggestedTitleStr     = getSuggestedTitle( data ),
+			suggestedContentStr   = getSuggestedContent( data ),
+			hasSetFocus           = false,
+			catsCache             = [],
+			transitionEndEvent    = ( function() {
+				var style = document.documentElement.style;
+
+				if ( typeof style.transition !== 'undefined' ) {
+					return 'transitionend';
+				}
+
+				if ( typeof style.WebkitTransition !== 'undefined' ) {
+					return 'webkitTransitionEnd';
+				}
+
+				return false;
+			}() );
+
+		/* ***************************************************************
+		 * HELPER FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Emulates our PHP __() gettext function, powered by the strings exported in pressThisL10n.
+		 *
+		 * @param key string Key of the string to be translated, as found in pressThisL10n.
+		 * @returns string Original or translated string, or empty string if no key.
+		 */
+		function __( key ) {
+			if ( key && window.pressThisL10n ) {
+				return window.pressThisL10n[key] || key;
+			}
+
+			return key || '';
+		}
+
+		/**
+		 * Strips HTML tags
+		 *
+		 * @param string string Text to have the HTML tags striped out of.
+		 * @returns string Stripped text.
+		 */
+		function stripTags( string ) {
+			string = string || '';
+
+			return string
+				.replace( /<!--[\s\S]*?(-->|$)/g, '' )
+				.replace( /<(script|style)[^>]*>[\s\S]*?(<\/\1>|$)/ig, '' )
+				.replace( /<\/?[a-z][^>]*>/ig, '' );
+		}
+
+		// TODO: needed?
+		function entityEncode( text ) {
+			return $div.text( text ).html();
+		}
+
+		/**
+		 * Strip HTML tags and entity encode some of the HTML special chars.
+		 *
+		 * @param text string Text.
+		 * @returns string Sanitized text.
+		 */
+		function sanitizeText( text ) {
+			text = stripTags( text );
+
+			return text
+				.replace( /\\/, '' )
+				.replace( /</g, '&lt;' )
+				.replace( />/g, '&gt;' )
+				.replace( /"/g, '&quot;' )
+				.replace( /'/g, '&#039;' );
+		}
+
+		/**
+		 * Allow only HTTP or protocol relative URLs.
+		 *
+		 * @param url string The URL.
+		 * @returns string Processed URL.
+		 */
+		function checkUrl( url ) {
+			url = $.trim( url || '' );
+
+			if ( /^(?:https?:)?\/\//.test( url ) ) {
+				url = stripTags( url );
+				return url.replace( /["\\]+/g, '' );
+			}
+
+			return '';
+		}
+
+		/**
+		 * Gets the source page's canonical link, based on passed location and meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered canonical URL, or empty
+		 */
+		function getCanonicalLink( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var link = '';
+
+			if ( data._links ) {
+				if ( data._links.canonical && data._links.canonical.length ) {
+					link = data._links.canonical;
+				}
+			}
+
+			if ( ! link.length && data.u ) {
+				link = data.u;
+			}
+
+			if ( ! link.length && data._meta ) {
+				if ( data._meta['twitter:url'] && data._meta['twitter:url'].length ) {
+					link = data._meta['twitter:url'];
+				} else if ( data._meta['og:url'] && data._meta['og:url'].length ) {
+					link = data._meta['og:url'];
+				}
+			}
+
+			return decodeURI( link );
+		}
+
+		/**
+		 * Gets the source page's site name, based on passed meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered site name, or empty
+		 */
+		function getSourceSiteName( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var name='';
+
+			if ( data._meta ) {
+				if ( data._meta['og:site_name'] && data._meta['og:site_name'].length ) {
+					name = data._meta['og:site_name'];
+				} else if ( data._meta['application-name'] && data._meta['application-name'].length ) {
+					name = data._meta['application-name'];
+				}
+			}
+
+			return name.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Gets the source page's title, based on passed title and meta data.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered page title, or empty
+		 */
+		function getSuggestedTitle( data ) {
+			if ( ! data || data.length ) {
+				return __( 'newPost' );
+			}
+
+			var title = '';
+
+			if ( data.t ) {
+				title = data.t;
+			}
+
+			if ( ! title.length && data._meta ) {
+				if ( data._meta['twitter:title'] && data._meta['twitter:title'].length ) {
+					title = data._meta['twitter:title'];
+				} else if ( data._meta['og:title'] && data._meta['og:title'].length ) {
+					title = data._meta['og:title'];
+				} else if ( data._meta.title && data._meta.title.length ) {
+					title = data._meta.title;
+				}
+			}
+
+			if ( ! title.length ) {
+				title = __( 'newPost' );
+				hasEmptyTitleStr = true;
+			}
+
+			return title.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Gets the source page's suggested content, based on passed data (description, selection, etc).
+		 * Features a blockquoted excerpt, as well as content attribution, if any.
+		 *
+		 * @param data object Usually WpPressThis_App.data
+		 * @returns string Discovered content, or empty
+		 */
+		function getSuggestedContent( data ) {
+			if ( ! data || data.length ) {
+				return '';
+			}
+
+			var content   = '',
+				title     = getSuggestedTitle( data ),
+				url       = getCanonicalLink( data ),
+				siteName  = getSourceSiteName( data );
+
+			if ( data.s && data.s.length ) {
+				content = data.s;
+			} else if ( data._meta ) {
+				if ( data._meta['twitter:description'] && data._meta['twitter:description'].length ) {
+					content = data._meta['twitter:description'];
+				} else if ( data._meta['og:description'] && data._meta['og:description'].length ) {
+					content = data._meta['og:description'];
+				} else if ( data._meta.description && data._meta.description.length ) {
+					content = data._meta.description;
+				}
+			}
+
+			// Wrap suggested content in blockquote tag, if we have any.
+			content = ( content.length ? '<blockquote class="press-this-suggested-content">' + sanitizeText( content ) + '</blockquote>' : '' );
+
+			// Add a source attribution if there is one available.
+			if ( ( ( title.length && __( 'newPost' ) !== title ) || siteName.length ) && url.length ) {
+				content += '<p class="press-this-suggested-source">';
+				content += __( 'source' );
+				content += ' <cite>';
+				content += __( 'sourceLink').replace( '%1$s', encodeURI( url ) ).replace( '%2$s', sanitizeText( title || siteName ) );
+				content += '</cite></p>';
+			}
+
+			if ( ! content ) {
+				content = '';
+			}
+
+			return content.replace( /\\/g, '' );
+		}
+
+		/**
+		 * Tests if what was passed as an embed URL is deemed to be embeddable in the editor.
+		 *
+		 * @param url string Passed URl, usually from WpPressThis_App.data._embed
+		 * @returns boolean
+		 */
+		function isEmbeddable( url ) {
+			if ( ! url ) {
+				return false;
+			} else if ( url.match( /\/\/(m\.|www\.)?youtube\.com\/watch\?/ ) || url.match( /\/youtu\.be\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/vimeo\.com\/(.+\/)?[\d]+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/soundcloud\.com\/.+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
+				return true;
+			} else if ( url.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
+				return true;
+			}
+
+			return false;
+		}
+
+		/**
+		 * Tests if what was passed as an image URL is deemed to be interesting enough to offer to the user for selection.
+		 *
+		 * @param src string Passed URl, usually from WpPressThis_App.data._ing
+		 * @returns boolean Test for false
+		 */
+		function isSrcUninterestingPath( src ) {
+			if ( src.match( /\/ad[sx]{1}?\// ) ) {
+				// Ads
+				return true;
+			} else if ( src.match( /(\/share-?this[^\.]+?\.[a-z0-9]{3,4})(\?.*)?$/ ) ) {
+				// Share-this type button
+				return true;
+			} else if ( src.match( /\/(spinner|loading|spacer|blank|rss)\.(gif|jpg|png)/ ) ) {
+				// Loaders, spinners, spacers
+				return true;
+			} else if ( src.match( /\/([^\.\/]+[-_]{1})?(spinner|loading|spacer|blank)s?([-_]{1}[^\.\/]+)?\.[a-z0-9]{3,4}/ ) ) {
+				// Fancy loaders, spinners, spacers
+				return true;
+			} else if ( src.match( /([^\.\/]+[-_]{1})?thumb[^.]*\.(gif|jpg|png)$/ ) ) {
+				// Thumbnails, too small, usually irrelevant to context
+				return true;
+			} else if ( src.match( /\/wp-includes\// ) ) {
+				// Classic WP interface images
+				return true;
+			} else if ( src.match( /[^\d]{1}\d{1,2}x\d+\.(gif|jpg|png)$/ ) ) {
+				// Most often tiny buttons/thumbs (< 100px wide)
+				return true;
+			} else if ( src.indexOf( '/g.gif' ) > -1 ) {
+				// Classic WP stats gif
+				return true;
+			} else if ( src.indexOf( '/pixel.mathtag.com' ) > -1 ) {
+				// See mathtag.com
+				return true;
+			}
+			return false;
+		}
+
+		/**
+		 * Get a list of valid embeds from what was passed via WpPressThis_App.data._embed on page load.
+		 *
+		 * @returns array
+		 */
+		function getInterestingEmbeds() {
+			var embeds             = data._embed || [],
+				interestingEmbeds  = [],
+				alreadySelected    = [];
+
+			if ( embeds.length ) {
+				$.each( embeds, function ( i, src ) {
+					if ( !src || !src.length ) {
+						// Skip: no src value
+						return;
+					} else if ( !isEmbeddable( src ) ) {
+						// Skip: not deemed embeddable
+						return;
+					}
+
+					var schemelessSrc = src.replace( /^https?:/, '' );
+
+					if ( $.inArray( schemelessSrc, alreadySelected ) > -1 ) {
+						// Skip: already shown
+						return;
+					}
+
+					interestingEmbeds.push( src );
+					alreadySelected.push( schemelessSrc );
+				} );
+			}
+
+			return interestingEmbeds;
+		}
+
+		/**
+		 * Get what is likely the most valuable image from what was passed via WpPressThis_App.data._img and WpPressThis_App.data._meta on page load.
+		 *
+		 * @returns array
+		 */
+		function getFeaturedImage( data ) {
+			var featured = '';
+
+			if ( ! data || ! data._meta ) {
+				return '';
+			}
+
+			if ( data._meta['twitter:image0:src'] && data._meta['twitter:image0:src'].length ) {
+				featured = data._meta['twitter:image0:src'];
+			} else if ( data._meta['twitter:image0'] && data._meta['twitter:image0'].length ) {
+				featured = data._meta['twitter:image0'];
+			} else if ( data._meta['twitter:image:src'] && data._meta['twitter:image:src'].length ) {
+				featured = data._meta['twitter:image:src'];
+			} else if ( data._meta['twitter:image'] && data._meta['twitter:image'].length ) {
+				featured = data._meta['twitter:image'];
+			} else if ( data._meta['og:image'] && data._meta['og:image'].length ) {
+				featured = data._meta['og:image'];
+			} else if ( data._meta['og:image:secure_url'] && data._meta['og:image:secure_url'].length ) {
+				featured = data._meta['og:image:secure_url'];
+			}
+
+			featured = checkUrl( featured );
+
+			return ( isSrcUninterestingPath( featured ) ) ? '' : featured;
+		}
+
+		/**
+		 * Get a list of valid images from what was passed via WpPressThis_App.data._img and WpPressThis_App.data._meta on page load.
+		 *
+		 * @returns array
+		 */
+		function getInterestingImages( data ) {
+			var imgs             = data._img || [],
+				featuredPict     = getFeaturedImage( data ) || '',
+				interestingImgs  = [],
+				alreadySelected  = [];
+
+			if ( featuredPict.length ) {
+				interestingImgs.push( featuredPict );
+				alreadySelected.push( featuredPict.replace(/^https?:/, '') );
+			}
+
+			if ( imgs.length ) {
+				$.each( imgs, function ( i, src ) {
+					src = src.replace( /http:\/\/[\d]+\.gravatar\.com\//, 'https://secure.gravatar.com/' );
+					src = checkUrl( src );
+
+					if ( ! src || ! src.length ) {
+						// Skip: no src value
+						return;
+					}
+
+					var schemelessSrc = src.replace( /^https?:/, '' );
+
+					if ( Array.prototype.indexOf && alreadySelected.indexOf( schemelessSrc ) > -1 ) {
+						// Skip: already shown
+						return;
+					} else if ( isSrcUninterestingPath( src ) ) {
+						// Skip: spinner, stat, ad, or spacer pict
+						return;
+					} else if ( src.indexOf( 'avatar' ) > -1 && interestingImgs.length >= 15 ) {
+						// Skip:  some type of avatar and we've already gathered more than 23 diff images to show
+						return;
+					}
+
+					interestingImgs.push( src );
+					alreadySelected.push( schemelessSrc );
+				} );
+			}
+
+			return interestingImgs;
+		}
+
+		/**
+		 * Show UX spinner
+		 */
+		function showSpinner() {
+			$( '#spinner' ).addClass( 'show' );
+			$( '.post-actions button' ).each( function() {
+				$( this ).attr( 'disabled', 'disabled' );
+			} );
+		}
+
+		/**
+		 * Hide UX spinner
+		 */
+		function hideSpinner() {
+			$( '#spinner' ).removeClass( 'show' );
+			$( '.post-actions button' ).each( function() {
+				$( this ).removeAttr( 'disabled' );
+			} );
+		}
+
+		/**
+		 * Submit the post form via AJAX, and redirect to the proper screen if published vs saved as a draft.
+		 *
+		 * @param action string publish|draft
+		 */
+		function submitPost( action ) {
+			saveAlert = false;
+			showSpinner();
+
+			var $form = $( '#pressthis-form' );
+
+			if ( 'publish' === action ) {
+				$( '#post_status' ).val( 'publish' );
+			}
+
+			editor && editor.save();
+
+			$( '#title-field' ).val( sanitizeText( $( '#title-container' ).text() ) );
+
+			// Make sure to flush out the tags with tagBox before saving
+			if ( window.tagBox ) {
+				$( 'div.tagsdiv' ).each( function() {
+					window.tagBox.flushTags( this, false, 1 );
+				} );
+			}
+
+			var data = $form.serialize();
+
+			$.ajax( {
+				type: 'post',
+				url: window.ajaxurl,
+				data: data,
+				success: function( response ) {
+					if ( ! response.success ) {
+						renderError( response.data.errorMessage );
+						hideSpinner();
+					} else if ( response.data.redirect ) {
+						if ( window.opener && siteConfig.redir_in_parent ) {
+							try {
+								window.opener.location.href = response.data.redirect;
+							} catch( er ) {}
+
+							window.self.close();
+						} else {
+							window.location.href = response.data.redirect;
+						}
+					}
+				}
+			} );
+		}
+
+		/**
+		 * Inserts the media a user has selected from the presented list inside the editor, as an image or embed, based on type
+		 *
+		 * @param type string img|embed
+		 * @param src string Source URL
+		 * @param link string Optional destination link, for images (defaults to src)
+		 */
+		function insertSelectedMedia( type, src, link ) {
+			var newContent = '';
+
+			if ( ! editor ) {
+				return;
+			}
+
+			src = checkUrl( src );
+			link = checkUrl( link );
+
+			if ( 'img' === type ) {
+				if ( ! link || ! link.length ) {
+					link = src;
+				}
+
+				newContent = '<a href="' + link + '"><img class="alignnone size-full" src="' + src + '" /></a>\n';
+			} else {
+				newContent = '[embed]' + src + '[/embed]\n';
+			}
+
+			if ( ! hasSetFocus ) {
+				// Append to top of content on 1st media insert
+				editor.setContent( newContent + editor.getContent() );
+			} else {
+				// Or add where the cursor was last positioned in TinyMCE
+				editor.execCommand( 'mceInsertContent', false, newContent );
+			}
+
+			hasSetFocus = true;
+		}
+
+		/**
+		 * Adds the currently selected post format next to the option, in the options panel.
+		 *
+		 * @param format string Post format to be displayed
+		 */
+		function setPostFormatString( format ) {
+			if ( ! format || ! siteConfig || ! siteConfig.post_formats || ! siteConfig.post_formats[ format ] ) {
+				return;
+			}
+			$( '#post-option-post-format' ).text( siteConfig.post_formats[ format ] );
+		}
+
+		/**
+		 * Save a new user-generated category via AJAX
+		 */
+		function saveNewCategory() {
+			var data = {
+				action: 'press-this-add-category',
+				post_id: $( '#post_ID' ).val() || 0,
+				name: $( '#new-category' ).val() || '',
+				new_cat_nonce: $( '#_ajax_nonce-add-category' ).val() || '',
+				parent: $( '#new-category-parent' ).val() || 0
+			};
+
+			$.post( window.ajaxurl, data, function( response ) {
+				if ( ! response.success ) {
+					renderError( response.data.errorMessage );
+				} else {
+					// TODO: change if/when the html changes.
+					var $parent, $ul,
+						$wrap = $( 'ul.categories-select' );
+
+					$.each( response.data, function( i, newCat ) {
+						var $node = $( '<li>' ).attr( 'id', 'category-' + newCat.term_id )
+							.append( $( '<label class="selectit">' ).text( newCat.name )
+								.append( $( '<input type="checkbox" name="post_category[]" checked>' ).attr( 'value', newCat.term_id ) ) );
+
+						if ( newCat.parent ) {
+							if ( ! $ul || ! $ul.length ) {
+								$parent = $wrap.find( '#category-' + newCat.parent );
+								$ul = $parent.find( 'ul.children:first' );
+
+								if ( ! $ul.length ) {
+									$ul = $( '<ul class="children">' ).appendTo( $parent );
+								}
+							}
+
+							$ul.append( $node );
+							// TODO: set focus on
+						} else {
+							$wrap.prepend( $node );
+						}
+					} );
+
+					refreshCatsCache();
+				}
+			} );
+		}
+
+		/* ***************************************************************
+		 * RENDERING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Hide the form letting users enter a URL to be scanned, if a URL was already passed.
+		 */
+		function renderToolsVisibility() {
+			if ( data.u && data.u.match( /^https?:/ ) ) {
+				$( '#scanbar' ).hide();
+			}
+		}
+
+		/**
+		 * Render error notice
+		 *
+		 * @param msg string Notice/error message
+		 * @param error string error|notice CSS class for display
+		 */
+		function renderNotice( msg, error ) {
+			var $alerts = $( '.editor-wrapper div.alerts' ),
+				className = error ? 'is-error' : 'is-notice';
+
+			$alerts.append( $( '<p class="' + className + '">' ).text( msg ) );
+		}
+
+		/**
+		 * Render error notice
+		 *
+		 * @param msg string Error message
+		 */
+		function renderError( msg ) {
+			renderNotice( msg, true );
+		}
+
+		/**
+		 * Render notices on page load, if any already
+		 */
+		function renderStartupNotices() {
+			// Render errors sent in the data, if any
+			if ( data.errors && data.errors.length ) {
+				$.each( data.errors, function( i, msg ) {
+					renderError( msg );
+				} );
+			}
+
+			// Prompt user to upgrade their bookmarklet if there is a version mismatch.
+			if ( data.v && data._version && data.v !== data._version ) {
+				$( '.should-upgrade-bookmarklet' ).removeClass( 'is-hidden' );
+			}
+		}
+
+		/**
+		 * Render the suggested title, if any
+		 */
+		function renderSuggestedTitle() {
+			var suggestedTitle = suggestedTitleStr || '',
+				$title = $( '#title-container' );
+
+			if ( ! hasEmptyTitleStr ) {
+				$( '#title-field' ).val( suggestedTitle );
+				$title.text( suggestedTitle );
+				$( '.post-title-placeholder' ).addClass( 'is-hidden' );
+			}
+
+			$title.on( 'keyup', function() {
+				saveAlert = true;
+			}).on( 'paste', function() {
+				saveAlert = true;
+
+				setTimeout( function() {
+					$title.text( $title.text() );
+				}, 100 );
+			} );
+
+		}
+
+		/**
+		 * Render the suggested content, if any
+		 */
+		function renderSuggestedContent() {
+			if ( ! suggestedContentStr || ! suggestedContentStr.length ) {
+				return;
+			}
+
+			if ( ! editor ) {
+				editor = window.tinymce.get( 'pressthis' );
+			}
+
+			if ( editor ) {
+				editor.setContent( suggestedContentStr );
+				editor.on( 'focus', function() {
+					hasSetFocus = true;
+				} );
+			}
+
+		}
+
+		/**
+		 * Render the detected images and embed for selection, if any
+		 */
+		function renderDetectedMedia() {
+			var mediaContainer = $( '#featured-media-container'),
+				listContainer  = $( '#all-media-container' ),
+				found          = 0;
+
+			listContainer.empty();
+
+			if ( ( interestingEmbeds && interestingEmbeds.length ) || ( interestingImages && interestingImages.length ) ) {
+				listContainer.append( '<h2 class="screen-reader-text">' + __( 'allMediaHeading' ) + '</h2><ul class="wppt-all-media-list"/>' );
+			}
+
+			if ( interestingEmbeds && interestingEmbeds.length ) {
+				$.each( interestingEmbeds, function ( i, src ) {
+					src = checkUrl( src );
+
+					if ( ! isEmbeddable( src ) ) {
+						return;
+					}
+
+					var displaySrc = '',
+						cssClass   = 'suggested-media-thumbnail suggested-media-embed';
+
+					if ( src.indexOf( 'youtube.com/' ) > -1 ) {
+						displaySrc = 'https://i.ytimg.com/vi/' + src.replace( /.+v=([^&]+).*/, '$1' ) + '/hqdefault.jpg';
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'youtu.be/' ) > -1 ) {
+						displaySrc = 'https://i.ytimg.com/vi/' + src.replace( /\/([^\/])$/, '$1' ) + '/hqdefault.jpg';
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'dailymotion.com' ) > -1 ) {
+						displaySrc = src.replace( '/video/', '/thumbnail/video/' );
+						cssClass += ' is-video';
+					} else if ( src.indexOf( 'soundcloud.com' ) > -1 ) {
+						cssClass += ' is-audio';
+					} else if ( src.indexOf( 'twitter.com' ) > -1 ) {
+						cssClass += ' is-tweet';
+					} else {
+						cssClass += ' is-video';
+					}
+
+					$( '<li></li>', {
+						'id': 'embed-' + i + '-container',
+						'class': cssClass,
+						'tabindex': '0'
+					} ).css( {
+						'background-image': ( displaySrc.length ) ? 'url(' + displaySrc + ')' : null
+					} ).html(
+						'<span class="screen-reader-text">' + __( 'suggestedEmbedAlt' ).replace( '%d', i + 1 ) + '</span>'
+					).on( 'click keypress', function ( e ) {
+						if ( e.type === 'click' || e.which === 13 ) {
+							insertSelectedMedia( 'embed',src );
+						}
+					} ).appendTo( '.wppt-all-media-list', listContainer );
+
+					found++;
+				} );
+			}
+
+			if ( interestingImages && interestingImages.length ) {
+				$.each( interestingImages, function ( i, src ) {
+					src = checkUrl( src );
+
+					var displaySrc = src.replace(/^(http[^\?]+)(\?.*)?$/, '$1');
+					if ( src.indexOf( 'files.wordpress.com/' ) > -1 ) {
+						displaySrc = displaySrc.replace(/\?.*$/, '') + '?w=' + smallestWidth;
+					} else if ( src.indexOf( 'gravatar.com/' ) > -1 ) {
+						displaySrc = displaySrc.replace( /\?.*$/, '' ) + '?s=' + smallestWidth;
+					} else {
+						displaySrc = src;
+					}
+
+					$( '<li></li>', {
+						'id': 'img-' + i + '-container',
+						'class': 'suggested-media-thumbnail is-image',
+						'tabindex': '0'
+					} ).css( {
+						'background-image': 'url(' + displaySrc + ')'
+					} ).html(
+						'<span class="screen-reader-text">' +__( 'suggestedImgAlt' ).replace( '%d', i + 1 ) + '</span>'
+					).on( 'click keypress', function ( e ) {
+						if ( e.type === 'click' || e.which === 13 ) {
+							insertSelectedMedia( 'img', src, data.u );
+						}
+					} ).appendTo( '.wppt-all-media-list', listContainer );
+
+					found++;
+				} );
+			}
+
+			if ( ! found ) {
+				mediaContainer.removeClass( 'all-media-visible' ).addClass( 'no-media');
+				return;
+			}
+
+			mediaContainer.removeClass( 'no-media' ).addClass( 'all-media-visible' );
+		}
+
+		/* ***************************************************************
+		 * MONITORING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Interactive navigation behavior for the options modal (post format, tags, categories)
+		 */
+		function monitorOptionsModal() {
+			var isOffScreen   = 'is-off-screen',
+				isHidden      = 'is-hidden',
+				$postOptions  = $( '.post-options' ),
+				$postOption   = $( '.post-option' ),
+				$settingModal = $( '.setting-modal' ),
+				$modalClose   = $( '.modal-close' );
+
+			$postOption.on( 'click', function( event ) {
+				var index = $( this ).index(),
+					$targetSettingModal = $settingModal.eq( index );
+
+				event.preventDefault();
+
+				$postOptions
+					.addClass( isOffScreen )
+					.one( transitionEndEvent, function() {
+						$( this ).addClass( isHidden );
+					} );
+
+				$targetSettingModal
+					.removeClass( isOffScreen + ' ' + isHidden )
+					.one( transitionEndEvent, function() {
+						$( this ).find( $modalClose ).focus();
+					} );
+			} );
+
+			$modalClose.on( 'click', function( event ) {
+				var $targetSettingModal = $( this ).parent(),
+					index = $targetSettingModal.index();
+
+				event.preventDefault();
+
+				$postOptions
+					.removeClass( isOffScreen + ' ' + isHidden );
+
+				$targetSettingModal
+					.addClass( isOffScreen )
+					.one( transitionEndEvent, function() {
+						$( this ).addClass( isHidden );
+					} );
+
+				// For browser that don't support transitionend.
+				if ( ! transitionEndEvent ) {
+					setTimeout( function() {
+						$targetSettingModal.addClass( isHidden );
+					}, 350 );
+				}
+
+				$postOption.eq( index - 1 ).focus();
+			} );
+		}
+
+		/**
+		 * Interactive behavior for the sidebar toggle, to show the options modals
+		 */
+		function monitorSidebarToggle() {
+			var $optOpen  = $( '.options-open' ),
+				$optClose = $( '.options-close' ),
+				$postOption = $( '.post-option' ),
+				$sidebar = $( '.options-panel' ),
+				$postActions = $( '.press-this-actions' ),
+				$scanbar = $( '#scanbar' ),
+				isOffScreen = 'is-off-screen',
+				isHidden = 'is-hidden',
+				ifOffHidden = isOffScreen + ' ' + isHidden;
+
+			$optOpen.on( 'click', function(){
+				$optOpen.addClass( isHidden );
+				$optClose.removeClass( isHidden );
+				$postActions.addClass( isHidden );
+				$scanbar.addClass( isHidden );
+
+				$sidebar
+					.removeClass( ifOffHidden )
+					.one( 'transitionend', function() {
+						$postOption.eq( 0 ).focus();
+					} );
+			} );
+
+			$optClose.on( 'click', function(){
+				$optClose.addClass( isHidden );
+				$optOpen.removeClass( isHidden );
+				$postActions.removeClass( isHidden );
+				$scanbar.removeClass( isHidden );
+
+				$sidebar
+					.addClass( isOffScreen )
+					.one( 'transitionend', function() {
+						$( this ).addClass( isHidden );
+						// Reset to options list
+						$( '.post-options' ).removeClass( ifOffHidden );
+						$( '.setting-modal').addClass( ifOffHidden );
+					} );
+			} );
+		}
+
+		/**
+		 * Interactive behavior for the post title's field placeholder
+		 */
+		function monitorPlaceholder() {
+			var $selector = $( '#title-container'),
+				$placeholder = $('.post-title-placeholder');
+
+			$selector.on( 'focus', function() {
+				$placeholder.addClass('is-hidden');
+			} );
+
+			$selector.on( 'blur', function() {
+				var textLength = $( this ).text().length;
+
+				if ( ! textLength ) {
+					$placeholder.removeClass('is-hidden');
+				}
+			} );
+		}
+
+		/* ***************************************************************
+		 * PROCESSING FUNCTIONS
+		 *************************************************************** */
+
+		/**
+		 * Calls all the rendring related functions to happen on page load
+		 */
+		function render(){
+			// We're on!
+			renderToolsVisibility();
+			renderSuggestedTitle();
+			renderDetectedMedia();
+			$( document ).on( 'tinymce-editor-init', renderSuggestedContent );
+			renderStartupNotices();
+		}
+
+		/**
+		 * Set app events and other state monitoring related code.
+		 */
+		function monitor(){
+			$( '#current-site a').click( function( e ) {
+				e.preventDefault();
+			} );
+
+			// Publish and Draft buttons and submit
+
+			$( '#draft-field' ).on( 'click', function() {
+				submitPost( 'draft' );
+			} );
+
+			$( '#publish-field' ).on( 'click', function() {
+				submitPost( 'publish' );
+			} );
+
+			monitorOptionsModal();
+			monitorSidebarToggle();
+			monitorPlaceholder();
+
+			$( '#post-formats-select input' ).on( 'change', function() {
+				var $this = $( this );
+
+				if ( $this.is( ':checked' ) ) {
+					setPostFormatString( $this.attr( 'id' ).replace( /^post-format-(.+)$/, '$1' ) );
+				}
+			} );
+
+			// Needs more work, doesn't detect when the other JS changes the value of #tax-input-post_tag
+			$( '#tax-input-post_tag' ).on( 'change', function() {
+				var val =  $( this ).val();
+				$( '#post-option-tags' ).text( ( val.length ) ? val.replace( /,([^\s])/g, ', $1' ) : '' );
+			} );
+
+			$( window ).on( 'beforeunload.press-this', function() {
+				if ( saveAlert || ( editor && editor.isDirty() ) ) {
+					return __( 'saveAlert' );
+				}
+			} );
+
+			$( 'button.add-cat-toggle' ).on( 'click.press-this', function() {
+				$( this ).toggleClass( 'is-toggled' );
+				$( '.setting-modal .add-category' ).toggleClass( 'is-hidden' );
+				$( '.categories-search-wrapper' ).toggleClass( 'is-hidden' );
+			} );
+
+			$( 'button.add-cat-submit' ).on( 'click.press-this', saveNewCategory );
+
+			$( '.categories-search' ).on( 'keyup', function() {
+				var search = $( this ).val().toLowerCase() || '';
+
+				// Don't search when less thasn 3 extended ASCII chars
+				if ( /[\x20-\xFF]+/.test( search ) && search.length < 2 ) {
+					return;
+				}
+
+				$.each( catsCache, function( i, cat ) {
+					cat.node.removeClass( 'is-hidden searched-parent' );
+				} );
+
+				if ( search ) {
+					$.each( catsCache, function( i, cat ) {
+						if ( cat.text.indexOf( search ) === -1 ) {
+							cat.node.addClass( 'is-hidden' );
+						} else {
+							cat.parents.addClass( 'searched-parent' );
+						}
+					} );
+				}
+			} );
+
+			return true;
+		}
+
+		function refreshCatsCache() {
+			$( '.categories-select' ).find( 'li' ).each( function() {
+				var $this = $( this );
+
+				catsCache.push( {
+					node: $this,
+					parents: $this.parents( 'li' ),
+					text: $this.children( 'label' ).text().toLowerCase()
+				} );
+			} );
+		}
+
+		// Let's go!
+		$( document ).ready( function() {
+			render();
+			monitor();
+			refreshCatsCache();
+		});
+
+		// Expose public methods
+		// TODO: which are needed?
+		return {
+			renderNotice: renderNotice,
+			renderError: renderError
+		};
+	}
+
+	window.wp = window.wp || {};
+	window.wp.pressThis = new PressThis();
+
+}( jQuery, window ));
Index: src/wp-admin/options-writing.php
===================================================================
--- src/wp-admin/options-writing.php	(revision 31531)
+++ src/wp-admin/options-writing.php	(working copy)
@@ -113,16 +113,6 @@
 ?>
 </table>
 
-<h3 class="title"><?php _e('Press This') ?></h3>
-<p><?php _e('Press This is a bookmarklet: a little app that runs in your browser and lets you grab bits of the web.');?></p>
-<p><?php _e('Use Press This to clip text, images and videos from any web page. Then edit and add more straight from Press This before you save or publish it in a post on your site.'); ?></p>
-<p><?php _e('Drag-and-drop the following link to your bookmarks bar or right click it and add it to your favorites for a posting shortcut.') ?></p>
-<p class="pressthis"><a onclick="return false;" oncontextmenu="if(window.navigator.userAgent.indexOf('WebKit')!=-1||window.navigator.userAgent.indexOf('MSIE')!=-1){jQuery('.pressthis-code').show().find('textarea').focus().select();return false;}" href="<?php echo htmlspecialchars( get_shortcut_link() ); ?>"><span><?php _e('Press This') ?></span></a></p>
-<div class="pressthis-code" style="display:none;">
-	<p class="description"><?php _e('If your bookmarks toolbar is hidden: copy the code below, open your Bookmarks manager, create new bookmark, type Press This into the name field and paste the code into the URL field.') ?></p>
-	<p><textarea rows="5" cols="120" readonly="readonly"><?php echo htmlspecialchars( get_shortcut_link() ); ?></textarea></p>
-</div>
-
 <?php
 /** This filter is documented in wp-admin/options.php */
 if ( apply_filters( 'enable_post_by_email_configuration', true ) ) {
Index: src/wp-admin/press-this.php
===================================================================
--- src/wp-admin/press-this.php	(revision 31531)
+++ src/wp-admin/press-this.php	(working copy)
@@ -11,675 +11,11 @@
 /** WordPress Administration Bootstrap */
 require_once( dirname( __FILE__ ) . '/admin.php' );
 
-header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
-
 if ( ! current_user_can( 'edit_posts' ) || ! current_user_can( get_post_type_object( 'post' )->cap->create_posts ) )
 	wp_die( __( 'Cheatin&#8217; uh?' ), 403 );
 
-/**
- * Press It form handler.
- *
- * @since 2.6.0
- *
- * @return int Post ID
- */
-function press_it() {
-
-	$post = get_default_post_to_edit();
-	$post = get_object_vars($post);
-	$post_ID = $post['ID'] = (int) $_POST['post_id'];
-
-	if ( !current_user_can('edit_post', $post_ID) )
-		wp_die(__('You are not allowed to edit this post.'));
-
-	$post['post_category'] = isset($_POST['post_category']) ? $_POST['post_category'] : '';
-	$post['tax_input'] = isset($_POST['tax_input']) ? $_POST['tax_input'] : '';
-	$post['post_title'] = isset($_POST['title']) ? $_POST['title'] : '';
-	$content = isset($_POST['content']) ? $_POST['content'] : '';
-
-	$upload = false;
-	if ( !empty($_POST['photo_src']) && current_user_can('upload_files') ) {
-		foreach( (array) $_POST['photo_src'] as $key => $image) {
-			// See if files exist in content - we don't want to upload non-used selected files.
-			if ( strpos($_POST['content'], htmlspecialchars($image)) !== false ) {
-				$desc = isset($_POST['photo_description'][$key]) ? $_POST['photo_description'][$key] : '';
-				$upload = media_sideload_image($image, $post_ID, $desc);
-
-				// Replace the POSTED content <img> with correct uploaded ones. Regex contains fix for Magic Quotes
-				if ( !is_wp_error($upload) )
-					$content = preg_replace('/<img ([^>]*)src=\\\?(\"|\')'.preg_quote(htmlspecialchars($image), '/').'\\\?(\2)([^>\/]*)\/*>/is', $upload, $content);
-			}
-		}
-	}
-	// Set the post_content and status.
-	$post['post_content'] = $content;
-	if ( isset( $_POST['publish'] ) && current_user_can( 'publish_posts' ) )
-		$post['post_status'] = 'publish';
-	elseif ( isset( $_POST['review'] ) )
-		$post['post_status'] = 'pending';
-	else
-		$post['post_status'] = 'draft';
-
-	// Error handling for media_sideload.
-	if ( is_wp_error($upload) ) {
-		wp_delete_post($post_ID);
-		wp_die( esc_html( $upload->get_error_message() ) );
-	} else {
-		// Post formats.
-		if ( isset( $_POST['post_format'] ) ) {
-			if ( current_theme_supports( 'post-formats', $_POST['post_format'] ) )
-				set_post_format( $post_ID, $_POST['post_format'] );
-			elseif ( '0' == $_POST['post_format'] )
-				set_post_format( $post_ID, false );
-		}
-
-		$post_ID = wp_update_post($post);
-	}
-
-	return $post_ID;
+if ( empty( $GLOBALS['wp_press_this'] ) ) {
+	include( ABSPATH . 'wp-admin/includes/class-wp-press-this.php' );
 }
 
-// For submitted posts.
-if ( isset($_REQUEST['action']) && 'post' == $_REQUEST['action'] ) {
-	check_admin_referer('press-this');
-	$posted = $post_ID = press_it();
-} else {
-	$post = get_default_post_to_edit('post', true);
-	$post_ID = $post->ID;
-}
-
-// Set Variables
-$title = isset( $_GET['t'] ) ? trim( strip_tags( html_entity_decode( wp_unslash( $_GET['t'] ) , ENT_QUOTES) ) ) : '';
-
-$selection = '';
-if ( !empty($_GET['s']) ) {
-	$selection = str_replace('&apos;', "'", wp_unslash($_GET['s']));
-	$selection = trim( htmlspecialchars( html_entity_decode($selection, ENT_QUOTES) ) );
-}
-
-if ( ! empty($selection) ) {
-	$selection = preg_replace('/(\r?\n|\r)/', '</p><p>', $selection);
-	$selection = '<p>' . str_replace('<p></p>', '', $selection) . '</p>';
-}
-
-$url = isset($_GET['u']) ? esc_url($_GET['u']) : '';
-$image = isset($_GET['i']) ? $_GET['i'] : '';
-
-if ( !empty($_REQUEST['ajax']) ) {
-	switch ($_REQUEST['ajax']) {
-		case 'video': ?>
-			<script type="text/javascript">
-				jQuery('.select').click(function() {
-					append_editor(jQuery('#embed-code').val());
-					jQuery('#extra-fields').hide();
-					jQuery('#extra-fields').html('');
-				});
-				jQuery('.close').click(function() {
-					jQuery('#extra-fields').hide();
-					jQuery('#extra-fields').html('');
-				});
-			</script>
-			<div class="postbox">
-				<h2><label for="embed-code"><?php _e('Embed Code') ?></label></h2>
-				<div class="inside">
-					<textarea name="embed-code" id="embed-code" rows="8" cols="40"><?php echo esc_textarea( $selection ); ?></textarea>
-					<p id="options"><a href="#" class="select button"><?php _e('Insert Video'); ?></a> <a href="#" class="close button"><?php _e('Cancel'); ?></a></p>
-				</div>
-			</div>
-			<?php break;
-
-		case 'photo_thickbox': ?>
-			<script type="text/javascript">
-				jQuery('.cancel').click(function() {
-					tb_remove();
-				});
-				jQuery('.select').click(function() {
-					image_selector(this);
-				});
-			</script>
-			<h3 class="tb"><label for="tb_this_photo_description"><?php _e('Description') ?></label></h3>
-			<div class="titlediv">
-				<div class="titlewrap">
-					<input id="tb_this_photo_description" name="photo_description" class="tb_this_photo_description tbtitle text" type="text" onkeypress="if(event.keyCode==13) image_selector(this);" value="<?php echo esc_attr($title);?>"/>
-				</div>
-			</div>
-
-			<p class="centered">
-				<input type="hidden" name="this_photo" value="<?php echo esc_attr( $image ); ?>" id="tb_this_photo" class="tb_this_photo" />
-				<a href="#" class="select">
-					<img src="<?php echo esc_url( $image ); ?>" alt="<?php esc_attr_e( 'Click to insert.' ); ?>" title="<?php esc_attr_e( 'Click to insert.' ); ?>" />
-				</a>
-			</p>
-
-			<p id="options"><a href="#" class="select button"><?php _e('Insert Image'); ?></a> <a href="#" class="cancel button"><?php _e('Cancel'); ?></a></p>
-			<?php break;
-	case 'photo_images':
-		/**
-		 * Retrieve all image URLs from given URI.
-		 *
-		 * @since 2.6.0
-		 *
-		 * @param string $uri
-		 * @return string
-		 */
-		function get_images_from_uri($uri) {
-			$uri = preg_replace('/\/#.+?$/','', $uri);
-			if ( preg_match( '/\.(jpe?g|jpe|gif|png)\b/i', $uri ) && !strpos( $uri, 'blogger.com' ) )
-				return "'" . esc_attr( html_entity_decode($uri) ) . "'";
-			$content = wp_remote_fopen($uri);
-			if ( false === $content )
-				return '';
-			$host = parse_url($uri);
-			$pattern = '/<img ([^>]*)src=(\"|\')([^<>\'\"]+)(\2)([^>]*)\/*>/i';
-			$content = str_replace(array("\n","\t","\r"), '', $content);
-			preg_match_all($pattern, $content, $matches);
-			if ( empty($matches[0]) )
-				return '';
-			$sources = array();
-			foreach ($matches[3] as $src) {
-
-				// If no http in URL.
-				if (strpos($src, 'http') === false)
-					// If it doesn't have a relative URI.
-					if ( strpos($src, '../') === false && strpos($src, './') === false && strpos($src, '/') === 0)
-						$src = 'http://'.str_replace('//','/', $host['host'].'/'.$src);
-					else
-						$src = 'http://'.str_replace('//','/', $host['host'].'/'.dirname($host['path']).'/'.$src);
-				$sources[] = esc_url($src);
-			}
-			return "'" . implode("','", $sources) . "'";
-		}
-		$url = wp_kses(urldecode($url), null);
-		echo 'new Array('.get_images_from_uri($url).')';
-		break;
-
-	case 'photo_js': ?>
-		// Gather images and load some default JS.
-		var last = null
-		var img, img_tag, aspect, w, h, skip, i, strtoappend = "";
-		if(photostorage == false) {
-		var my_src = eval(
-			jQuery.ajax({
-				type: "GET",
-				url: "<?php echo esc_url($_SERVER['PHP_SELF']); ?>",
-				cache : false,
-				async : false,
-				data: "ajax=photo_images&u=<?php echo urlencode($url); ?>",
-				dataType : "script"
-			}).responseText
-		);
-		if(my_src.length == 0) {
-			var my_src = eval(
-				jQuery.ajax({
-					type: "GET",
-					url: "<?php echo esc_url($_SERVER['PHP_SELF']); ?>",
-					cache : false,
-					async : false,
-					data: "ajax=photo_images&u=<?php echo urlencode($url); ?>",
-					dataType : "script"
-				}).responseText
-			);
-			if(my_src.length == 0) {
-				strtoappend = '<?php _e('Unable to retrieve images or no images on page.'); ?>';
-			}
-		}
-		}
-		for (i = 0; i < my_src.length; i++) {
-			img = new Image();
-			img.src = my_src[i];
-			img_attr = 'id="img' + i + '"';
-			skip = false;
-
-			maybeappend = '<a href="?ajax=photo_thickbox&amp;i=' + encodeURIComponent(img.src) + '&amp;u=<?php echo urlencode($url); ?>&amp;height=400&amp;width=500" title="" class="thickbox"><img src="' + img.src + '" ' + img_attr + '/></a>';
-
-			if (img.width && img.height) {
-				if (img.width >= 30 && img.height >= 30) {
-					aspect = img.width / img.height;
-					scale = (aspect > 1) ? (71 / img.width) : (71 / img.height);
-
-					w = img.width;
-					h = img.height;
-
-					if (scale < 1) {
-						w = parseInt(img.width * scale);
-						h = parseInt(img.height * scale);
-					}
-					img_attr += ' style="width: ' + w + 'px; height: ' + h + 'px;"';
-					strtoappend += maybeappend;
-				}
-			} else {
-				strtoappend += maybeappend;
-			}
-		}
-
-		function pick(img, desc) {
-			if (img) {
-				if('object' == typeof jQuery('.photolist input') && jQuery('.photolist input').length != 0) length = jQuery('.photolist input').length;
-				if(length == 0) length = 1;
-				jQuery('.photolist').append('<input name="photo_src[' + length + ']" value="' + img +'" type="hidden"/>');
-				jQuery('.photolist').append('<input name="photo_description[' + length + ']" value="' + desc +'" type="hidden"/>');
-				insert_editor( "\n\n" + encodeURI('<p style="text-align: center;"><a href="<?php echo $url; ?>"><img src="' + img +'" alt="' + desc + '" /></a></p>'));
-			}
-			return false;
-		}
-
-		function image_selector(el) {
-			var desc, src, parent = jQuery(el).closest('#photo-add-url-div');
-
-			if ( parent.length ) {
-				desc = parent.find('input.tb_this_photo_description').val() || '';
-				src = parent.find('input.tb_this_photo').val() || ''
-			} else {
-				desc = jQuery('#tb_this_photo_description').val() || '';
-				src = jQuery('#tb_this_photo').val() || ''
-			}
-
-			tb_remove();
-			pick(src, desc);
-			jQuery('#extra-fields').hide();
-			jQuery('#extra-fields').html('');
-			return false;
-		}
-
-		jQuery('#extra-fields').html('<div class="postbox"><h2><?php _e( 'Add Photos' ); ?> <small id="photo_directions">(<?php _e("click images to select") ?>)</small></h2><ul class="actions"><li><a href="#" id="photo-add-url" class="button button-small"><?php _e("Add from URL") ?> +</a></li></ul><div class="inside"><div class="titlewrap"><div id="img_container"></div></div><p id="options"><a href="#" class="close button"><?php _e('Cancel'); ?></a><a href="#" class="refresh button"><?php _e('Refresh'); ?></a></p></div>');
-		jQuery('#img_container').html(strtoappend);
-		<?php break;
-}
-die;
-}
-
-	wp_enqueue_style( 'colors' );
-	wp_enqueue_script( 'post' );
-	add_thickbox();
-	_wp_admin_html_begin();
-?>
-<title><?php _e('Press This') ?></title>
-<script type="text/javascript">
-addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
-var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>', pagenow = 'press-this', isRtl = <?php echo (int) is_rtl(); ?>;
-var photostorage = false;
-</script>
-
-<?php
-	/** This action is documented in wp-admin/admin-header.php */
-	do_action( 'admin_enqueue_scripts', 'press-this.php' );
-
-	/**
-	 * Fires when styles are printed for the Press This admin page.
-	 *
-	 * @since 3.7.0
-	 */
-	do_action( 'admin_print_styles-press-this.php' );
-
-	/** This action is documented in wp-admin/admin-header.php */
-	do_action( 'admin_print_styles' );
-
-	/**
-	 * Fires when scripts are printed for the Press This admin page.
-	 *
-	 * @since 3.7.0
-	 */
-	do_action( 'admin_print_scripts-press-this.php' );
-
-	/** This action is documented in wp-admin/admin-header.php */
-	do_action( 'admin_print_scripts' );
-
-	/**
-	 * Fires in the head tag on the Press This admin page.
-	 *
-	 * @since 3.7.0
-	 */
-	do_action( 'admin_head-press-this.php' );
-
-	/** This action is documented in wp-admin/admin-header.php */
-	do_action( 'admin_head' );
-?>
-	<script type="text/javascript">
-	var wpActiveEditor = 'content';
-
-	function insert_plain_editor(text) {
-		if ( typeof(QTags) != 'undefined' )
-			QTags.insertContent(text);
-	}
-	function set_editor(text) {
-		if ( '' == text || '<p></p>' == text )
-			text = '<p><br /></p>';
-
-		if ( tinyMCE.activeEditor )
-			tinyMCE.execCommand('mceSetContent', false, text);
-	}
-	function insert_editor(text) {
-		if ( '' != text && tinyMCE.activeEditor && ! tinyMCE.activeEditor.isHidden()) {
-			tinyMCE.execCommand('mceInsertContent', false, '<p>' + decodeURI(tinymce.DOM.decode(text)) + '</p>', {format : 'raw'});
-		} else {
-			insert_plain_editor(decodeURI(text));
-		}
-	}
-	function append_editor(text) {
-		if ( '' != text && tinyMCE.activeEditor && ! tinyMCE.activeEditor.isHidden()) {
-			tinyMCE.execCommand('mceSetContent', false, tinyMCE.activeEditor.getContent({format : 'raw'}) + '<p>' + text + '</p>');
-		} else {
-			insert_plain_editor(text);
-		}
-	}
-
-	function show(tab_name) {
-		jQuery('#extra-fields').html('');
-		switch(tab_name) {
-			case 'video' :
-				jQuery('#extra-fields').load('<?php echo esc_url($_SERVER['PHP_SELF']); ?>', { ajax: 'video', s: '<?php echo esc_attr($selection); ?>'}, function() {
-					<?php
-					$content = '';
-					if ( preg_match("/youtube\.com\/watch/i", $url) ) {
-						list($domain, $video_id) = explode("v=", $url);
-						$video_id = esc_attr($video_id);
-						$content = '<object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/' . $video_id . '"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/' . $video_id . '" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object>';
-
-					} elseif ( preg_match("/vimeo\.com\/[0-9]+/i", $url) ) {
-						list($domain, $video_id) = explode(".com/", $url);
-						$video_id = esc_attr($video_id);
-						$content = '<object width="400" height="225"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://www.vimeo.com/moogaloop.swf?clip_id=' . $video_id . '&amp;server=www.vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" />	<embed src="http://www.vimeo.com/moogaloop.swf?clip_id=' . $video_id . '&amp;server=www.vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="225"></embed></object>';
-
-						if ( trim($selection) == '' )
-							$selection = '<p><a href="http://www.vimeo.com/' . $video_id . '?pg=embed&sec=' . $video_id . '">' . $title . '</a> on <a href="http://vimeo.com?pg=embed&sec=' . $video_id . '">Vimeo</a></p>';
-
-					} elseif ( strpos( $selection, '<object' ) !== false ) {
-						$content = $selection;
-					}
-					?>
-					jQuery('#embed-code').prepend('<?php echo htmlentities($content); ?>');
-				});
-				jQuery('#extra-fields').show();
-				return false;
-				break;
-			case 'photo' :
-				function setup_photo_actions() {
-					jQuery('.close').click(function() {
-						jQuery('#extra-fields').hide();
-						jQuery('#extra-fields').html('');
-					});
-					jQuery('.refresh').click(function() {
-						photostorage = false;
-						show('photo');
-					});
-					jQuery('#photo-add-url').click(function(){
-						var form = jQuery('#photo-add-url-div').clone();
-						jQuery('#img_container').empty().append( form.show() );
-					});
-					jQuery('#waiting').hide();
-					jQuery('#extra-fields').show();
-				}
-
-				jQuery('#waiting').show();
-				if(photostorage == false) {
-					jQuery.ajax({
-						type: "GET",
-						cache : false,
-						url: "<?php echo esc_url($_SERVER['PHP_SELF']); ?>",
-						data: "ajax=photo_js&u=<?php echo urlencode($url)?>",
-						dataType : "script",
-						success : function(data) {
-							eval(data);
-							photostorage = jQuery('#extra-fields').html();
-							setup_photo_actions();
-						}
-					});
-				} else {
-					jQuery('#extra-fields').html(photostorage);
-					setup_photo_actions();
-				}
-				return false;
-				break;
-		}
-	}
-	jQuery(document).ready(function($) {
-		var $contnet = $( '#content' );
-
-		// Resize screen.
-		window.resizeTo(760,580);
-
-		// Set button actions.
-		jQuery('#photo_button').click(function() { show('photo'); return false; });
-		jQuery('#video_button').click(function() { show('video'); return false; });
-
-		// Auto select.
-		<?php if ( preg_match("/youtube\.com\/watch/i", $url) ) { ?>
-			show('video');
-		<?php } elseif ( preg_match("/vimeo\.com\/[0-9]+/i", $url) ) { ?>
-			show('video');
-		<?php } elseif ( preg_match("/flickr\.com/i", $url) ) { ?>
-			show('photo');
-		<?php } ?>
-		jQuery('#title').unbind();
-		jQuery('#publish, #save').click(function() { jQuery('.press-this #publishing-actions .spinner').css('display', 'inline-block'); });
-
-		$('#tagsdiv-post_tag, #categorydiv').children('h3, .handlediv').click(function(){
-			$(this).siblings('.inside').toggle();
-		});
-
-		if ( $( '#wp-content-wrap' ).hasClass( 'html-active' ) && window.switchEditors &&
-			( tinyMCEPreInit.mceInit.content && tinyMCEPreInit.mceInit.content.wpautop ) ) {
-			// The Text editor is default, run the initial content through pre_wpautop() to convert the paragraphs
-			$contnet.text( window.switchEditors.pre_wpautop( $contnet.text() ) );
-		}
-	});
-</script>
-</head>
-<?php
-$admin_body_class = ( is_rtl() ) ? 'rtl' : '';
-$admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
-?>
-<body class="press-this wp-admin wp-core-ui <?php echo $admin_body_class; ?>">
-<form action="press-this.php?action=post" method="post">
-<div id="poststuff" class="metabox-holder">
-	<div id="side-sortables" class="press-this-sidebar">
-		<div class="sleeve">
-			<?php wp_nonce_field('press-this') ?>
-			<input type="hidden" name="post_type" id="post_type" value="text"/>
-			<input type="hidden" name="autosave" id="autosave" />
-			<input type="hidden" id="original_post_status" name="original_post_status" value="draft" />
-			<input type="hidden" id="prev_status" name="prev_status" value="draft" />
-			<input type="hidden" id="post_id" name="post_id" value="<?php echo (int) $post_ID; ?>" />
-
-			<!-- This div holds the photo metadata -->
-			<div class="photolist"></div>
-
-			<div id="submitdiv" class="postbox">
-				<div class="handlediv" title="<?php esc_attr_e( 'Click to toggle' ); ?>"><br /></div>
-				<h3 class="hndle"><?php _e('Press This') ?></h3>
-				<div class="inside">
-					<p id="publishing-actions">
-					<?php
-						submit_button( __( 'Save Draft' ), 'button', 'draft', false, array( 'id' => 'save' ) );
-						if ( current_user_can('publish_posts') ) {
-							submit_button( __( 'Publish' ), 'primary', 'publish', false );
-						} else {
-							echo '<br /><br />';
-							submit_button( __( 'Submit for Review' ), 'primary', 'review', false );
-						} ?>
-						<span class="spinner" style="display: none;"></span>
-					</p>
-					<?php if ( current_theme_supports( 'post-formats' ) && post_type_supports( 'post', 'post-formats' ) ) :
-							$post_formats = get_theme_support( 'post-formats' );
-							if ( is_array( $post_formats[0] ) ) :
-								$default_format = get_option( 'default_post_format', '0' );
-						?>
-					<p>
-						<label for="post_format"><?php _e( 'Post Format:' ); ?>
-						<select name="post_format" id="post_format">
-							<option value="0"><?php echo get_post_format_string( 'standard' ); ?></option>
-						<?php foreach ( $post_formats[0] as $format ): ?>
-							<option<?php selected( $default_format, $format ); ?> value="<?php echo esc_attr( $format ); ?>"> <?php echo esc_html( get_post_format_string( $format ) ); ?></option>
-						<?php endforeach; ?>
-						</select></label>
-					</p>
-					<?php endif; endif; ?>
-				</div>
-			</div>
-
-			<?php $tax = get_taxonomy( 'category' ); ?>
-			<div id="categorydiv" class="postbox">
-				<div class="handlediv" title="<?php esc_attr_e( 'Click to toggle' ); ?>"><br /></div>
-				<h3 class="hndle"><?php _e('Categories') ?></h3>
-				<div class="inside">
-				<div id="taxonomy-category" class="categorydiv">
-
-					<ul id="category-tabs" class="category-tabs">
-						<li class="tabs"><a href="#category-all"><?php echo $tax->labels->all_items; ?></a></li>
-						<li class="hide-if-no-js"><a href="#category-pop"><?php _e( 'Most Used' ); ?></a></li>
-					</ul>
-
-					<div id="category-pop" class="tabs-panel" style="display: none;">
-						<ul id="categorychecklist-pop" class="categorychecklist form-no-clear" >
-							<?php $popular_ids = wp_popular_terms_checklist( 'category' ); ?>
-						</ul>
-					</div>
-
-					<div id="category-all" class="tabs-panel">
-						<ul id="categorychecklist" data-wp-lists="list:category" class="categorychecklist form-no-clear">
-							<?php wp_terms_checklist($post_ID, array( 'taxonomy' => 'category', 'popular_cats' => $popular_ids ) ) ?>
-						</ul>
-					</div>
-
-					<?php if ( !current_user_can($tax->cap->assign_terms) ) : ?>
-					<p><em><?php _e('You cannot modify this Taxonomy.'); ?></em></p>
-					<?php endif; ?>
-					<?php if ( current_user_can($tax->cap->edit_terms) ) : ?>
-						<div id="category-adder" class="wp-hidden-children">
-							<h4>
-								<a id="category-add-toggle" href="#category-add" class="hide-if-no-js">
-									<?php printf( __( '+ %s' ), $tax->labels->add_new_item ); ?>
-								</a>
-							</h4>
-							<p id="category-add" class="category-add wp-hidden-child">
-								<label class="screen-reader-text" for="newcategory"><?php echo $tax->labels->add_new_item; ?></label>
-								<input type="text" name="newcategory" id="newcategory" class="form-required form-input-tip" value="<?php echo esc_attr( $tax->labels->new_item_name ); ?>" aria-required="true"/>
-								<label class="screen-reader-text" for="newcategory_parent">
-									<?php echo $tax->labels->parent_item_colon; ?>
-								</label>
-								<?php wp_dropdown_categories( array( 'taxonomy' => 'category', 'hide_empty' => 0, 'name' => 'newcategory_parent', 'orderby' => 'name', 'hierarchical' => 1, 'show_option_none' => '&mdash; ' . $tax->labels->parent_item . ' &mdash;' ) ); ?>
-								<input type="button" id="category-add-submit" data-wp-lists="add:categorychecklist:category-add" class="button category-add-submit" value="<?php echo esc_attr( $tax->labels->add_new_item ); ?>" />
-								<?php wp_nonce_field( 'add-category', '_ajax_nonce-add-category', false ); ?>
-								<span id="category-ajax-response"></span>
-							</p>
-						</div>
-					<?php endif; ?>
-				</div>
-				</div>
-			</div>
-
-			<div id="tagsdiv-post_tag" class="postbox">
-				<div class="handlediv" title="<?php esc_attr_e( 'Click to toggle' ); ?>"><br /></div>
-				<h3><span><?php _e('Tags'); ?></span></h3>
-				<div class="inside">
-					<div class="tagsdiv" id="post_tag">
-						<div class="jaxtag">
-							<label class="screen-reader-text" for="newtag"><?php _e('Tags'); ?></label>
-							<input type="hidden" name="tax_input[post_tag]" class="the-tags" id="tax-input[post_tag]" value="" />
-							<div class="ajaxtag">
-								<input type="text" name="newtag[post_tag]" class="newtag form-input-tip" size="16" autocomplete="off" value="" />
-								<input type="button" class="button tagadd" value="<?php esc_attr_e('Add'); ?>" />
-							</div>
-						</div>
-						<div class="tagchecklist"></div>
-					</div>
-					<p class="tagcloud-link"><a href="#titlediv" class="tagcloud-link" id="link-post_tag"><?php _e('Choose from the most used tags'); ?></a></p>
-				</div>
-			</div>
-		</div>
-	</div>
-	<div class="posting">
-
-		<div id="wphead">
-			<h1 id="site-heading">
-				<a href="<?php echo get_option('home'); ?>/" target="_blank">
-					<span id="site-title"><?php bloginfo('name'); ?></span>
-				</a>
-			</h1>
-		</div>
-
-		<?php
-		if ( isset($posted) && intval($posted) ) {
-			$post_ID = intval($posted); ?>
-			<div id="message" class="updated">
-			<p><strong><?php _e('Your post has been saved.'); ?></strong>
-			<a onclick="window.opener.location.replace(this.href); window.close();" href="<?php echo get_permalink($post_ID); ?>"><?php _e('View post'); ?></a>
-			| <a href="<?php echo get_edit_post_link( $post_ID ); ?>" onclick="window.opener.location.replace(this.href); window.close();"><?php _e('Edit Post'); ?></a>
-			| <a href="#" onclick="window.close();"><?php _e('Close Window'); ?></a></p>
-			</div>
-		<?php } ?>
-
-		<div id="titlediv">
-			<div class="titlewrap">
-				<input name="title" id="title" class="text" type="text" value="<?php echo esc_attr($title);?>"/>
-			</div>
-		</div>
-
-		<div id="waiting" style="display: none"><span class="spinner"></span> <span><?php esc_html_e( 'Loading&hellip;' ); ?></span></div>
-
-		<div id="extra-fields" style="display: none"></div>
-
-		<div class="postdivrich">
-		<?php
-
-		$editor_settings = array(
-			'teeny' => true,
-			'textarea_rows' => '15'
-		);
-
-		$content = '';
-		if ( $selection )
-			$content .= $selection;
-
-		if ( $url ) {
-			$content .= '<p>';
-
-			if ( $selection )
-				$content .= __('via ');
-
-			$content .= sprintf( "<a href='%s'>%s</a>.</p>", esc_url( $url ), esc_html( $title ) );
-		}
-
-		remove_action( 'media_buttons', 'media_buttons' );
-		add_action( 'media_buttons', 'press_this_media_buttons' );
-		function press_this_media_buttons() {
-			_e( 'Add:' );
-
-			if ( current_user_can('upload_files') ) {
-				?>
-				<a id="photo_button" title="<?php esc_attr_e('Insert an Image'); ?>" href="#">
-				<img alt="<?php esc_attr_e('Insert an Image'); ?>" src="<?php echo esc_url( admin_url( 'images/media-button-image.gif?ver=20100531' ) ); ?>"/></a>
-				<?php
-			}
-			?>
-			<a id="video_button" title="<?php esc_attr_e('Embed a Video'); ?>" href="#"><img alt="<?php esc_attr_e('Embed a Video'); ?>" src="<?php echo esc_url( admin_url( 'images/media-button-video.gif?ver=20100531' ) ); ?>"/></a>
-			<?php
-		}
-
-		wp_editor( $content, 'content', $editor_settings );
-
-		?>
-		</div>
-	</div>
-</div>
-</form>
-<div id="photo-add-url-div" style="display:none;">
-	<table><tr>
-	<td><label for="this_photo"><?php _e('URL') ?></label></td>
-	<td><input type="text" id="this_photo" name="this_photo" class="tb_this_photo text" onkeypress="if(event.keyCode==13) image_selector(this);" /></td>
-	</tr><tr>
-	<td><label for="this_photo_description"><?php _e('Description') ?></label></td>
-	<td><input type="text" id="this_photo_description" name="photo_description" class="tb_this_photo_description text" onkeypress="if(event.keyCode==13) image_selector(this);" value="<?php echo esc_attr($title);?>"/></td>
-	</tr><tr>
-	<td><input type="button" class="button" onclick="image_selector(this)" value="<?php esc_attr_e('Insert Image'); ?>" /></td>
-	</tr></table>
-</div>
-<?php
-/** This action is documented in wp-admin/admin-footer.php */
-do_action( 'admin_footer' );
-/** This action is documented in wp-admin/admin-footer.php */
-do_action( 'admin_print_footer_scripts' );
-?>
-<script type="text/javascript">if(typeof wpOnload=='function')wpOnload();</script>
-</body>
-</html>
+$GLOBALS['wp_press_this']->html();
Index: src/wp-admin/tools.php
===================================================================
--- src/wp-admin/tools.php	(revision 31531)
+++ src/wp-admin/tools.php	(working copy)
@@ -38,15 +38,62 @@
 <?php if ( current_user_can('edit_posts') ) : ?>
 <div class="tool-box">
 	<h3 class="title"><?php _e('Press This') ?></h3>
-	<p><?php _e('Press This is a bookmarklet: a little app that runs in your browser and lets you grab bits of the web.');?></p>
+	<div class="postbox press-this-install">
+		<p><?php _e( 'Press This is a little app that lets you grab bits of the web and create new posts with ease.' );?></p>
+		<p><?php _e( 'Use Press This to clip text, images and videos from any web page. Then edit and add more straight from Press This before you save or publish it in a post on your site.' ); ?></p>
+	</div>
 
-	<p><?php _e('Use Press This to clip text, images and videos from any web page. Then edit and add more straight from Press This before you save or publish it in a post on your site.'); ?></p>
-	<p class="description"><?php _e('Drag-and-drop the following link to your bookmarks bar or right click it and add it to your favorites for a posting shortcut.') ?></p>
-	<p class="pressthis"><a onclick="return false;" oncontextmenu="if(window.navigator.userAgent.indexOf('WebKit')!=-1||window.navigator.userAgent.indexOf('MSIE')!=-1){jQuery('.pressthis-code').show().find('textarea').focus().select();return false;}" href="<?php echo htmlspecialchars( get_shortcut_link() ); ?>"><span><?php _e('Press This') ?></span></a></p>
-	<div class="pressthis-code" style="display:none;">
-	<p class="description"><?php _e('If your bookmarks toolbar is hidden: copy the code below, open your Bookmarks manager, create new bookmark, type Press This into the name field and paste the code into the URL field.') ?></p>
-	<p><textarea rows="5" cols="120" readonly="readonly"><?php echo htmlspecialchars( get_shortcut_link() ); ?></textarea></p>
+	<form>
+	<div class="postbox press-this-install">
+		<h3><?php _e( 'Install Press This' ); ?></h3>
+		<h4><?php _e( 'Bookmarklet' ); ?></h4>
+		<p><?php _e( 'Drag the bookmarklet below to your bookmarks bar. Then, when you\'re on a page you want to share, simply "press" it.' ); ?></p>
+
+		<p class="pressthis">
+			<a class="" onclick="return false;" href="<?php echo htmlspecialchars( get_shortcut_link() ); ?>"><span><?php _e( 'Press This' ) ?></span></a>
+			<button type="button" class="button button-secondary js-show-pressthis-code-wrap" aria-expanded="false" aria-controls="pressthis-code-wrap">
+				<span class="dashicons dashicons-clipboard"></span>
+				<span class="screen-reader-text"><?php _e( 'Copy Press This Bookmarklet' ) ?></span>
+			</button>
+		</p>
+
+		<div class="hidden js-pressthis-code-wrap">
+			<p id="pressthis-code-desc">
+				<?php _e( 'If you can\'t drag it to your bookmarks, copy the following code and create new bookmark. Paste the code into the new bookmark\'s URL field.' ) ?>
+			</p>
+			<p>
+				<textarea class="js-pressthis-code" rows="5" cols="120" readonly="readonly" aria-labelledby="pressthis-code-desc"><?php echo htmlspecialchars( get_shortcut_link() ); ?></textarea>
+			</p>
+		</div>
+
+		<h4><?php _e( 'Direct link (best for mobile)' ); ?></h4>
+		<p><?php _e( 'Follow the link to open Press This. Then add it to your device\'s bookmarks or home screen.' ); ?></p>
+
+		<p>
+			<a class="button button-secondary" href="<?php echo htmlspecialchars( admin_url( 'press-this.php' ) ); ?>"><?php _e( 'Open Press This' ) ?></a>
+		</p>
+		<script>
+			jQuery( document ).ready( function( $ ) {
+				var $showPressThisWrap = $( '.js-show-pressthis-code-wrap' );
+				var $pressthisCode = $( '.js-pressthis-code' );
+
+				$showPressThisWrap.on( 'click', function( event ) {
+					var $this = $( this );
+
+					$this.parent().next( '.js-pressthis-code-wrap' ).slideToggle( 200 );
+					$this.attr( 'aria-expanded', $this.attr( 'aria-expanded' ) === 'false' ? 'true' : 'false' );
+				});
+
+				// Select Press This code when focusing (tabbing) or clicking the textarea.
+				$pressthisCode.on( 'click focus', function() {
+					var self = this;
+					setTimeout( function() { self.select(); }, 50 );
+				});
+
+			});
+		</script>
 	</div>
+	</form>
 </div>
 <?php
 endif;
Index: src/wp-includes/link-template.php
===================================================================
--- src/wp-includes/link-template.php	(revision 31531)
+++ src/wp-includes/link-template.php	(working copy)
@@ -2594,24 +2594,55 @@
  * @return string The Press This bookmarklet link URL.
  */
 function get_shortcut_link() {
-	// In case of breaking changes, version this. #WP20071
-	$link = "javascript:
-			var d=document,
-			w=window,
-			e=w.getSelection,
-			k=d.getSelection,
-			x=d.selection,
-			s=(e?e():(k)?k():(x?x.createRange().text:0)),
-			f='" . admin_url('press-this.php') . "',
-			l=d.location,
-			e=encodeURIComponent,
-			u=f+'?u='+e(l.href)+'&t='+e(d.title)+'&s='+e(s)+'&v=4';
-			a=function(){if(!w.open(u,'t','toolbar=0,resizable=1,scrollbars=1,status=1,width=720,height=570'))l.href=u;};
-			if (/Firefox/.test(navigator.userAgent)) setTimeout(a, 0); else a();
-			void(0)";
+	global $is_IE, $wp_version;
 
-	$link = str_replace(array("\r", "\n", "\t"),  '', $link);
+	$bookmarklet_version = 5;
+	$link = '';
 
+	if ( $is_IE ) {
+		/**
+		 * Return the old/shorter bookmarklet code for MSIE 8 and lower,
+		 * since they only support a max length of ~2000 characters for
+		 * bookmark[let] URLs, which is way to small for our smarter one.
+		 * Do update the version number so users do not get the "upgrade your
+		 * bookmarklet" notice when using PT in those browsers.
+		 */
+		$ua = $_SERVER['HTTP_USER_AGENT'];
+		
+		if ( ! empty( $ua ) && preg_match( '/\bMSIE (\d)/', $ua, $matches ) && (int) $matches[1] <= 8 ) {
+			$link = "javascript:
+				var d=document,
+				w=window,
+				e=w.getSelection,
+				k=d.getSelection,
+				x=d.selection,
+				s=(e?e():(k)?k():(x?x.createRange().text:0)),
+				f='" . admin_url('press-this.php') . "',
+				l=d.location,
+				e=encodeURIComponent,
+				u=f+'?u='+e(l.href)+'&t='+e(d.title)+'&s='+e(s)+'&v=" . $bookmarklet_version . "';
+				a=function(){if(!w.open(u,'t','toolbar=0,resizable=1,scrollbars=1,status=1,width=600,height=700'))l.href=u;};
+				if (/Firefox/.test(navigator.userAgent)) setTimeout(a, 0); else a();
+				void(0)";
+		}
+	}
+
+	if ( empty( $link ) ) {
+		$suffix = '.min';
+		$develop_src = false !== strpos( $wp_version, '-src' );
+
+		if ( $develop_src || ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ) {
+			$suffix = '';
+		}
+
+		$url = admin_url( 'press-this.php' ) . '?v=' . $bookmarklet_version;
+
+		$link = 'javascript:' . file_get_contents( ABSPATH . "wp-admin/js/bookmarklet$suffix.js" );
+		$link = str_replace( 'window.pt_url', wp_json_encode( $url ), $link );
+	}
+
+	$link = str_replace( array( "\r", "\n", "\t" ),  '', $link );
+
 	/**
 	 * Filter the Press This bookmarklet link.
 	 *
Index: src/wp-includes/script-loader.php
===================================================================
--- src/wp-includes/script-loader.php	(revision 31531)
+++ src/wp-includes/script-loader.php	(working copy)
@@ -439,7 +439,12 @@
 
 		$scripts->add( 'postbox', "/wp-admin/js/postbox$suffix.js", array('jquery-ui-sortable'), false, 1 );
 
-		$scripts->add( 'post', "/wp-admin/js/post$suffix.js", array('suggest', 'wp-lists', 'postbox'), false, 1 );
+		$scripts->add( 'tags-box', "/wp-admin/js/tags-box$suffix.js", array( 'jquery', 'suggest' ), false, 1 );
+		did_action( 'init' ) && $scripts->localize( 'tags-box', 'tagsBoxL10n', array(
+			'tagDelimiter' => _x( ',', 'tag delimiter' ),
+		) );
+
+		$scripts->add( 'post', "/wp-admin/js/post$suffix.js", array( 'suggest', 'wp-lists', 'postbox', 'tags-box' ), false, 1 );
 		did_action( 'init' ) && $scripts->localize( 'post', 'postL10n', array(
 			'ok' => __('OK'),
 			'cancel' => __('Cancel'),
@@ -461,11 +466,43 @@
 			'password' => __('Password Protected'),
 			'privatelyPublished' => __('Privately Published'),
 			'published' => __('Published'),
-			'comma' => _x( ',', 'tag delimiter' ),
 			'saveAlert' => __('The changes you made will be lost if you navigate away from this page.'),
 			'savingText' => __('Saving Draft&#8230;'),
 		) );
 
+		$scripts->add( 'press-this', "/wp-admin/js/press-this$suffix.js", array( 'jquery', 'tags-box' ), false, 1 );
+		did_action( 'init' ) && $scripts->localize( 'press-this', 'pressThisL10n', array(
+			/**
+			 * press_this_source_string: string displayed before the source attribution string, defaults to "Source:".
+			 *
+			 * @since 4.2
+			 * @see https://github.com/MichaelArestad/Press-This/issues/25
+			 *
+			 * @param string $string Internationalized source string
+			 *
+			 * @return string Source string
+			 */
+			'source' => apply_filters( 'press_this_source_string', __( 'Source:' ) ),
+
+			/**
+			 * press_this_source_link: HTML link format for the source attribution, can control target, class, etc
+			 *
+			 * @since 4.2
+			 * @see https://github.com/MichaelArestad/Press-This/issues/25
+			 *
+			 * @param string $link_format Internationalized link format, %1$s is link href, %2$s is link text
+			 *
+			 * @return string Link markup
+			 */
+			'sourceLink' => apply_filters( 'press_this_source_link', __( '<a href="%1$s">%2$s</a>' ) ),
+			'newPost' => __( 'Title' ),
+			'unexpectedError' => __( 'Sorry, but an unexpected error occurred.' ),
+			'saveAlert' => __( 'The changes you made will be lost if you navigate away from this page.' ),
+			'allMediaHeading' => __( 'Suggested media' ),
+			'suggestedEmbedAlt' => __( 'Suggested embed #%d' ),
+			'suggestedImgAlt' => __( 'Suggested image #%d' ),
+		) );
+		
 		$scripts->add( 'editor-expand', "/wp-admin/js/editor-expand$suffix.js", array( 'jquery' ), false, 1 );
 
 		$scripts->add( 'link', "/wp-admin/js/link$suffix.js", array( 'wp-lists', 'postbox' ), false, 1 );
@@ -633,8 +670,9 @@
 	$styles->add( 'wp-color-picker',    "/wp-admin/css/color-picker$suffix.css" );
 	$styles->add( 'customize-controls', "/wp-admin/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'ie', 'imgareaselect' ) );
 	$styles->add( 'customize-widgets',  "/wp-admin/css/customize-widgets$suffix.css", array( 'wp-admin', 'colors' ) );
+	$styles->add( 'press-this',         "/wp-admin/css/press-this$suffix.css", array( 'open-sans' ) );
+
 	$styles->add( 'ie',                 "/wp-admin/css/ie$suffix.css" );
-
 	$styles->add_data( 'ie', 'conditional', 'lte IE 7' );
 
 	// Common dependencies
