WordPress.org

Make WordPress Core

Ticket #31373: 31373.2.patch

File 31373.2.patch, 256.5 KB (added by DrewAPicture, 5 years ago)

Docs: 1st pass audit

  • src/wp-admin/admin-ajax.php

     
    6161        'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor',
    6262        'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs',
    6363        'save-user-color-scheme', 'update-widget', 'query-themes', 'parse-embed', 'set-attachment-thumbnail',
    64         'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin'
     64        'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin', 'press-this-save-post',
     65        'press-this-add-category',
    6566);
    6667
    6768// Register core Ajax calls.
  • src/wp-admin/css/forms.css

     
    684684
    685685.pressthis {
    686686        margin: 20px 0;
     687        vertical-align: top;
     688        position: relative;
     689        z-index: 1;
    687690}
    688691
    689692.pressthis a,
     
    748751        box-shadow: 0 10px 8px rgba(0, 0, 0, 0.6);
    749752}
    750753
     754.pressthis .button {
     755        margin-left: 10px;
     756        padding: 0;
     757        height: auto;
     758        vertical-align: top;
     759}
     760
     761.pressthis button .dashicons {
     762        margin: 5px 8px 6px 7px;
     763        color: #777;
     764}
     765
     766.press-this-install {
     767        margin: 20px 0 0 0;
     768        padding: 0.7em 2em 1em;
     769        max-width: 520px;
     770}
     771
     772.press-this-install textarea {
     773        width: 100%;
     774        font-size: 1em;
     775}
     776
     777.press-this-install h4 {
     778        margin: 2em 0 1em;
     779}
     780
     781
    751782/*------------------------------------------------------------------------------
    752783  20.0 - Settings
    753784------------------------------------------------------------------------------*/
  • src/wp-admin/css/press-this-editor.css

     
     1/*
     2Press This TinyMCE editor styles :)
     3*/
     4
     5
     6/**
     7* Links
     8*/
     9@import url("//fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,600,700");
     10a {
     11        color: #0074a2;
     12}
     13
     14a:visited {
     15        color: #0074a2;
     16}
     17
     18a:hover,
     19a:focus,
     20a:active {
     21        color: #2ea2cc;
     22}
     23
     24
     25/**
     26* Lists
     27*/
     28ul,
     29ol {
     30        margin: 0 0 1.5em 3em;
     31}
     32
     33ul {
     34        list-style: disc;
     35}
     36
     37ol {
     38        list-style: decimal;
     39}
     40
     41li > ul,
     42li > ol {
     43        margin-bottom: 0;
     44        margin-left: 1.5em;
     45}
     46
     47dt {
     48        font-weight: 700;
     49}
     50
     51dd {
     52        margin: 0 1.5em 1.5em;
     53}
     54
     55
     56/**
     57* Media
     58*
     59* Basic image and object styles
     60*/
     61img {
     62        max-width: 100%;
     63        height: auto;
     64}
     65
     66/* Makes sure embeds and iframes fit inside their containers */
     67embed,
     68iframe,
     69object {
     70        max-width: 100%;
     71}
     72
     73
     74/**
     75* TinyMCE styles
     76*
     77* Pretty dang good.
     78*/
     79body {
     80        color: #404040;
     81        font-family: "Open Sans", Helvetica, Arial, sans-serif;
     82        font-size: 20px;
     83        font-weight: 400;
     84        line-height: 1.6;
     85}
     86@media (max-width: 900px) {
     87        body#tinymce {
     88                padding-top: 30px !important;
     89        }
     90}
     91@media (max-width: 640px) {
     92        body {
     93                font-size: 16px;
     94        }
     95}
     96@media (max-width: 320px) {
     97        body {
     98                margin: 0 15px;
     99        }
     100}
     101
     102#tinymce b,
     103#tinymce strong {
     104        /* overrides TinyMCE's !important. Woohoo. */
     105        font-weight: 700 !important;
     106}
     107
     108blockquote {
     109        margin: 1em 1.5em;
     110        color: #9ea7af;
     111        font-size: em(25px);
     112        font-style: italic;
     113}
     114@media (max-width: 900px) {
     115        blockquote {
     116                margin: 1.5em 1em;
     117        }
     118}
     119
     120ul,
     121ol {
     122        margin: 0 0 1.5em .75em;
     123}
     124/*
     125Press This TinyMCE editor styles :)
     126*/
     127
     128
     129/**
     130* Links
     131*/
     132@import url("//fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,600,700");
     133a {
     134        color: #0074a2;
     135}
     136
     137a:visited {
     138        color: #0074a2;
     139}
     140
     141a:hover,
     142a:focus,
     143a:active {
     144        color: #2ea2cc;
     145}
     146
     147
     148/**
     149* Lists
     150*/
     151ul,
     152ol {
     153        margin: 0 0 1.5em 3em;
     154}
     155
     156ul {
     157        list-style: disc;
     158}
     159
     160ol {
     161        list-style: decimal;
     162}
     163
     164li > ul,
     165li > ol {
     166        margin-bottom: 0;
     167        margin-left: 1.5em;
     168}
     169
     170dt {
     171        font-weight: 700;
     172}
     173
     174dd {
     175        margin: 0 1.5em 1.5em;
     176}
     177
     178
     179/**
     180* Media
     181*
     182* Basic image and object styles
     183*/
     184img {
     185        max-width: 100%;
     186        height: auto;
     187}
     188
     189/* Makes sure embeds and iframes fit inside their containers */
     190embed,
     191iframe,
     192object {
     193        max-width: 100%;
     194}
     195
     196
     197/**
     198* TinyMCE styles
     199*
     200* Pretty dang good.
     201*/
     202body {
     203        color: #404040;
     204        font-family: "Open Sans", Helvetica, Arial, sans-serif;
     205        font-size: 20px;
     206        font-weight: 400;
     207        line-height: 1.6;
     208}
     209@media (max-width: 900px) {
     210        body#tinymce {
     211                padding-top: 30px !important;
     212        }
     213}
     214@media (max-width: 640px) {
     215        body {
     216                font-size: 16px;
     217        }
     218}
     219@media (max-width: 320px) {
     220        body {
     221                margin: 0 15px;
     222        }
     223}
     224
     225#tinymce b,
     226#tinymce strong {
     227        /* overrides TinyMCE's !important. Woohoo. */
     228        font-weight: 700 !important;
     229}
     230
     231blockquote {
     232        margin: 1em 1.5em;
     233        color: #9ea7af;
     234        font-size: em(25px);
     235        font-style: italic;
     236}
     237@media (max-width: 900px) {
     238        blockquote {
     239                margin: 1.5em 1em;
     240        }
     241}
     242
     243ul,
     244ol {
     245        margin: 0 0 1.5em .75em;
     246}
     247/*
     248Press This TinyMCE editor styles :)
     249*/
     250
     251
     252/**
     253* Links
     254*/
     255@import url("//fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,600,700");
     256a {
     257        color: #0074a2;
     258}
     259
     260a:visited {
     261        color: #0074a2;
     262}
     263
     264a:hover,
     265a:focus,
     266a:active {
     267        color: #2ea2cc;
     268}
     269
     270
     271/**
     272* Lists
     273*/
     274ul,
     275ol {
     276        margin: 0 0 1.5em 3em;
     277}
     278
     279ul {
     280        list-style: disc;
     281}
     282
     283ol {
     284        list-style: decimal;
     285}
     286
     287li > ul,
     288li > ol {
     289        margin-bottom: 0;
     290        margin-left: 1.5em;
     291}
     292
     293dt {
     294        font-weight: 700;
     295}
     296
     297dd {
     298        margin: 0 1.5em 1.5em;
     299}
     300
     301
     302/**
     303* Media
     304*
     305* Basic image and object styles
     306*/
     307img {
     308        max-width: 100%;
     309        height: auto;
     310}
     311
     312/* Makes sure embeds and iframes fit inside their containers */
     313embed,
     314iframe,
     315object {
     316        max-width: 100%;
     317}
     318
     319
     320/**
     321* TinyMCE styles
     322*
     323* Pretty dang good.
     324*/
     325body {
     326        color: #404040;
     327        font-family: "Open Sans", Helvetica, Arial, sans-serif;
     328        font-size: 20px;
     329        font-weight: 400;
     330        line-height: 1.6;
     331}
     332@media (max-width: 900px) {
     333        body#tinymce {
     334                padding-top: 30px !important;
     335        }
     336}
     337@media (max-width: 640px) {
     338        body {
     339                font-size: 16px;
     340        }
     341}
     342@media (max-width: 320px) {
     343        body {
     344                margin: 0 15px;
     345        }
     346}
     347
     348#tinymce b,
     349#tinymce strong {
     350        /* overrides TinyMCE's !important. Woohoo. */
     351        font-weight: 700 !important;
     352}
     353
     354blockquote {
     355        margin: 1em 1.5em;
     356        color: #9ea7af;
     357        font-size: em(25px);
     358        font-style: italic;
     359}
     360@media (max-width: 900px) {
     361        blockquote {
     362                margin: 1.5em 1em;
     363        }
     364}
     365
     366ul,
     367ol {
     368        margin: 0 0 1.5em .75em;
     369}
     370/*
     371Press This TinyMCE editor styles :)
     372*/
     373
     374
     375/**
     376* Links
     377*/
     378@import url("//fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,600,700");
     379a {
     380        color: #0074a2;
     381}
     382
     383a:visited {
     384        color: #0074a2;
     385}
     386
     387a:hover,
     388a:focus,
     389a:active {
     390        color: #2ea2cc;
     391}
     392
     393
     394/**
     395* Lists
     396*/
     397ul,
     398ol {
     399        margin: 0 0 1.5em 3em;
     400}
     401
     402ul {
     403        list-style: disc;
     404}
     405
     406ol {
     407        list-style: decimal;
     408}
     409
     410li > ul,
     411li > ol {
     412        margin-bottom: 0;
     413        margin-left: 1.5em;
     414}
     415
     416dt {
     417        font-weight: 700;
     418}
     419
     420dd {
     421        margin: 0 1.5em 1.5em;
     422}
     423
     424
     425/**
     426* Media
     427*
     428* Basic image and object styles
     429*/
     430img {
     431        max-width: 100%;
     432        height: auto;
     433}
     434
     435/* Makes sure embeds and iframes fit inside their containers */
     436embed,
     437iframe,
     438object {
     439        max-width: 100%;
     440}
     441
     442
     443/**
     444* TinyMCE styles
     445*
     446* Pretty dang good.
     447*/
     448body {
     449        color: #404040;
     450        font-family: "Open Sans", Helvetica, Arial, sans-serif;
     451        font-size: 20px;
     452        font-weight: 400;
     453        line-height: 1.6;
     454}
     455@media (max-width: 900px) {
     456        body#tinymce {
     457                padding-top: 30px !important;
     458        }
     459}
     460@media (max-width: 640px) {
     461        body {
     462                font-size: 16px;
     463        }
     464}
     465@media (max-width: 320px) {
     466        body {
     467                margin: 0 15px;
     468        }
     469}
     470
     471#tinymce b,
     472#tinymce strong {
     473        /* overrides TinyMCE's !important. Woohoo. */
     474        font-weight: 700 !important;
     475}
     476
     477blockquote {
     478        margin: 1em 1.5em;
     479        color: #9ea7af;
     480        font-size: em(25px);
     481        font-style: italic;
     482}
     483@media (max-width: 900px) {
     484        blockquote {
     485                margin: 1.5em 1em;
     486        }
     487}
     488
     489ul,
     490ol {
     491        margin: 0 0 1.5em .75em;
     492}
  • src/wp-admin/css/press-this.css

     
    1 .press-this #message {
    2         border-left: 4px solid #7ad03a;
    3         padding: 1px 12px;
    4         background-color: #fff;
    5         -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,0.1);
    6         box-shadow: 0 1px 1px 0 rgba(0,0,0,0.1);
     1/*
     2Press This styles :)
     3*/
     4
     5
     6/**
     7* Normalize
     8*
     9* normalize.css v3.0.0 | MIT License | git.io/normalize
     10*/
     11html {
     12        font-family: sans-serif;
     13        -ms-text-size-adjust: 100%;
     14        -webkit-text-size-adjust: 100%;
    715}
    816
    9 .press-this #side-sortables .category-tabs li {
    10         display: inline;
    11         line-height: 1.35em;
     17body {
     18        margin: 0;
    1219}
    1320
    14 body.press-this ul.category-tabs li.tabs a {
    15         color: #32373c;
     21*,
     22*:before,
     23*:after {
     24        -webkit-box-sizing: border-box;
     25        -moz-box-sizing: border-box;
     26        box-sizing: border-box;
    1627}
     28@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) {
     29        *,
     30        *:before,
     31        *:after {
     32                -webkit-font-smoothing: antialiased;
     33        }
     34}
    1735
    18 .press-this #content-resize-handle {
    19         bottom: 2px;
     36article,
     37aside,
     38details,
     39figcaption,
     40figure,
     41footer,
     42header,
     43hgroup,
     44main,
     45nav,
     46section,
     47summary {
     48        display: block;
    2049}
    2150
    22 body.press-this {
    23         color: #32373c;
    24         margin: 0;
    25         padding: 0;
    26         min-width: 708px;
    27         min-height: 400px;
     51audio,
     52canvas,
     53progress,
     54video {
     55        display: inline-block;
     56        vertical-align: baseline;
    2857}
    2958
    30 .press-this #titlediv #title {
    31         font-size: 1.4em;
     59audio:not([controls]) {
     60        display: none;
     61        height: 0;
    3262}
    3363
    34 .press-this #site-heading:before {
    35     top: 3px;
    36     position: relative;
    37     display: inline-block;
    38     font: normal 18px/1 'dashicons';
    39     speak: none;
    40     color: #727272;
    41     content: '\f120';
    42     -webkit-font-smoothing: antialiased;
    43     -moz-osx-font-smoothing: grayscale;
     64[hidden],
     65template {
     66        display: none;
    4467}
    4568
    46 .press-this #wphead {
    47         height: 32px;
    48         margin-left: 0;
    49         margin-right: 0;
    50         margin-bottom: 5px;
     69a {
     70        background: transparent;
    5171}
    5272
    53 .press-this #header-logo {
    54         float: left;
    55         margin: 7px 7px 0;
    56         -webkit-user-select: none;
    57         -moz-user-select: none;
    58         -ms-user-select: none;
    59         user-select: none;
     73a:active,
     74a:hover {
     75        outline: 0;
    6076}
    6177
    62 .press-this #wphead h1 {
    63         font-weight: normal;
    64         font-size: 16px;
    65         line-height: 32px;
    66         margin: 0;
    67         float: left;
     78abbr[title] {
     79        border-bottom: 1px dotted;
    6880}
    6981
    70 .press-this #wphead h1 a {
    71         text-decoration: none;
     82b,
     83strong {
     84        font-weight: bold;
    7285}
    7386
    74 .press-this #wphead h1 a:hover {
    75         text-decoration: underline;
     87dfn {
     88        font-style: italic;
    7689}
    7790
    78 .press-this #message {
    79         margin: 10px 0;
     91h1 {
     92        font-size: 2em;
     93        margin: 0.67em 0;
    8094}
    8195
    82 .press-this .posting {
    83         margin-right: 250px;
     96mark {
     97        background: #ff0;
     98        color: #000;
    8499}
    85100
    86 .press-this-sidebar {
    87         float: right;
    88         width: 240px;
    89         padding-top: 10px;
     101small {
     102        font-size: 80%;
    90103}
    91104
    92 .press-this #title {
    93         margin-left: 0;
    94         margin-right: 0;
    95         -webkit-box-sizing: border-box;
    96         -moz-box-sizing: border-box;
    97         box-sizing: border-box;
     105sub,
     106sup {
     107        font-size: 75%;
     108        line-height: 0;
     109        position: relative;
     110        vertical-align: baseline;
    98111}
    99112
    100 .press-this .tagchecklist {
    101         margin-top: 8px;
     113sup {
     114        top: -0.5em;
    102115}
    103116
    104 .press-this #titlediv {
    105         margin: 0;
     117sub {
     118        bottom: -0.25em;
    106119}
    107120
    108 .press-this #wp-content-wrap #wp-content-editor-tools {
    109         padding: 0;
    110         top: 3px;
     121img {
     122        border: 0;
     123}
     124
     125svg:not(:root) {
    111126        overflow: hidden;
    112127}
    113128
    114 .press-this .wp-media-buttons {
     129figure {
     130        margin: 1em 40px;
     131}
     132
     133hr {
     134        -webkit-box-sizing: content-box;
     135        -moz-box-sizing: content-box;
     136        box-sizing: content-box;
     137        height: 0;
     138}
     139
     140pre {
     141        overflow: auto;
     142}
     143
     144code,
     145kbd,
     146pre,
     147samp {
     148        font-family: monospace, monospace;
     149        font-size: 1em;
     150}
     151
     152button,
     153input,
     154optgroup,
     155select,
     156textarea {
     157        color: inherit;
     158        font: inherit;
     159        margin: 0;
     160}
     161
     162button {
     163        overflow: visible;
     164}
     165
     166button,
     167select {
     168        text-transform: none;
     169}
     170
     171button,
     172html input[type="button"],
     173input[type="reset"],
     174input[type="submit"] {
     175        -webkit-appearance: button;
     176        cursor: pointer;
     177}
     178
     179button[disabled],
     180html input[disabled] {
    115181        cursor: default;
    116         padding: 8px 8px 6px;
    117182}
    118183
    119 .press-this #wp-content-wrap #wp-content-media-buttons a {
     184button::-moz-focus-inner,
     185input::-moz-focus-inner {
     186        border: 0;
    120187        padding: 0;
     188}
     189
     190input {
    121191        line-height: normal;
     192}
     193
     194input[type="checkbox"],
     195input[type="radio"] {
     196        -webkit-box-sizing: border-box;
     197        -moz-box-sizing: border-box;
     198        box-sizing: border-box;
     199        padding: 0;
     200}
     201
     202input[type="number"]::-webkit-inner-spin-button,
     203input[type="number"]::-webkit-outer-spin-button {
    122204        height: auto;
    123         font-size: 16px;
    124205}
    125206
    126 .press-this #wp-content-wrap .mce-toolbar .mce-btn-group .mce-btn {
    127         margin: 0 1px;
     207input[type="search"] {
     208        -webkit-appearance: textfield;
     209        -webkit-box-sizing: content-box;
     210        -moz-box-sizing: content-box;
     211        box-sizing: content-box;
    128212}
    129213
    130 .press-this #wp-content-wrap .mce-toolbar .mce-btn button {
    131         padding: 2px 3px;
     214input[type="search"]::-webkit-search-cancel-button,
     215input[type="search"]::-webkit-search-decoration {
     216        -webkit-appearance: none;
    132217}
    133218
    134 .press-this #wp-content-wrap div.mce-toolbar-grp,
    135 .press-this #wp-content-wrap .quicktags-toolbar {
    136         padding-right: 3px;
     219fieldset {
     220        border: 1px solid #c0c0c0;
     221        margin: 0 2px;
     222        padding: 0.35em 0.625em 0.75em;
    137223}
    138224
    139 .press-this .howto {
    140         margin-top: 2px;
    141         margin-bottom: 3px;
    142         font-size: 12px;
    143         font-style: italic;
    144         display: block;
     225legend {
     226        border: 0;
     227        padding: 0;
    145228}
    146229
    147 .press-this #wp-content-editor-container {
    148         clear: none;
     230textarea {
     231        overflow: auto;
    149232}
    150233
    151 .press-this #poststuff .inside {
    152         margin-top: 18px;
     234optgroup {
     235        font-weight: bold;
    153236}
    154237
    155 .press-this .category-tabs {
    156         margin-bottom: 3px;
     238table {
     239        border-collapse: collapse;
     240        border-spacing: 0;
    157241}
    158242
    159 /* Editor/Main Column */
    160 .press-this #poststuff {
    161         margin: 0 8px;
     243td,
     244th {
    162245        padding: 0;
    163246}
    164247
    165 .press-this #photo-add-url-div input[type="text"] {
    166         width: 220px;
     248.clearfix:before,
     249.clearfix:after {
     250        content: "";
     251        display: table;
    167252}
     253.clearfix:after {
     254        clear: both;
     255}
    168256
    169 #poststuff #editor-toolbar {
    170         height: 30px;
     257.hide-if-js {
     258        display: none;
    171259}
    172260
    173 .posting {
    174         margin-right: 212px;
    175         position: relative;
     261.screen-reader-text,
     262.taghint {
     263        position: absolute;
     264        margin: -1px;
     265        padding: 0;
     266        height: 1px;
     267        width: 1px;
     268        overflow: hidden;
     269        clip: rect(0 0 0 0);
     270        border: 0;
    176271}
    177272
    178 .press-this .inner-sidebar {
    179         width: 200px;
     273
     274/**
     275* Typography
     276*
     277* Base element typographic styles.
     278*/
     279body,
     280button,
     281input,
     282select,
     283textarea {
     284        color: #404040;
     285        font-family: "Open Sans", Helvetica, Arial, sans-serif;
     286        font-size: 20px;
     287        font-weight: 400;
     288        line-height: 1.6;
    180289}
    181290
    182 .press-this .inner-sidebar .sleeve {
    183         padding-top: 5px;
     291h1,
     292h2,
     293h3,
     294h4,
     295h5,
     296h6 {
     297        clear: both;
    184298}
    185299
    186 .press-this #submitdiv p {
     300p {
     301        margin-bottom: 1.5em;
     302}
     303
     304b,
     305strong {
     306        font-weight: 700;
     307}
     308
     309
     310/**
     311* Buttons
     312*
     313* Pushing buttons is what I do.
     314*/
     315.button-primary,
     316.button-subtle,
     317.scan-submit {
     318        display: inline-block;
    187319        margin: 0;
    188         padding: 6px;
     320        padding: 0 10px 1px;
     321        border-width: 1px;
     322        border-style: solid;
     323        -webkit-border-radius: 3px;
     324        border-radius: 3px;
     325        font-size: 13px;
     326        line-height: 2;
     327        text-decoration: none;
     328        white-space: nowrap;
     329        cursor: pointer;
     330        -webkit-appearance: none;
    189331}
    190332
    191 .press-this #submitdiv #publishing-actions {
    192         border-bottom: 1px solid #dfdfdf;
     333.button-primary {
     334        background: #2ea2cc;
     335        border-color: #2581a2;
     336        color: #fff;
    193337}
    194338
    195 .press-this #publish {
    196         float: right;
     339.button-primary:hover,
     340.button-primary:focus {
     341        background: #2991b7;
     342        border-color: #20708e;
     343        color: #fff;
     344        outline: 0;
    197345}
    198346
    199 .press-this #poststuff h2,
    200 .press-this #poststuff h3 {
    201         font-size: 14px;
    202         line-height: 1;
     347.button-primary:active {
     348        background: #2581a2;
     349        border-color: #20708e;
     350        color: #fff;
    203351}
    204352
    205 .press-this #tagsdiv-post_tag h3,
    206 .press-this #categorydiv h3 {
    207         cursor: pointer;
     353.button-primary[disabled],
     354.button-primary:disabled {
     355        color: #c7ced1 !important;
     356        background: #2688ab !important;
     357        border-color: #20708e !important;
    208358}
    209359
    210 .press-this #submitdiv h3 {
    211         cursor: default;
     360.button-primary:visited {
     361        color: #fff;
    212362}
    213363
    214 h3.tb {
    215         font-weight: 600;
    216         font-size: 12px;
    217         margin-left: 5px;
     364.button-subtle {
     365        background: none;
     366        border: 0;
     367        color: #0074a2;
    218368}
    219369
    220 .press-this .postbox,
    221 .press-this .stuffbox {
    222         margin-bottom: 10px;
    223         min-width: 0;
     370.button-subtle:visited {
     371        color: #0074a2;
    224372}
    225373
    226 .press-this #submitdiv:hover .handlediv {
     374.button-subtle:focus,
     375.button-subtle:hover,
     376.button-subtle:active {
     377        color: #2ea2cc;
     378}
     379
     380.button-subtle:focus,
     381.button-subtle:active {
     382        outline: 0;
     383        text-decoration: underline;
     384}
     385
     386.button-reset {
     387        margin: 0;
     388        padding: 0;
     389        border: 0;
    227390        background: none;
     391        cursor: pointer;
     392        -webkit-appearance: none;
    228393}
    229394
    230 .tbtitle {
    231         font-size: 1.7em;
    232         outline: none;
    233         padding: 3px 4px;
    234         border: 1px solid #dfdfdf;
     395.button-reset:focus {
     396        outline: 0;
    235397}
    236398
    237 .press-this .actions {
    238         float: right;
    239         margin: -19px 0 0;
     399
     400/**
     401* Forms
     402*
     403* So many input types.
     404*/
     405button,
     406input,
     407select,
     408textarea {
     409        font-size: 100%;
     410        margin: 0;
     411        vertical-align: baseline;
     412        *vertical-align: middle;
    240413}
    241414
    242 .press-this #extra-fields .actions {
    243         margin: -32px -7px 0 0;
     415[type="checkbox"],
     416[type="radio"] {
     417        padding: 0;
    244418}
    245419
    246 .press-this .actions li {
    247         float: left;
    248         list-style: none;
    249         margin-right: 10px;
     420[type="search"] {
     421        -webkit-appearance: textfield;
     422        -webkit-box-sizing: content-box;
     423        -moz-box-sizing: content-box;
     424        box-sizing: content-box;
    250425}
    251426
    252 #extra-fields .button {
    253         margin-right: 5px;
     427[type="search"]::-webkit-search-decoration {
     428        -webkit-appearance: none;
    254429}
    255430
    256 /* Photo Styles */
    257 #photo_saving {
    258         margin: 0 8px 8px;
    259         vertical-align: middle;
     431button::-moz-focus-inner,
     432input::-moz-focus-inner {
     433        border: 0;
     434        padding: 0;
    260435}
    261436
    262 #img_container_container {
     437[type="text"],
     438[type="email"],
     439[type="url"],
     440[type="password"],
     441[type="search"],
     442textarea {
     443        padding: 0.4em 0.75em;
     444        color: #333;
     445        border: 1px solid #ccc;
     446}
     447
     448[type="text"]:focus,
     449[type="email"]:focus,
     450[type="url"]:focus,
     451[type="password"]:focus,
     452[type="search"]:focus,
     453textarea:focus {
     454        color: #333;
     455        outline: 0;
     456}
     457
     458textarea {
    263459        overflow: auto;
     460        padding-left: 3px;
     461        vertical-align: top;
    264462}
    265463
    266 #extra-fields {
    267         margin-top: 10px;
     464
     465/**
     466* Links
     467*/
     468a {
     469        color: #0074a2;
     470}
     471
     472a:visited {
     473        color: #0074a2;
     474}
     475
     476a:hover,
     477a:focus,
     478a:active {
     479        color: #2ea2cc;
     480}
     481
     482
     483/**
     484* Lists
     485*/
     486ul,
     487ol {
     488        margin: 0 0 1.5em 3em;
     489}
     490
     491ul {
     492        list-style: disc;
     493}
     494
     495ol {
     496        list-style: decimal;
     497}
     498
     499li > ul,
     500li > ol {
     501        margin-bottom: 0;
     502        margin-left: 1.5em;
     503}
     504
     505dt {
     506        font-weight: 700;
     507}
     508
     509dd {
     510        margin: 0 1.5em 1.5em;
     511}
     512
     513
     514/**
     515* Post formats
     516*
     517* Complete styles for post formats UI
     518*/
     519/* TODO if we remove the <br> during merge, this can go. */
     520#post-formats-select br {
     521        display: none;
     522}
     523
     524/* TODO Needed after merge? */
     525.post-format {
     526        width: 0;
     527        height: 0;
     528        position: absolute;
     529        top: -9999px;
     530}
     531
     532.lt-ie9 .post-format {
     533        margin: 17px 12px 0 13px;
     534        width: auto;
     535        height: auto;
     536        position: static;
     537        top: auto;
     538        float: left;
     539        width: 16px;
     540        height: 16px;
     541}
     542
     543.post-format-icon {
    268544        position: relative;
     545        display: block;
     546        padding: 13px 2px 14px 13px;
     547        cursor: pointer;
    269548}
    270549
    271 #extra-fields h2 {
    272         margin: 12px;
     550.post-format-icon:before,
     551.post-format-icon:after {
     552        content: "";
     553        display: inline-block;
     554        width: 20px;
     555        height: 20px;
     556        margin-right: 10px;
     557        font-size: 20px;
     558        line-height: 1;
     559        font-family: dashicons;
     560        text-decoration: inherit;
     561        color: #9ea7af;
     562        font-weight: 400;
     563        font-style: normal;
     564        vertical-align: top;
     565        text-align: center;
     566        -webkit-transition: color .1s ease-in 0;
     567        transition: color .1s ease-in 0;
     568        -webkit-font-smoothing: antialiased;
     569        -moz-osx-font-smoothing: grayscale;
    273570}
    274571
    275 #waiting {
    276         margin-top: 10px;
    277         overflow: hidden;
     572.post-format-icon:before {
     573        content: "\f109";
    278574}
    279575
    280 #waiting span {
     576.post-format-icon:after {
     577        display: none;
     578        content: "\f147";
    281579        float: right;
    282         margin: 0 0 0 5px;
    283580}
    284581
    285 #waiting .spinner {
     582.post-format:checked + .post-format-icon {
     583        -webkit-box-shadow: inset 6px 0 0 #2ea2cc;
     584        box-shadow: inset 6px 0 0 #2ea2cc;
     585        background: rgba(46, 162, 204, 0.1);
     586}
     587
     588.post-format:checked + .post-format-icon:before,
     589.post-format:checked + .post-format-icon:after {
     590        color: #333;
     591}
     592
     593.post-format:focus + .post-format-icon {
     594        background: #2ea2cc;
     595        color: #fff;
     596}
     597
     598.post-format:focus + .post-format-icon:before,
     599.post-format:focus + .post-format-icon:after {
     600        color: #fff;
     601}
     602
     603.post-format:checked + .post-format-icon:after {
    286604        display: block;
    287605}
    288606
    289 #extra-fields .postbox {
    290         margin-bottom: 5px;
     607.lt-ie9 .post-format-icon {
     608        margin-left: 16px;
    291609}
    292610
    293 #extra-fields .titlewrap {
     611.post-format-aside:before {
     612        content: "\f123";
     613}
     614
     615.post-format-image:before {
     616        content: "\f128";
     617}
     618
     619.post-format-video:before {
     620        content: "\f126";
     621}
     622
     623.post-format-audio:before {
     624        content: "\f127";
     625}
     626
     627.post-format-quote:before {
     628        content: "\f122";
     629}
     630
     631.post-format-link:before {
     632        content: "\f103";
     633}
     634
     635.post-format-gallery:before {
     636        content: "\f161";
     637}
     638
     639
     640/**
     641* Tags
     642*
     643* Complete styles for tags UI
     644*/
     645.tagsdiv p {
     646        margin: 0;
     647}
     648
     649.tagsdiv .ajaxtag {
     650        position: relative;
     651}
     652
     653.tagsdiv .newtag {
     654        display: block;
     655        position: relative;
     656        padding: 11px 58px 11px 16px;
     657        width: 100%;
     658        border: 0;
     659        border-bottom: 1px solid #e5e5e5;
     660        font-size: 16px;
     661}
     662
     663.tagsdiv .tagadd {
     664        position: absolute;
     665        top: 0;
     666        right: 0;
     667        bottom: 1px;
     668        border: 0;
     669        -webkit-border-radius: 0;
     670        border-radius: 0;
     671        padding: 0 16px;
     672        background: #f7f7f7;
     673        border-left: 1px solid #f1f1f1;
     674}
     675
     676.tagsdiv .tagadd:hover,
     677.tagsdiv .tagadd:active,
     678.tagsdiv .tagadd:focus {
     679        outline: 0;
     680        background: #2991b7;
     681        border-color: #20708e;
     682        color: #fff;
     683}
     684
     685.tagsdiv .howto {
     686        color: #727272;
     687        font-style: italic;
     688        margin: 10px 0 6px 16px;
     689}
     690
     691
     692/* Tag hint TODO needed? */
     693/* Tag suggestions */
     694.ac_results {
    294695        padding: 0;
    295         overflow: auto;
    296         height: 120px;
     696        margin: -1px 0 0 -1px;
     697        list-style: none;
     698        position: absolute;
     699        z-index: 10000;
     700        display: none;
     701        border: 1px solid #d8d8d8;
     702        background-color: #fff;
     703        font-size: 14px;
    297704}
    298705
    299 #img_container a {
     706.ac_results li {
     707        padding: 6px 16px;
     708        white-space: nowrap;
     709        color: #101010;
     710        text-align: left;
     711}
     712
     713.ac_results .ac_over {
     714        background-color: #e5e5e5;
     715        background-color: #2ea2cc;
     716        color: #fff;
     717        cursor: pointer;
     718}
     719
     720.ac_match {
     721        text-decoration: underline;
     722}
     723
     724/* Tags */
     725.tagchecklist {
     726        padding: 16px 28px 5px;
     727}
     728
     729.tagchecklist:before,
     730.tagchecklist:after {
     731        content: "";
     732        display: table;
     733}
     734
     735.tagchecklist:after {
     736        clear: both;
     737}
     738
     739.tagchecklist span {
    300740        display: block;
     741        margin-right: 25px;
    301742        float: left;
     743        font-size: 13px;
     744        line-height: 1.8;
     745        white-space: nowrap;
     746        cursor: default;
     747}
     748
     749@media (max-width: 600px) {
     750        .tagchecklist span {
     751                margin-bottom: 15px;
     752                font-size: 16px;
     753                line-height: 1.3;
     754        }
     755}
     756
     757.tagchecklist .ntdelbutton {
     758        margin: 1px 0 0 -17px;
     759        cursor: pointer;
     760        width: 20px;
     761        height: 20px;
     762        display: block;
     763        float: left;
     764        text-indent: 0;
    302765        overflow: hidden;
     766        position: absolute;
     767        outline: 0;
    303768}
    304769
    305 #img_container img,
    306 #img_container a {
    307         width: 68px;
    308         height: 68px;
     770.tagchecklist .ntdelbutton:before {
     771        content: '\f153';
     772        display: block;
     773        margin: 2px 0;
     774        height: 20px;
     775        width: 20px;
     776        background: 0 0;
     777        color: #9ea7af;
     778        font: 400 16px/1 dashicons;
     779        text-align: center;
     780        speak: none;
     781        -webkit-font-smoothing: antialiased;
    309782}
    310783
    311 #img_container img {
     784.tagchecklist .ntdelbutton:focus:before {
     785        color: #2ea2cc;
     786}
     787
     788
     789/* THE TAG CLOUD. */
     790.tagsdiv + p {
     791        margin: 0;
     792}
     793
     794.tagcloud-link {
     795        display: block;
     796        padding: 0 16px;
     797        text-decoration: none;
     798        outline: 0;
     799}
     800
     801.tagcloud-link:focus {
     802        text-decoration: underline;
     803}
     804
     805.popular-tags {
    312806        border: none;
    313         background-color: #f4f4f4;
     807        line-height: 2em;
     808        padding: 8px 12px 12px;
     809        text-align: justify;
     810}
     811
     812.popular-tags a {
     813        padding: 0 3px;
     814}
     815
     816.the-tagcloud {
     817        margin: 0;
     818        padding: 16px;
     819}
     820
     821.the-tagcloud a {
     822        text-decoration: none;
     823        outline: 0;
     824}
     825
     826.the-tagcloud a:focus {
     827        text-decoration: underline;
     828}
     829
     830.tagcloud h3 {
     831        margin: 2px 0 12px;
     832}
     833
     834
     835/**
     836* Categories
     837*
     838* Complete styles for post categories UI
     839*/
     840input[type="search"].categories-search,
     841.add-category-name {
     842        display: block;
     843        width: 100%;
     844        padding: 0.85714em 1.07143em;
     845        border: 0;
     846        -webkit-border-radius: 0;
     847        border-radius: 0;
     848        border-bottom: 1px solid #e5e5e5;
     849        font-size: 14px;
     850        -webkit-appearance: none;
     851        appearance: none;
     852}
     853
     854@media (max-width: 600px) {
     855        input[type="search"].categories-search,
     856        .add-category-name {
     857                /* Needs to be 16px to prevent zooming on iOS. Guh. */
     858                font-size: 16px;
     859        }
     860}
     861
     862.add-cat-toggle {
     863        float: right;
     864        margin-top: -33px;
     865}
     866
     867.add-cat-toggle:focus {
     868        text-decoration: none;
     869        color: #2ea2cc;
     870}
     871
     872.add-cat-toggle.is-toggled {
     873        margin-top: -36px;
     874}
     875
     876.add-cat-toggle.is-toggled .dashicons:before {
     877        content: "\f179";
     878}
     879
     880.add-category {
     881        position: relative;
     882        border-bottom: 1px solid #e5e5e5;
     883}
     884
     885.add-category.is-hidden {
     886        display: none;
     887}
     888
     889.add-category .add-cat-submit {
     890        position: absolute;
     891        top: 0;
     892        right: 0;
     893        border: 0;
     894        -webkit-border-radius: 0;
     895        border-radius: 0;
     896        padding: 12px 16px;
     897        background: #f7f7f7;
     898        border-left: 1px solid #f1f1f1;
     899}
     900
     901.add-category .add-cat-submit:hover,
     902.add-category .add-cat-submit:active,
     903.add-category .add-cat-submit:focus {
     904        outline: 0;
     905        background: #2991b7;
     906        border-color: #20708e;
     907        color: #fff;
     908}
     909
     910/* Parent category select */
     911.postform-wrapper {
     912        padding: 12px;
     913}
     914
     915.postform {
     916        display: block;
     917        margin: 0;
     918        width: 100%;
     919        height: 34px;
     920        border: 0;
     921        -webkit-border-radius: 0;
     922        border-radius: 0;
     923        border: 1px solid #e5e5e5;
     924        background: #fff;
     925        -webkit-background-size: 20px 20px;
     926        background-size: 20px 20px;
     927        overflow: hidden;
     928        line-height: 21px;
     929        text-overflow: ellipsis;
     930        text-decoration: none;
     931        vertical-align: top;
     932        white-space: nowrap;
    314933        cursor: pointer;
     934        outline: 0;
    315935}
    316936
    317 #img_container a,
    318 #img_container a:link,
    319 #img_container a:visited {
    320         border: 1px solid #ccc;
     937.postform:focus {
     938        border-color: #0074a2;
     939        -webkit-box-shadow: 0 0 0 3px #2ea2cc;
     940        box-shadow: 0 0 0 3px #2ea2cc;
     941        outline: 0;
     942        -moz-outline: none;
     943        -moz-user-focus: ignore;
     944}
     945
     946.postform::-ms-expand {
     947        display: none;
     948}
     949
     950.postform::-ms-value {
     951        background: none;
     952        color: #727272;
     953}
     954
     955.postform:-moz-focusring {
     956        color: transparent;
     957        text-shadow: 0 0 0 #727272;
     958}
     959
     960/* Category list */
     961.categories-select {
     962        margin: 0;
     963        padding: 0;
     964        list-style: none;
     965}
     966
     967.categories-select ul {
     968        margin: 0;
     969        padding: 0;
     970        list-style: none;
     971}
     972
     973.categories-select input {
     974        clear: none;
     975        position: absolute;
     976        top: 0;
     977        left: 0;
    321978        display: block;
     979        line-height: 0;
     980        width: 100%;
     981        height: 100%;
     982        outline: 0;
     983        padding: 0;
     984        border: 0;
     985        -webkit-border-radius: 0;
     986        border-radius: 0;
     987        text-align: center;
     988        vertical-align: middle;
     989        -webkit-appearance: none;
     990        appearance: none;
     991        cursor: pointer;
     992}
     993
     994.categories-select input:checked {
     995        -webkit-box-shadow: inset 6px 0 0 #2ea2cc;
     996        box-shadow: inset 6px 0 0 #2ea2cc;
     997        background: rgba(46, 162, 204, 0.1);
     998}
     999
     1000.categories-select input:checked:after {
     1001        display: inline-block;
     1002        content: "\f147";
     1003        position: absolute;
     1004        top: 13px;
     1005        right: 0;
     1006        width: 20px;
     1007        height: 20px;
     1008        margin-right: 10px;
     1009        font-size: 20px;
     1010        line-height: 1;
     1011        font-family: dashicons;
     1012        text-decoration: inherit;
     1013        color: #222;
     1014        font-weight: 400;
     1015        font-style: normal;
     1016        vertical-align: top;
     1017        text-align: center;
     1018        -webkit-transition: color .1s ease-in 0;
     1019        transition: color .1s ease-in 0;
     1020        -webkit-font-smoothing: antialiased;
     1021        -moz-osx-font-smoothing: grayscale;
     1022}
     1023
     1024.categories-select input:focus {
     1025        -webkit-box-shadow: inset 6px 0 0 #2ea2cc;
     1026        box-shadow: inset 6px 0 0 #2ea2cc;
     1027        background: rgba(46, 162, 204, 0.05);
     1028}
     1029
     1030.categories-select label {
    3221031        position: relative;
     1032        display: block;
     1033        padding: 13px 16px 14px 16px;
     1034        cursor: pointer;
     1035        background: #fff;
    3231036}
    3241037
    325 #img_container a:hover,
    326 #img_container a:active {
    327         border-color: #000;
    328         z-index: 1000;
    329         border-width: 1px;
     1038.categories-select ul label {
     1039        padding-left: 24px;
    3301040}
    3311041
    332 /* Video */
    333 #embed-code {
     1042.categories-select ul ul label {
     1043        padding-left: 32px;
     1044}
     1045
     1046.categories-select ul ul ul label {
     1047        padding-left: 40px;
     1048}
     1049
     1050.categories-select ul ul ul ul label {
     1051        padding-left: 48px;
     1052}
     1053
     1054.categories-select ul ul ul ul ul label {
     1055        padding-left: 56px;
     1056}
     1057
     1058.categories-select ul ul ul ul ul ul label {
     1059        padding-left: 64px;
     1060}
     1061
     1062.categories-select .is-hidden {
     1063        display: none;
     1064}
     1065
     1066.categories-select .is-hidden.searched-parent {
     1067        display: block;
     1068}
     1069
     1070.lt-ie9 .categories-select input {
     1071        top: 50%;
     1072        right: 10px;
     1073        left: auto;
     1074        margin-top: -8px;
     1075        width: 16px;
     1076        height: 16px;
     1077}
     1078
     1079/* TODO Reformats checkbox on Firefox until we remove checkbox in merge */
     1080@-moz-document url-prefix() {
     1081        .categories-select input {
     1082                top: 50%;
     1083                right: 10px;
     1084                left: auto;
     1085                margin-top: -8px;
     1086                width: 16px;
     1087                height: 16px;
     1088        }
     1089}
     1090
     1091/* Category search */
     1092.categories-search-wrapper {
     1093        position: relative;
     1094}
     1095
     1096.categories-search-wrapper.is-hidden {
     1097        display: none;
     1098}
     1099
     1100.categories-search-wrapper label {
     1101        position: absolute;
     1102        top: 50%;
     1103        right: 10px;
     1104        margin-top: -10px;
     1105        color: #9ea7af;
     1106}
     1107
     1108
     1109/**
     1110* Main
     1111*/
     1112html,
     1113body {
     1114        overflow-x: hidden;
     1115}
     1116
     1117@media (min-width: 901px) {
     1118        html,
     1119        body {
     1120                height: 100%;
     1121        }
     1122}
     1123
     1124html {
     1125        background: #fff;
     1126        -webkit-box-shadow: -10px 0 0 rgba(0, 0, 0, 0.3);
     1127        box-shadow: -10px 0 0 rgba(0, 0, 0, 0.3);
     1128}
     1129
     1130@media (max-width: 900px) {
     1131        body {
     1132                font-size: 16px;
     1133        }
     1134}
     1135
     1136@media (max-width: 320px) {
     1137        body {
     1138                font-size: 14px;
     1139        }
     1140}
     1141
     1142.lt-ie9 {
     1143        overflow: visible;
     1144}
     1145
     1146.adminbar {
     1147        position: relative;
    3341148        width: 100%;
    335         height: 98px;
     1149        padding: 0 0.8em;
     1150        min-height: 3.2em;
     1151        background: #222;
     1152        color: #fff;
     1153        z-index: 9999;
    3361154}
    3371155
    338 /* Categories */
    339 .press-this .categorydiv div.tabs-panel {
    340         height: 100px;
     1156.adminbar:before,
     1157.adminbar:after {
     1158        content: "";
     1159        display: table;
    3411160}
    3421161
    343 /* Tags */
    344 .press-this .tagsdiv .newtag {
    345         width: 120px;
     1162.adminbar:after {
     1163        clear: both;
    3461164}
    3471165
    348 .press-this #content {
    349         margin: 5px 0;
    350         padding: 0 5px;
    351         border: 0 none;
    352         height: 340px;
    353         font-family: Consolas, Monaco, monospace;
    354         font-size: 13px;
    355         line-height: 19px;
    356         background: transparent;
     1166.adminbar .dashicons {
     1167        color: #999;
    3571168}
    3581169
    359 /* Submit */
    360 .press-this #publishing-actions .spinner {
    361         display: inline;
     1170.adminbar button {
     1171        position: absolute;
     1172        top: 50%;
     1173        right: 6px;
     1174        margin-top: -13px;
     1175}
     1176
     1177@media (max-width: 320px) {
     1178        .adminbar {
     1179                min-height: 45px;
     1180        }
     1181}
     1182
     1183.current-site {
     1184        margin-top: 0.5625em;
     1185        font-size: 16px;
     1186        line-height: 44px;
     1187        font-weight: 400;
     1188        overflow: hidden;
     1189        white-space: nowrap;
     1190        text-overflow: ellipsis;
     1191}
     1192
     1193@media (max-width: 600px) {
     1194        .current-site {
     1195                margin: 3px 0 0;
     1196        }
     1197}
     1198
     1199@media (max-width: 320px) {
     1200        .current-site {
     1201                margin: 0;
     1202                font-size: 14px;
     1203        }
     1204}
     1205
     1206.current-site span:nth-child(2) {
     1207        color: #ededed;
     1208}
     1209
     1210@media (max-width: 320px) {
     1211        .current-site span:nth-child(2) {
     1212                font-weight: 600;
     1213        }
     1214}
     1215
     1216.current-site .dashicons-wordpress {
     1217        position: relative;
     1218        top: -1px;
     1219        margin-right: 10px;
    3621220        vertical-align: middle;
    3631221}
    3641222
    365 /* =Media Queries
    366 -------------------------------------------------------------- */
     1223.options-open,
     1224.options-close {
     1225        display: none;
     1226}
    3671227
    368 /* Reset responsive styles in Press This */
    369 @media screen and ( max-width: 782px ) {
    370         .press-this ul.category-tabs li.tabs {
    371                 padding: 3px 5px 5px; /* Reset tabs in Press This to standard size */
     1228@media (max-width: 900px) {
     1229        .options-open,
     1230        .options-close {
     1231                display: block;
    3721232        }
     1233}
    3731234
    374         .press-this a.wp-switch-editor {
    375                 font: 13px/19px "Open Sans", sans-serif;
    376                 margin: 5px 0 0 5px;
    377                 padding: 3px 8px 4px;
     1235.options-open.is-hidden,
     1236.options-close.is-hidden {
     1237        display: none;
     1238}
     1239
     1240.options-open:focus .dashicons {
     1241        color: #fff;
     1242        text-decoration: none;
     1243}
     1244
     1245.options-open .dashicons {
     1246        margin-top: 3px;
     1247}
     1248
     1249.options-close {
     1250        color: #2ea2cc;
     1251}
     1252
     1253.alert {
     1254        position: relative;
     1255        margin: 0;
     1256        padding: 16px 50px;
     1257        border-bottom: 1px solid #e5e5e5;
     1258        font-size: 14px;
     1259}
     1260
     1261.alert:before {
     1262        content: '';
     1263        position: absolute;
     1264        top: 50%;
     1265        left: 30px;
     1266        width: 8px;
     1267        height: 8px;
     1268        margin-top: -4px;
     1269        -webkit-border-radius: 50%;
     1270        border-radius: 50%;
     1271        background: #2ea2cc;
     1272}
     1273
     1274@media (max-width: 600px) {
     1275        .alert {
     1276                padding: 16px 35px;
    3781277        }
     1278        .alert:before {
     1279                left: 15px;
     1280        }
     1281}
    3791282
    380         .press-this #wp-content-media-buttons a {
    381                 padding: 0;
    382                 line-height: normal;
    383                 height: auto;
     1283.alert.is-hidden {
     1284        display: none;
     1285}
     1286.alert.is-error:before {
     1287        background: red;
     1288}
     1289
     1290.scan {
     1291        position: relative;
     1292        border-bottom: 1px solid #e5e5e5;
     1293}
     1294
     1295@media (max-width: 900px) {
     1296        .scan form {
     1297                -webkit-transition: opacity .3s ease-in-out;
     1298                transition: opacity .3s ease-in-out;
    3841299        }
     1300        .scan.is-hidden form {
     1301                opacity: .2;
     1302                pointer-events: none;
     1303        }
     1304}
    3851305
    386         .press-this #wp-content-editor-tools {
    387                 padding: 0;
    388                 top: 3px;
     1306.scan-url {
     1307        display: block;
     1308        border: 0;
     1309        padding: 0.85714em 1.07143em;
     1310        font-size: 14px;
     1311        width: 100%;
     1312}
     1313
     1314@media (max-width: 600px) {
     1315        .scan-url {
     1316                font-size: 16px;
    3891317        }
     1318}
    3901319
    391         .press-this .category-tabs {
    392                 margin-top: 0;
     1320.scan-submit {
     1321        position: absolute;
     1322        top: 0;
     1323        right: 0;
     1324        bottom: 0;
     1325        padding: 0.85714em 1.07143em;
     1326        background: #f7f7f7;
     1327        border-color: #dedede;
     1328        border-bottom: 0;
     1329        border-left: 1px solid #f1f1f1;
     1330        -webkit-border-radius: 0;
     1331        border-radius: 0;
     1332        color: #555;
     1333        font-size: 14px;
     1334        line-height: 1.6;
     1335}
     1336
     1337.scan-submit:hover,
     1338.scan-submit:focus {
     1339        background: #2991b7;
     1340        border-color: #20708e;
     1341        color: #fff;
     1342        outline: 0;
     1343}
     1344
     1345.scan-submit:active {
     1346        background: #2581a2;
     1347        border-color: #20708e;
     1348        color: #fff;
     1349}
     1350
     1351.scan-submit:visited {
     1352        color: #555;
     1353}
     1354
     1355.wrapper {
     1356        position: relative;
     1357        margin-bottom: 60px;
     1358        margin-right: 320px;
     1359}
     1360
     1361.wrapper:before,
     1362.wrapper:after {
     1363        content: "";
     1364        display: table;
     1365}
     1366
     1367.wrapper:after {
     1368        clear: both;
     1369}
     1370
     1371@media (max-width: 900px) {
     1372        .wrapper {
     1373                margin: 0;
     1374                width: 100%;
    3931375        }
     1376}
    3941377
    395         .press-this .tagsdiv .newtag {
    396                 width: 120px;
    397                 padding: 3px 5px;
    398                 margin-bottom: 0;
     1378.editor-wrapper {
     1379        overflow: auto;
     1380        float: left;
     1381        width: 100%;
     1382}
     1383
     1384.editor-wrapper:before,
     1385.editor-wrapper:after {
     1386        content: "";
     1387        display: table;
     1388}
     1389
     1390.editor-wrapper:after {
     1391        clear: both;
     1392}
     1393
     1394.editor {
     1395        padding: 0 1.5em 4.75em;
     1396        max-width: 700px;
     1397        margin: 0 auto;
     1398}
     1399
     1400@media (min-width: 901px) {
     1401        .editor {
     1402                max-width: 760px;
    3991403        }
     1404}
    4001405
    401         .press-this .tagchecklist {
     1406@media (max-width: 320px) {
     1407        .editor {
    4021408                padding: 0;
    403                 margin-bottom: 0;
    4041409        }
     1410}
    4051411
    406         .press-this .wp_themeSkin a.mceButton {
    407                 width: 20px;
    408                 height: 20px;
     1412.post-title,
     1413.post-title-placeholder {
     1414        margin: 0;
     1415        padding: .83em 0;
     1416        width: 100%;
     1417        border-bottom: 1px solid #e5e5e5;
     1418        font-size: 32px;
     1419        line-height: 1.4;
     1420        font-weight: 700;
     1421}
     1422
     1423.post-title:active,
     1424.post-title:focus,
     1425.post-title-placeholder:active,
     1426.post-title-placeholder:focus {
     1427        outline: 0;
     1428        -webkit-box-shadow: inset 0px -3px 0 #2ea2cc;
     1429        box-shadow: inset 0px -3px 0 #2ea2cc;
     1430        border-color: #2ea2cc;
     1431}
     1432
     1433@media (max-width: 900px) {
     1434        .post-title,
     1435        .post-title-placeholder {
     1436                font-size: 24px;
    4091437        }
     1438}
    4101439
    411         .press-this .wp_themeSkin .mceButton .mceIcon {
    412                 margin: 0;
     1440@media (max-height: 400px) {
     1441        .post-title,
     1442        .post-title-placeholder {
     1443                padding: 15px 0;
     1444                font-size: 16px;
    4131445        }
     1446}
    4141447
    415         .press-this #poststuff h3,
    416         .press-this .metabox-holder h3 {
    417                 padding: 7px 12px;
     1448@media (max-width: 320px) {
     1449        .post-title,
     1450        .post-title-placeholder {
     1451                font-size: 16px;
     1452                font-weight: 600;
     1453                padding: 1.14286em 1.42857em;
    4181454        }
     1455}
    4191456
    420         .press-this input[type=checkbox],
    421         .press-this input[type=radio] {
    422                 height: 16px;
    423                 width: 16px;
     1457.post-title {
     1458        /* IE8 fallback */
     1459        background: url(data:image/gif;base64,R0lGODlhAQABAJEAAAAAAP///////wAAACH5BAEHAAIALAAAAAABAAEAAAICVAEAOw==);
     1460        background: none, none;
     1461}
     1462
     1463.post-title:before {
     1464        /* Keeps empty container from collapsing */
     1465        content: '\a0';
     1466        display: inline-block;
     1467        width: 0;
     1468        speak: none;
     1469}
     1470
     1471.post-title-placeholder {
     1472        position: absolute;
     1473        border: 0;
     1474        color: #9ea7af;
     1475        z-index: -1;
     1476}
     1477
     1478.post-title-placeholder.is-hidden {
     1479        display: none;
     1480}
     1481
     1482/* Suggested images */
     1483.featured-container {
     1484        position: relative;
     1485        padding: 2px 0;
     1486        border-bottom: 1px solid #e5e5e5;
     1487}
     1488
     1489.all-media {
     1490        display: none;
     1491        overflow: auto;
     1492        max-height: 150px;
     1493        max-height: 40vw;
     1494}
     1495
     1496.all-media:before, .all-media:after {
     1497        content: "";
     1498        display: table;
     1499}
     1500
     1501.all-media:after {
     1502        clear: both;
     1503}
     1504
     1505@media (min-width: 321px) {
     1506        .all-media {
     1507                max-height: 250px;
     1508                max-height: 40vw;
    4241509        }
     1510}
    4251511
    426         .press-this input[type=checkbox]:checked:before {
    427                 width: 16px;
    428                 font: normal 21px/1 'dashicons';
    429                 margin: -3px 0 0 -4px;
     1512@media (min-width: 601px) {
     1513        .all-media {
     1514                max-height: 200px;
     1515                max-height: 18.75vw;
    4301516        }
     1517}
    4311518
    432         .press-this input[type=radio]:checked:before {
    433                 font: normal 21px/1 'dashicons';
    434                 width: 6px;
    435                 height: 6px;
    436                 margin: 4px;
     1519.wppt-all-media-list {
     1520        list-style: none;
     1521        margin: 0;
     1522        padding: 0;
     1523}
     1524
     1525.suggested-media-thumbnail:focus,
     1526.suggested-media-embed:focus {
     1527        outline: 0;
     1528        -webkit-box-shadow: inset 0 0 0 3px #2ea2cc;
     1529        box-shadow: inset 0 0 0 3px #2ea2cc;
     1530}
     1531
     1532.suggested-media-thumbnail {
     1533        position: relative;
     1534        display: block;
     1535        float: left;
     1536        width: 16.66%;
     1537        padding: 16.66% 0 0 16.66%;
     1538        background-position: center;
     1539        background-repeat: no-repeat;
     1540        -webkit-background-size: cover;
     1541        background-size: cover;
     1542        background-color: #d8d8d8;
     1543        color: #fff;
     1544        color: rgba(255, 255, 255, 0.6);
     1545        cursor: pointer;
     1546}
     1547
     1548.suggested-media-thumbnail:hover,
     1549.suggested-media-thumbnail:active,
     1550.suggested-media-thumbnail:focus {
     1551        color: #fff;
     1552}
     1553
     1554.suggested-media-thumbnail:before,
     1555.suggested-media-thumbnail:after {
     1556        display: inline-block;
     1557        position: absolute;
     1558        font-size: 20px;
     1559        line-height: 1;
     1560        font-family: dashicons;
     1561        text-decoration: inherit;
     1562        font-weight: 400;
     1563        font-style: normal;
     1564        -webkit-transition: color .1s ease-in 0;
     1565        transition: color .1s ease-in 0;
     1566        -webkit-font-smoothing: antialiased;
     1567        -moz-osx-font-smoothing: grayscale;
     1568}
     1569
     1570.suggested-media-thumbnail:before {
     1571        left: 50%;
     1572        top: 50%;
     1573        margin: -20px 0 0 -20px;
     1574        font-size: 40px;
     1575}
     1576
     1577.suggested-media-thumbnail:after {
     1578        content: "\f132";
     1579        right: 3%;
     1580        bottom: 2%;
     1581}
     1582
     1583@media (min-width: 601px) {
     1584        .suggested-media-thumbnail {
     1585                width: 12.5%;
     1586                padding: 12.5% 0 0 12.5%;
    4371587        }
     1588}
    4381589
    439         .press-this ul.categorychecklist ul,
    440         .press-this ul.categorychecklist li {
    441                 margin-top: 0;
    442                 margin-bottom: 0;
     1590.suggested-media-embed:before {
     1591        content: "\f104";
     1592        color: #fff;
     1593        color: rgba(255, 255, 255, 0.9);
     1594}
     1595
     1596.suggested-media-embed.is-audio:hover:before,
     1597.suggested-media-embed.is-audio:active:before,
     1598.suggested-media-embed.is-audio:focus:before,
     1599.suggested-media-embed.is-tweet:hover:before,
     1600.suggested-media-embed.is-tweet:active:before,
     1601.suggested-media-embed.is-tweet:focus:before {
     1602        color: #fff;
     1603}
     1604
     1605.suggested-media-embed.is-video {
     1606        background-color: #222;
     1607}
     1608
     1609.suggested-media-embed.is-video:hover:before,
     1610.suggested-media-embed.is-video:active:before,
     1611.suggested-media-embed.is-video:focus:before {
     1612        color: rgba(255, 255, 255, 0.2);
     1613}
     1614
     1615.suggested-media-embed.is-video:before {
     1616        content: "\f236";
     1617}
     1618
     1619.suggested-media-embed.is-audio {
     1620        background-color: #ff7d44;
     1621}
     1622
     1623.suggested-media-embed.is-audio:before {
     1624        content: "\f127";
     1625}
     1626
     1627.suggested-media-embed.is-tweet {
     1628        background-color: #55acee;
     1629}
     1630
     1631.suggested-media-embed.is-tweet:before {
     1632        content: "\f301";
     1633}
     1634
     1635.all-media-visible .all-media {
     1636        display: block;
     1637}
     1638
     1639.no-media {
     1640        margin: 0;
     1641        padding: 0;
     1642        border: 0;
     1643}
     1644
     1645/* Actions bar */
     1646.press-this-actions {
     1647        position: fixed;
     1648        bottom: 0;
     1649        left: 0;
     1650        width: 100%;
     1651        background: #f1f1f1;
     1652        background: rgba(241, 241, 241, 0.9);
     1653        border-top: 1px solid #e5e5e5;
     1654}
     1655
     1656@media (max-width: 900px) {
     1657        .press-this-actions {
     1658                -webkit-transform: translateY(0);
     1659                -ms-transform: translateY(0);
     1660                transform: translateY(0);
     1661                -webkit-transition: -webkit-transform .3s ease-in-out;
     1662                transition: transform .3s ease-in-out;
    4431663        }
     1664        .press-this-actions.is-hidden {
     1665                -webkit-transform: translateY(100%);
     1666                -ms-transform: translateY(100%);
     1667                transform: translateY(100%);
     1668        }
     1669}
    4441670
    445         .press-this div.quicktags-toolbar input {
    446                 padding: 2px 4px;
     1671.add-media {
     1672        float: left;
     1673        margin: 14px 0 14px 30px;
     1674        font-size: 0;
     1675}
     1676
     1677@media (max-width: 320px) {
     1678        .add-media {
     1679                margin: 10px 0 10px 10px;
    4471680        }
     1681}
    4481682
    449         .press-this textarea,
    450         .press-this input {
    451                 font-size: 14px;
     1683.insert-media {
     1684        color: #9ea7af;
     1685        float: left;
     1686        margin: 0;
     1687        padding: 0;
     1688        border: 0;
     1689        border-right: 1px solid #e5e5e5;
     1690        -webkit-border-radius: 0;
     1691        border-radius: 0;
     1692        background: none;
     1693        -webkit-box-shadow: none;
     1694        box-shadow: none;
     1695        overflow: hidden;
     1696}
     1697
     1698.insert-media:hover,
     1699.insert-media:focus,
     1700.insert-media:active {
     1701        margin: 0;
     1702        background: none;
     1703        border-color: #e5e5e5;
     1704        color: #222;
     1705}
     1706
     1707.insert-media:focus,
     1708.insert-media:active {
     1709        outline: 0;
     1710        color: #2ea2cc;
     1711        text-decoration: none;
     1712}
     1713
     1714.insert-media .dashicons {
     1715        padding: 11px;
     1716        width: 63px;
     1717        height: 58px;
     1718        font-size: 40px;
     1719}
     1720
     1721@media (max-width: 320px) {
     1722        .insert-media .dashicons {
     1723                width: 55px;
     1724                height: 49px;
     1725                padding: 14px;
     1726                font-size: 20px;
    4521727        }
     1728}
    4531729
    454         .press-this .tagchecklist span {
    455                 font-size: 13px;
    456                 line-height: 1.8em;
     1730.post-actions {
     1731        float: right;
     1732        margin: 14px 30px 14px 0;
     1733        font-size: 0;
     1734}
     1735
     1736@media (max-width: 320px) {
     1737        .post-actions {
     1738                margin: 10px 10px 10px 0;
    4571739        }
    4581740}
     1741
     1742/* TinyMCE styles */
     1743.editor .wp-media-buttons {
     1744        float: none;
     1745}
     1746
     1747.editor div.mce-toolbar-grp {
     1748        padding: 0.71429em 0;
     1749        background: none;
     1750        border: 0;
     1751}
     1752
     1753@media (max-height: 400px), (max-width: 320px) {
     1754        .editor div.mce-toolbar-grp {
     1755                padding: 0;
     1756        }
     1757}
     1758
     1759.mce-stack-layout:before,
     1760.mce-stack-layout:after {
     1761        content: "";
     1762        display: table;
     1763}
     1764
     1765.mce-stack-layout:after {
     1766        clear: both;
     1767}
     1768
     1769.mce-container.mce-toolbar {
     1770        float: left;
     1771}
     1772
     1773.mce-container.mce-toolbar:nth-child(2) {
     1774        float: right;
     1775}
     1776
     1777@media (max-width: 600px) {
     1778        #mceu_11,
     1779        #mceu_12 {
     1780                position: absolute;
     1781                margin: -1px;
     1782                padding: 0;
     1783                height: 1px;
     1784                width: 1px;
     1785                overflow: hidden;
     1786                clip: rect(0 0 0 0);
     1787                border: 0;
     1788        }
     1789
     1790        #mceu_11:focus,
     1791        #mceu_12:focus {
     1792                position: static;
     1793                margin: 1px;
     1794                padding: inherit;
     1795                height: auto;
     1796                width: auto;
     1797                overflow: visible;
     1798                clip: auto;
     1799                border: 1px solid #999;
     1800        }
     1801}
     1802
     1803#wp-link-wrap.search-panel-visible {
     1804        font-size: 13px;
     1805}
     1806
     1807/* Options panel (sidebar) */
     1808.options-panel {
     1809        position: relative;
     1810        float: right;
     1811        margin-right: -320px;
     1812        width: 320px;
     1813        border-left: 1px solid #e5e5e5;
     1814        font-size: 14px;
     1815        /* Keeps background the full height of the screen */
     1816        -webkit-box-shadow: 5001px 5000px 0 5000px #fff, 5000px 5000px 0 5000px #e5e5e5;
     1817        box-shadow: 5001px 5000px 0 5000px #fff, 5000px 5000px 0 5000px #e5e5e5;
     1818}
     1819
     1820@media (max-width: 900px) {
     1821        .options-panel {
     1822                background: #fff;
     1823                -webkit-transform: translateX(-100%);
     1824                -ms-transform: translateX(-100%);
     1825                transform: translateX(-100%);
     1826                -webkit-transition: -webkit-transform .3s ease-in-out;
     1827                transition: transform .3s ease-in-out;
     1828        }
     1829
     1830        .options-panel.is-hidden {
     1831                visibility: hidden;
     1832        }
     1833
     1834        .options-panel.is-off-screen {
     1835                -webkit-transform: translateX(0);
     1836                -ms-transform: translateX(0);
     1837                transform: translateX(0);
     1838        }
     1839}
     1840
     1841@media (max-width: 320px) {
     1842        .options-panel {
     1843                margin-right: -100%;
     1844                width: 100%;
     1845                border: 0;
     1846                -webkit-box-shadow: 5001px 5000px 0 5000px #fff;
     1847                box-shadow: 5001px 5000px 0 5000px #fff;
     1848        }
     1849}
     1850
     1851.post-options {
     1852        background: #fff;
     1853        position: absolute;
     1854        right: 0;
     1855        width: 100%;
     1856        overflow-x: hidden;
     1857}
     1858
     1859.post-options .post-option-contents {
     1860        margin-left: 3px;
     1861        color: #333;
     1862}
     1863
     1864.post-options .dashicons-arrow-right-alt2 {
     1865        position: absolute;
     1866        top: 50%;
     1867        right: 8px;
     1868        margin-top: -10px;
     1869}
     1870
     1871.lt-ie9 .options-panel,
     1872.lt-ie9 .post-options {
     1873        border-left: 1px solid #e5e5e5;
     1874}
     1875
     1876.lt-ie9 .post-options.is-off-screen {
     1877        border: 0;
     1878}
     1879
     1880.post-option {
     1881        position: relative;
     1882}
     1883
     1884.post-options .post-option {
     1885        display: block;
     1886        width: 100%;
     1887        padding: 13px 37px 13px 14px;
     1888        border-bottom: 1px solid #e5e5e5;
     1889        text-decoration: none;
     1890        text-align: left;
     1891        color: #9ea7af;
     1892        text-overflow: ellipsis;
     1893        white-space: nowrap;
     1894        overflow: hidden;
     1895        -webkit-transition: -webkit-transform .3s ease-in-out;
     1896        transition: transform .3s ease-in-out;
     1897}
     1898
     1899.post-options .post-option:focus {
     1900        outline: 0;
     1901        -webkit-box-shadow: inset 5px 0 0 #2ea2cc;
     1902        box-shadow: inset 5px 0 0 #2ea2cc;
     1903}
     1904
     1905.is-off-screen > .post-option {
     1906        right: 100%;
     1907}
     1908
     1909.is-hidden > .post-option {
     1910        visibility: hidden;
     1911}
     1912
     1913@media (min-width: 1px) {
     1914        .is-off-screen > .post-option {
     1915                right: auto;
     1916                -webkit-transform: translateX(-100%);
     1917                -ms-transform: translateX(-100%);
     1918                transform: translateX(-100%);
     1919        }
     1920}
     1921
     1922.post-option-title {
     1923        display: inline-block;
     1924        margin: 0 0 0 8px;
     1925        font-size: 14px;
     1926        font-weight: normal;
     1927}
     1928
     1929.setting-modal {
     1930        position: relative;
     1931        top: 0;
     1932        left: 0;
     1933        width: 100%;
     1934        overflow: hidden;
     1935        -webkit-transition: -webkit-transform .3s ease-in-out;
     1936        transition: transform .3s ease-in-out;
     1937}
     1938
     1939.setting-modal.is-hidden {
     1940        visibility: hidden;
     1941        height: 0;
     1942}
     1943
     1944.setting-modal.is-off-screen {
     1945        left: 100%;
     1946}
     1947
     1948@media (min-width: 1px) {
     1949        .setting-modal.is-off-screen {
     1950                left: 0;
     1951                -webkit-transform: translateX(100%);
     1952                -ms-transform: translateX(100%);
     1953                transform: translateX(100%);
     1954        }
     1955}
     1956
     1957.modal-close {
     1958        display: block;
     1959        width: 100%;
     1960        padding: 13px 14px;
     1961        border-bottom: 1px solid #e5e5e5;
     1962        color: #2ea2cc;
     1963        text-decoration: none;
     1964        text-align: left;
     1965}
     1966
     1967.modal-close:focus {
     1968        outline: 0;
     1969        -webkit-box-shadow: inset 5px 0 0 #2ea2cc;
     1970        box-shadow: inset 5px 0 0 #2ea2cc;
     1971}
     1972
     1973.setting-title {
     1974        position: relative;
     1975        top: -1px;
     1976        margin-left: 11px;
     1977}
  • src/wp-admin/css/wp-admin.css

     
    77@import url(revisions.css);
    88@import url(media.css);
    99@import url(themes.css);
    10 @import url(press-this.css);
    1110@import url(about.css);
    1211@import url(nav-menus.css);
    1312@import url(widgets.css);
  • src/wp-admin/includes/ajax-actions.php

     
    29542954
    29552955        wp_send_json_success( $status );
    29562956}
     2957
     2958/**
     2959 * AJAX handler for saving a post from Ptrss This.
     2960 *
     2961 * @since 4.2.0
     2962 */
     2963function wp_ajax_press_this_save_post() {
     2964        if ( empty( $GLOBALS['wp_press_this'] ) ) {
     2965                include( ABSPATH . 'wp-admin/includes/class-wp-press-this.php' );
     2966        }
     2967
     2968        $GLOBALS['wp_press_this']->save_post();
     2969}
     2970
     2971/**
     2972 * AJAX handler for creating new category from Ptrss This.
     2973 *
     2974 * @since 4.2.0
     2975 */
     2976function wp_ajax_press_this_add_category() {
     2977        if ( empty( $GLOBALS['wp_press_this'] ) ) {
     2978                include( ABSPATH . 'wp-admin/includes/class-wp-press-this.php' );
     2979        }
     2980
     2981        $GLOBALS['wp_press_this']->add_category();
     2982}
  • src/wp-admin/includes/class-wp-press-this.php

     
     1<?php
     2/**
     3 * Press This class and display functionality
     4 *
     5 * @package WordPress
     6 * @subpackage Press_This
     7 * @since 4.2.0
     8 */
     9
     10/**
     11 * Press This class
     12 *
     13 * @since 4.2.0
     14 */
     15class WP_Press_This {
     16
     17        /**
     18         * Constructor.
     19         *
     20         * @since 4.2.0
     21         * @access public
     22         */
     23        public function __construct() {}
     24
     25        /**
     26         * App and site settings data, including i18n strings for the client-side.
     27         *
     28         * @since 4.2.0
     29         * @access public
     30         *
     31         * @return array Site settings.
     32         */
     33        public function site_settings() {
     34                $supported_formats = get_theme_support( 'post-formats' );
     35                $post_formats      = array();
     36
     37                if ( ! empty( $supported_formats[0] ) && is_array( $supported_formats[0] ) ) {
     38                        $post_formats[0] = __( 'Standard' );
     39                        foreach ( $supported_formats[0] as $post_format ) {
     40                                $post_formats[ $post_format ] = esc_html( get_post_format_string( $post_format ) );
     41                        }
     42                }
     43
     44                return array(
     45                        'version'         => 5,
     46                        'post_formats'    => $post_formats,
     47
     48                        /**
     49                         * Filter whether Press This should redirect the user in the parent window instead of the popup, upon save.
     50                         *
     51                         * @since 4.2.0
     52                         *
     53                         * @param bool $redir_in_parent Whether to redirect in parent window or not. Default false.
     54                         */
     55                        'redir_in_parent' => apply_filters( 'press_this_redirect_in_parent', __return_false() ),
     56                );
     57        }
     58
     59        /**
     60         * Get the sources images and save them locally, fr posterity, unless we can't.
     61         *
     62         * @since 4.2.0
     63         * @access public
     64         *
     65         * @param int    $post_id Post ID.
     66         * @param string $content Optional. Current expected markup for Press This. Default empty.
     67         * @return string New markup with old image URLs replaced with the local attachment ones if swapped.
     68         */
     69        public function side_load_images( $post_id, $content = '' ) {
     70                $new_content = $content;
     71
     72                preg_match_all( '/<img [^>]+>/', $content, $matches );
     73
     74                if ( ! empty( $matches ) && current_user_can( 'upload_files' ) ) {
     75                        foreach ( (array) $matches[0] as $key => $image ) {
     76                                preg_match( '/src=["\']{1}([^"\']+)["\']{1}/', stripslashes( $image ), $url_matches );
     77
     78                                if ( empty( $url_matches[1] ) ) {
     79                                        continue;
     80                                }
     81
     82                                $image_url = $url_matches[1];
     83
     84                                // Don't try to sideload a file without a file extension, leads to WP upload error.
     85                                if ( ! preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $image_url ) )
     86                                         continue;
     87
     88                                // See if files exist in content - we don't want to upload non-used selected files.
     89                                if ( false !== strpos( $new_content, htmlspecialchars( $image_url ) ) ) {
     90
     91                                        // Sideload image, which ives us a new image tag, strip the empty alt that comes with it.
     92                                        $upload = str_replace( ' alt=""', '', media_sideload_image( $image_url, $post_id ) );
     93
     94                                        // Preserve assigned class, id, width, height and alt attributes.
     95                                        if ( preg_match_all( '/(class|width|height|id|alt)=\\\?(\"|\')[^"\']+\\\?(\2)/', $image, $attr_matches )
     96                                             && is_array( $attr_matches[0] )
     97                                        ) {
     98                                                foreach ( $attr_matches[0] as $attr ) {
     99                                                        $upload = str_replace( '<img', '<img ' . $attr, $upload );
     100                                                }
     101                                        }
     102
     103                                        /*
     104                                         * Replace the POSTED content <img> with correct uploaded ones.
     105                                         * Regex contains fix for Magic Quotes.
     106                                         */
     107                                        if ( ! is_wp_error( $upload ) ) {
     108                                                $new_content = str_replace( $image, $upload, $new_content );
     109                                        }
     110                                }
     111                        }
     112                }
     113
     114                // Error handling for media_sideload, send original content back.
     115                if ( is_wp_error( $new_content ) ) {
     116                        return $content;
     117                }
     118
     119                return $new_content;
     120        }
     121
     122        /**
     123         * AJAX handler for saving the post as draft or published.
     124         *
     125         * @since 4.2.0
     126         * @access public
     127         */
     128        public function save_post() {
     129                if ( empty( $_POST['pressthis-nonce'] ) || ! wp_verify_nonce( $_POST['pressthis-nonce'], 'press-this' ) ) {
     130                        wp_send_json_error( array( 'errorMessage' => __( 'Cheatin&#8217; uh?' ) ) );
     131                }
     132
     133                if ( empty( $_POST['post_ID'] ) || ! $post_id = (int) $_POST['post_ID'] ) {
     134                        wp_send_json_error( array( 'errorMessage' => __( 'Missing post ID.' ) ) );
     135                }
     136       
     137                if ( ! current_user_can( 'edit_post', $post_id ) ) {
     138                        wp_send_json_error( array( 'errorMessage' => __( 'Cheatin&#8217; uh?' ) ) );
     139                }
     140       
     141                $post = array(
     142                        'ID'            => $post_id,
     143                        'post_title'    => ( ! empty( $_POST['title'] ) ) ? sanitize_text_field( trim( $_POST['title'] ) ) : '',
     144                        'post_content'  => ( ! empty( $_POST['pressthis'] ) ) ? trim( $_POST['pressthis'] ) : '',
     145                        'post_type'     => 'post',
     146                        'post_status'   => 'draft',
     147                        'post_format'   => ( ! empty( $_POST['post_format'] ) ) ? sanitize_text_field( $_POST['post_format'] ) : '',
     148                        'tax_input'     => ( ! empty( $_POST['tax_input'] ) ) ? $_POST['tax_input'] : array(),
     149                        'post_category' => ( ! empty( $_POST['post_category'] ) ) ? $_POST['post_category'] : array(),
     150                );
     151       
     152                if ( ! empty( $_POST['post_status'] ) && 'publish' === $_POST['post_status'] ) {
     153                        if ( current_user_can( 'publish_posts' ) ) {
     154                                $post['post_status'] = 'publish';
     155                        } else {
     156                                $post['post_status'] = 'pending';
     157                        }
     158                }
     159
     160                $new_content = $this->side_load_images( $post_id, $post['post_content'] );
     161
     162                if ( ! is_wp_error( $new_content ) ) {
     163                        $post['post_content'] = $new_content;
     164                }
     165
     166                $updated = wp_update_post( $post, true );
     167       
     168                if ( is_wp_error( $updated ) || intval( $updated ) < 1 ) {
     169                        wp_send_json_error( array( 'errorMessage' => __( 'Error while saving the post. Please try again later.' ) ) );
     170                } else {
     171                        if ( isset( $post['post_format'] ) ) {
     172                                if ( current_theme_supports( 'post-formats', $post['post_format'] ) ) {
     173                                        set_post_format( $post_id, $post['post_format'] );
     174                                } elseif ( $post['post_format'] ) {
     175                                        set_post_format( $post_id, false );
     176                                }
     177                        }
     178
     179                        if ( 'publish' === get_post_status( $post_id ) ) {
     180                                /**
     181                                 * Filter the URL to redirect to when Press This saves.
     182                                 *
     183                                 * @since 4.2.0
     184                                 *
     185                                 * @param string $url     Redirect URL. If `$status` is 'publish', this will be the post permalink.
     186                                 *                        Otherwise, the post edit URL will be used.
     187                                 * @param int    $post_id Post ID.
     188                                 * @param string $status  Post status.
     189                                 */
     190                                $redirect = apply_filters( 'press_this_save_redirect', get_post_permalink( $post_id ), $post_id, $post['post_status'] );
     191                        } else {
     192                                /** This filter is documented in wp-admin/includes/class-wp-press-this.php */
     193                                $redirect = apply_filters( 'press_this_save_redirect', get_edit_post_link( $post_id, 'raw' ), $post_id, $post['post_status'] );
     194                        }
     195       
     196                        wp_send_json_success( array( 'redirect' => $redirect ) );
     197                }
     198        }
     199
     200        /**
     201         * AJAX handler for adding a new category.
     202         *
     203         * @since 4.2.0
     204         * @access public
     205         */
     206        public function add_category() {
     207                if ( false === wp_verify_nonce( $_POST['new_cat_nonce'], 'add-category' ) ) {
     208                        wp_send_json_error();
     209                }
     210
     211                $taxonomy = get_taxonomy( 'category' );
     212
     213                if ( ! current_user_can( $taxonomy->cap->edit_terms ) || empty( $_POST['name'] ) ) {
     214                        wp_send_json_error();
     215                }
     216
     217                $parent = isset( $_POST['parent'] ) && (int) $_POST['parent'] > 0 ? (int) $_POST['parent'] : 0;
     218                $names = explode( ',', $_POST['name'] );
     219                $added = $data = array();
     220
     221                foreach ( $names as $cat_name ) {
     222                        $cat_name = trim( $cat_name );
     223                        $cat_nicename = sanitize_title( $cat_name );
     224
     225                        if ( empty( $cat_nicename ) ) {
     226                                continue;
     227                        }
     228
     229                        // @todo Find a more performant to check existence, maybe get_term() with a separate parent check.
     230                        if ( ! $cat_id = term_exists( $cat_name, $taxonomy->name, $parent ) ) {
     231                                $cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
     232                        }
     233
     234                        if ( is_wp_error( $cat_id ) ) {
     235                                continue;
     236                        } elseif ( is_array( $cat_id ) ) {
     237                                $cat_id = $cat_id['term_id'];
     238                        }
     239
     240                        $added[] = $cat_id;
     241                }
     242
     243                if ( empty( $added ) ) {
     244                        wp_send_json_error( array( 'errorMessage' => __( 'This category cannot be added. Please change the name and try again.' ) ) );
     245                }
     246
     247                foreach ( $added as $new_cat_id ) {
     248                        $new_cat = get_category( $new_cat_id );
     249
     250                        if ( is_wp_error( $new_cat ) ) {
     251                                wp_send_json_error( array( 'errorMessage' => __( 'Error while adding the category. Please try again later.' ) ) );
     252                        }
     253
     254                        $data[] = array(
     255                                'term_id' => $new_cat->term_id,
     256                                'name' => $new_cat->name,
     257                                'parent' => $new_cat->parent,
     258                        );
     259                }
     260                wp_send_json_success( $data );
     261        }
     262
     263        /**
     264         * Downloads the source's HTML via server-side call for the given URL.
     265         *
     266         * @since 4.2.0
     267         * @access public
     268         *
     269         * @param string $url URL to scan.
     270         * @return string Source's HTML sanitized markup
     271         */
     272        public function fetch_source_html( $url ) {
     273                // Download source page to tmp file.
     274                $source_tmp_file = ( ! empty( $url ) ) ? download_url( $url ) : '';
     275                $source_content  = '';
     276
     277                if ( ! is_wp_error( $source_tmp_file ) && file_exists( $source_tmp_file ) ) {
     278                        // Get the content of the source page from the tmp file..
     279
     280                        $source_content = wp_kses(
     281                                file_get_contents( $source_tmp_file ),
     282                                array(
     283                                        'img' => array(
     284                                                'src'      => array(),
     285                                        ),
     286                                        'iframe' => array(
     287                                                'src'      => array(),
     288                                        ),
     289                                        'link' => array(
     290                                                'rel'      => array(),
     291                                                'itemprop' => array(),
     292                                                'href'     => array(),
     293                                        ),
     294                                        'meta' => array(
     295                                                'property' => array(),
     296                                                'name'     => array(),
     297                                                'content'  => array(),
     298                                        )
     299                                )
     300                        );
     301
     302                        // All done with backward compatibility. Let's do some cleanup, for good measure :)
     303                        unlink( $source_tmp_file );
     304
     305                } else if ( is_wp_error( $source_tmp_file ) ) {
     306                        $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() ) ) );
     307                } else if ( ! file_exists( $source_tmp_file ) ) {
     308                        $source_content = new WP_Error( 'no-local-file',  sprintf( __( 'Error: %s' ), __( 'Could not save or locate the temporary download file for the source URL.' ) ) );
     309                }
     310
     311                return $source_content;
     312        }
     313
     314        /**
     315         * Fetches and parses _meta, _img, and _links data from the source.
     316         *
     317         * @since 4.2.0
     318         * @access public
     319         *
     320         * @param string $url  URL to scan.
     321         * @param array  $data Optional. Existing data array if you have one. Default empty array.
     322         * @return array New data array.
     323         */
     324        public function source_data_fetch_fallback( $url, $data = array() ) {
     325                if ( empty( $url ) ) {
     326                        return array();
     327                }
     328
     329                // Download source page to tmp file.
     330                $source_content = $this->fetch_source_html( $url );
     331                if ( is_wp_error( $source_content ) ) {
     332                        return array( 'errors' => $source_content->get_error_messages() );
     333                }
     334
     335                // Fetch and gather <img> data.
     336                if ( empty( $data['_img'] ) ) {
     337                        $data['_img'] = array();
     338                }
     339
     340                if ( preg_match_all( '/<img (.+)[\s]?\/>/', $source_content, $matches ) ) {
     341                        if ( ! empty( $matches[0] ) ) {
     342                                foreach ( $matches[0] as $value ) {
     343                                        if ( preg_match( '/<img[^>]+src="([^"]+)"[^>]+\/>/', $value, $new_matches ) ) {
     344                                                if ( ! in_array( $new_matches[1], $data['_img'] ) ) {
     345                                                        $data['_img'][] = $new_matches[1];
     346                                                }
     347                                        }
     348                                }
     349                        }
     350                }
     351
     352                // Fetch and gather <iframe> data.
     353                if ( empty( $data['_embed'] ) ) {
     354                        $data['_embed'] = array();
     355                }
     356
     357                if ( preg_match_all( '/<iframe (.+)[\s][^>]*>/', $source_content, $matches ) ) {
     358                        if ( ! empty( $matches[0] ) ) {
     359                                foreach ( $matches[0] as $value ) {
     360                                        if ( preg_match( '/<iframe[^>]+src=(\'|")([^"]+)(\'|")/', $value, $new_matches ) ) {
     361                                                if ( ! in_array( $new_matches[2], $data['_embed'] ) ) {
     362                                                        if ( preg_match( '/\/\/www\.youtube\.com\/embed\/([^\?]+)\?.+$/', $new_matches[2], $src_matches ) ) {
     363                                                                $data['_embed'][] = 'https://www.youtube.com/watch?v=' . $src_matches[1];
     364                                                        } else if ( preg_match( '/\/\/player\.vimeo\.com\/video\/([\d]+)([\?\/]{1}.*)?$/', $new_matches[2], $src_matches ) ) {
     365                                                                $data['_embed'][] = 'https://vimeo.com/' . (int) $src_matches[1];
     366                                                        } else if ( preg_match( '/\/\/vine\.co\/v\/([^\/]+)\/embed/', $new_matches[2], $src_matches ) ) {
     367                                                                $data['_embed'][] = 'https://vine.co/v/' . $src_matches[1];
     368                                                        }
     369                                                }
     370                                        }
     371                                }
     372                        }
     373                }
     374
     375                // Fetch and gather <meta> data.
     376                if ( empty( $data['_meta'] ) ) {
     377                        $data['_meta'] = array();
     378                }
     379
     380                if ( preg_match_all( '/<meta ([^>]+)[\s]?\/?>/  ', $source_content, $matches ) ) {
     381                        if ( ! empty( $matches[0] ) ) {
     382                                foreach ( $matches[0] as $key => $value ) {
     383                                        if ( preg_match( '/<meta[^>]+(property|name)="(.+)"[^>]+content="(.+)"/', $value, $new_matches ) ) {
     384                                                if ( empty( $data['_meta'][ $new_matches[2] ] ) ) {
     385                                                        if ( preg_match( '/:?(title|description|keywords)$/', $new_matches[2] ) ) {
     386                                                                $data['_meta'][ $new_matches[2] ] = str_replace( '&#039;', "'", str_replace( '&#034;', '', html_entity_decode( $new_matches[3] ) ) );
     387                                                        } else {
     388                                                                $data['_meta'][ $new_matches[2] ] = $new_matches[3];
     389                                                                if ( 'og:url' == $new_matches[2] ) {
     390                                                                        if ( false !== strpos( $new_matches[3], '//www.youtube.com/watch?' )
     391                                                                             || false !== strpos( $new_matches[3], '//www.dailymotion.com/video/' )
     392                                                                             || preg_match( '/\/\/vimeo\.com\/[\d]+$/', $new_matches[3] )
     393                                                                             || preg_match( '/\/\/soundcloud\.com\/.+$/', $new_matches[3] )
     394                                                                             || preg_match( '/\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/', $new_matches[3] )
     395                                                                             || preg_match( '/\/\/vine\.co\/v\/[^\/]+/', $new_matches[3] ) ) {
     396                                                                                if ( ! in_array( $new_matches[3], $data['_embed'] ) ) {
     397                                                                                        $data['_embed'][] = $new_matches[3];
     398                                                                                }
     399                                                                        }
     400                                                                } else if ( 'og:video' == $new_matches[2] || 'og:video:secure_url' == $new_matches[2] ) {
     401                                                                        if ( preg_match( '/\/\/www\.youtube\.com\/v\/([^\?]+)/', $new_matches[3], $src_matches ) ) {
     402                                                                                if ( ! in_array( 'https://www.youtube.com/watch?v=' . $src_matches[1], $data['_embed'] ) ) {
     403                                                                                        $data['_embed'][] = 'https://www.youtube.com/watch?v=' . $src_matches[1];
     404                                                                                }
     405                                                                        } else if ( preg_match( '/\/\/vimeo.com\/moogaloop\.swf\?clip_id=([\d]+)$/', $new_matches[3], $src_matches ) ) {
     406                                                                                if ( ! in_array( 'https://vimeo.com/' . $src_matches[1], $data['_embed'] ) ) {
     407                                                                                        $data['_embed'][] = 'https://vimeo.com/' . $src_matches[1];
     408                                                                                }
     409                                                                        }
     410                                                                } else if ( 'og:image' == $new_matches[2] || 'og:image:secure_url' == $new_matches[2] ) {
     411                                                                        if ( ! in_array( $new_matches[3], $data['_img'] ) ) {
     412                                                                                $data['_img'][] = $new_matches[3];
     413                                                                        }
     414                                                                }
     415                                                        }
     416                                                }
     417                                        }
     418                                }
     419                        }
     420                }
     421
     422                // Fetch and gather <link> data
     423                if ( empty( $data['_links'] ) ) {
     424                        $data['_links'] = array();
     425                }
     426
     427                if ( preg_match_all( '/<link ([^>]+)[\s]?\/>/', $source_content, $matches ) ) {
     428                        if ( ! empty( $matches[0] ) ) {
     429                                foreach ( $matches[0] as $key => $value ) {
     430                                        if ( preg_match( '/<link[^>]+(rel|itemprop)="([^"]+)"[^>]+href="([^"]+)"[^>]+\/>/', $value, $new_matches ) ) {
     431                                                if ( 'alternate' == $new_matches[2] || 'thumbnailUrl' == $new_matches[2] || 'url' == $new_matches[2] ) {
     432                                                        if ( empty( $data['_links'][ $new_matches[2] ] ) ) {
     433                                                                $data['_links'][ $new_matches[2] ] = $new_matches[3];
     434                                                        }
     435                                                }
     436                                        }
     437                                }
     438                        }
     439                }
     440
     441                return $data;
     442        }
     443
     444        /**
     445         * Handles backward-compat with the legacy version of Press This by supporting its query string params.
     446         *
     447         * @since 4.2.0
     448         * @access public
     449         *
     450         * @return array
     451         */
     452        public function merge_or_fetch_data() {
     453                // Merge $_POST and $_GET, as appropriate ($_POST > $_GET), to remain backward compatible.
     454                $data = array_merge_recursive( $_POST, $_GET );
     455
     456                // Get the legacy QS params, or equiv POST data
     457                $data['u'] = ( ! empty( $data['u'] ) && preg_match( '/^https?:/', $data['u'] ) ) ? $data['u'] : '';
     458                $data['s'] = ( ! empty( $data['s'] ) ) ? $data['s'] : '';
     459                $data['t'] = ( ! empty( $data['t'] ) ) ? $data['t'] : '';
     460
     461                /**
     462                 * Filter whether to enable in-source media discovery in Press This.
     463                 *
     464                 * @since 4.2.0
     465                 *
     466                 * @param bool $enable Whether to enable media discovery.
     467                 */
     468                if ( apply_filters( 'enable_press_this_media_discovery', __return_true() ) ) {
     469                        /*
     470                         * If no _meta (a new thing) was passed via $_POST, fetch data from source as fallback,
     471                         * makes PT fully backward compatible
     472                         */
     473                        if ( empty( $data['_meta'] ) && ! empty( $data['u'] ) ) {
     474                                $data = $this->source_data_fetch_fallback( $data['u'], $data );
     475                        }
     476                } else {
     477                        if ( ! empty( $data['_img'] ) ) {
     478                                $data['_img'] = array();
     479                        }
     480                        if ( ! empty( $data['_embed'] ) ) {
     481                                $data['_embed'] = array();
     482                        }
     483                        if ( ! empty( $data['_meta'] ) ) {
     484                                $data['_meta'] = array();
     485                        }
     486                }
     487
     488                /**
     489                 * Filter the Press This data array.
     490                 *
     491                 * @since 4.2.0
     492                 *
     493                 * @param array $data Press This Data array.
     494                 */
     495                return apply_filters( 'press_this_data', $data );
     496        }
     497
     498        /**
     499         * Adds another stylesheet inside TinyMCE.
     500         *
     501         * @since 4.2.0
     502         * @access public
     503         *
     504         * @param string $styles URL to editor stylesheet.
     505         * @return string Possibly modified stylesheets list.
     506         */
     507        public function add_editor_style( $styles ) {
     508                if ( ! empty( $styles ) ) {
     509                        $styles .= ',';
     510                }
     511                return $styles . admin_url( 'css/press-this-editor.css' );
     512        }
     513
     514        /**
     515         * Outputs the post format selection HTML.
     516         *
     517         * @since 4.2.0
     518         * @access public
     519         *
     520         * @param WP_Post $post Post object.
     521         */
     522        function post_formats_html( $post ) {
     523                if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) ) {
     524                        $post_formats = get_theme_support( 'post-formats' );
     525
     526                        if ( is_array( $post_formats[0] ) ) {
     527                                $post_format = get_post_format( $post->ID );
     528
     529                                if ( ! $post_format ) {
     530                                        $post_format = '0';
     531                                }
     532
     533                                // Add in the current one if it isn't there yet, in case the current theme doesn't support it.
     534                                if ( $post_format && ! in_array( $post_format, $post_formats[0] ) ) {
     535                                        $post_formats[0][] = $post_format;
     536                                }
     537
     538                                ?>
     539                                <div id="post-formats-select">
     540                                        <input type="radio" name="post_format" class="post-format" id="post-format-0" value="0" <?php checked( $post_format, '0' ); ?> />
     541                                        <label for="post-format-0" class="post-format-icon post-format-standard"><?php echo get_post_format_string( 'standard' ); ?></label>
     542                                        <?php
     543
     544                                        foreach ( $post_formats[0] as $format ) {
     545                                                $attr_format = esc_attr( $format );
     546                                                ?>
     547                                                <br />
     548                                                <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 ); ?> />
     549                                                <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>
     550                                                <?php
     551                                         }
     552                                         ?>
     553                                </div>
     554                                <?php
     555                        }
     556                }
     557        }
     558
     559        /**
     560         * Outputs the categories HTML.
     561         *
     562         * @since 4.2.0
     563         * @access public
     564         *
     565         * @param WP_Post $post Post object.
     566         */
     567        function categories_html( $post ) {
     568                $taxonomy = get_taxonomy( 'category' );
     569
     570                if ( current_user_can( $taxonomy->cap->edit_terms ) ) {
     571                        ?>
     572                        <button type="button" class="add-cat-toggle button-subtle">
     573                                <span class="dashicons dashicons-plus"></span>
     574                        </button>
     575                        <div class="add-category is-hidden">
     576                                <label class="screen-reader-text" for="new-category"><?php echo $taxonomy->labels->add_new_item; ?></label>
     577                                <input type="text" id="new-category" class="add-category-name" placeholder="<?php echo esc_attr( $taxonomy->labels->new_item_name ); ?>" value="" aria-required="true">
     578                                <label class="screen-reader-text" for="new-category-parent"><?php echo $taxonomy->labels->parent_item_colon; ?></label>
     579                                <div class="postform-wrapper">
     580                                        <?php
     581                                        wp_dropdown_categories( array(
     582                                                'taxonomy'         => 'category',
     583                                                'hide_empty'       => 0,
     584                                                'name'             => 'new-category-parent',
     585                                                'orderby'          => 'name',
     586                                                'hierarchical'     => 1,
     587                                                'show_option_none' => '&mdash; ' . $taxonomy->labels->parent_item . ' &mdash;'
     588                                        ) );
     589                                        ?>
     590                                </div>
     591                                <button type="button" class="button add-cat-submit"><?php _e( 'Add' ); ?></button>
     592                        </div>
     593                <?php } ?>
     594                <div class="categories-search-wrapper">
     595                        <input id="categories-search" type="search" class="categories-search" placeholder="<?php esc_attr_e( 'Search categories' ) ?>">
     596                        <label for="categories-search">
     597                                <span class="dashicons dashicons-search"></span>
     598                        </label>
     599                </div>
     600                <ul class="categories-select">
     601                        <?php wp_terms_checklist( $post->ID, array( 'taxonomy' => 'category' ) ); ?>
     602                </ul>
     603                <?php
     604        }
     605
     606        /**
     607         * Outputs the tags HTML.
     608         *
     609         * @since 4.2.0
     610         * @access public
     611         *
     612         * @param WP_Post $post Post object.
     613         */
     614        function tags_html( $post ) {
     615                $taxonomy              = get_taxonomy( 'post_tag' );
     616                $user_can_assign_terms = current_user_can( $taxonomy->cap->assign_terms );
     617                $esc_tags              = get_terms_to_edit( $post->ID, 'post_tag' );
     618
     619                if ( ! $esc_tags || is_wp_error( $esc_tags ) ) {
     620                        $esc_tags = '';
     621                }
     622                ?>
     623                <div class="tagsdiv" id="post_tag">
     624                        <div class="jaxtag">
     625                        <input type="hidden" name="tax_input[post_tag]" class="the-tags" value="<?php echo $esc_tags; // escaped in get_terms_to_edit() ?>">
     626
     627                        <?php
     628                        if ( $user_can_assign_terms ) {
     629                                ?>
     630                                <div class="ajaxtag hide-if-no-js">
     631                                        <label class="screen-reader-text" for="new-tag-post_tag"><?php _e( 'Tags' ); ?></label>
     632                                        <div class="taghint"><?php echo $taxonomy->labels->add_new_item; ?></div>
     633                                        <p>
     634                                                <input type="text" id="new-tag-post_tag" name="newtag[post_tag]" class="newtag form-input-tip" size="16" autocomplete="off" value="" />
     635                                                <button type="button" class="button tagadd"><?php _e( 'Add' ); ?></button>
     636                                        </p>
     637                                </div>
     638                                <p class="howto">
     639                                        <?php echo $taxonomy->labels->separate_items_with_commas; ?>
     640                                </p>
     641                        <?php } ?>
     642                        </div>
     643                        <div class="tagchecklist"></div>
     644                </div>
     645                <?php
     646                if ( $user_can_assign_terms ) {
     647                        ?>
     648                        <p>
     649                                <a href="#titlediv" class="tagcloud-link" id="link-post_tag"><?php echo $taxonomy->labels->choose_from_most_used; ?></a>
     650                        </p>
     651                        <?php
     652                }
     653        }
     654
     655        /**
     656         * Serves the app's base HTML, which in turns calls the load script.
     657         *
     658         * @since 4.2.0
     659         * @access public
     660         */
     661        public function html() {
     662                global $wp_locale, $hook_suffix;
     663
     664                // Get data, new (POST) and old (GET).
     665                $data = $this->merge_or_fetch_data();
     666
     667                // Get site settings array/data.
     668                $site_settings = $this->site_settings();
     669
     670                // Set the passed data.
     671                $data['_version'] = $site_settings['version'];
     672
     673                // Add press-this-editor.css and remove theme's editor-style.css, if any.
     674                remove_editor_styles();
     675
     676                add_filter( 'mce_css', array( $this, 'add_editor_style' ) );
     677
     678                if ( ! empty( $GLOBALS['is_IE'] ) ) {
     679                        @header( 'X-UA-Compatible: IE=edge' );
     680                }
     681
     682                @header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) );
     683
     684?>
     685<!DOCTYPE html>
     686<!--[if IE 7]>         <html class="lt-ie9 lt-ie8" <?php language_attributes(); ?>> <![endif]-->
     687<!--[if IE 8]>         <html class="lt-ie9" <?php language_attributes(); ?>> <![endif]-->
     688<!--[if gt IE 8]><!--> <html <?php language_attributes(); ?>> <!--<![endif]-->
     689<head>
     690        <meta http-equiv="Content-Type" content="<?php esc_attr( bloginfo( 'html_type' ) ); ?>; charset=<?php echo esc_attr( get_option( 'blog_charset' ) ); ?>" />
     691        <meta name="viewport" content="width=device-width">
     692        <title><?php esc_html_e( 'Press This!' ) ?></title>
     693
     694        <script>
     695                window.wpPressThisData   = <?php echo json_encode( $data ) ?>;
     696                window.wpPressThisConfig = <?php echo json_encode( $site_settings ) ?>;
     697        </script>
     698
     699        <script type="text/javascript">
     700                var ajaxurl = '<?php echo esc_js( admin_url( 'admin-ajax.php', 'relative' ) ); ?>',
     701                        pagenow = 'press-this',
     702                        typenow = 'post',
     703                        adminpage = 'press-this-php',
     704                        thousandsSeparator = '<?php echo addslashes( $wp_locale->number_format['thousands_sep'] ); ?>',
     705                        decimalPoint = '<?php echo addslashes( $wp_locale->number_format['decimal_point'] ); ?>',
     706                        isRtl = <?php echo esc_js( (int) is_rtl() ); ?>;
     707        </script>
     708
     709        <?php
     710                /*
     711                 * $post->ID is needed for the embed shortcode so we can show oEmbed previews in the editor.
     712                 * Maybe find a way without it.
     713                 */
     714                $post = get_default_post_to_edit( 'post', true );
     715                $post_ID = (int) $post->ID;
     716
     717                wp_enqueue_style( 'press-this' );
     718                wp_enqueue_script( 'press-this' );
     719                wp_enqueue_script( 'json2' );
     720                wp_enqueue_media( array( 'post' => $post->ID ) );
     721                wp_enqueue_script( 'editor' );
     722
     723                $supports_formats = false;
     724                $post_format      = 0;
     725
     726                if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) ) {
     727                        $supports_formats = true;
     728
     729                        if ( ! ( $post_format = get_post_format( $post->ID ) ) ) {
     730                                $post_format = 0;
     731                        }
     732                }
     733
     734                /** This action is documented in wp-admin/admin-header.php */
     735                do_action( 'admin_enqueue_scripts', $hook_suffix );
     736
     737                /** This action is documented in wp-admin/admin-header.php */
     738                do_action( 'admin_print_styles' );
     739
     740                /** This action is documented in wp-admin/admin-header.php */
     741                do_action( 'admin_print_scripts' );
     742
     743        ?>
     744</head>
     745<body>
     746        <div id="adminbar" class="adminbar">
     747                <h1 id="current-site" class="current-site">
     748                        <span class="dashicons dashicons-wordpress"></span>
     749                        <span><?php bloginfo( 'name' ); ?></span>
     750                </h1>
     751                <button type="button" class="options-open button-subtle">
     752                        <span class="dashicons dashicons-tag"></span><span class="screen-reader-text"><?php _e( 'Show post options' ); ?></span>
     753                </button>
     754                <button type="button" class="options-close button-subtle is-hidden"><?php _e( 'Done' ); ?></button>
     755        </div>
     756
     757        <div id="scanbar" class="scan">
     758                <form method="GET">
     759                        <input type="url" name="u" id="url-scan" class="scan-url" value="" placeholder="<?php esc_attr_e( 'Enter a URL to scan' ) ?>" />
     760                        <input type="submit" name="url-scan-submit" id="url-scan-submit" class="scan-submit" value="<?php esc_attr_e( 'Scan' ) ?>" />
     761                </form>
     762        </div>
     763
     764        <form id="pressthis-form" name="pressthis-form" method="POST" autocomplete="off">
     765                <input type="hidden" name="post_ID" id="post_ID" value="<?php echo esc_attr( $post_ID ); ?>" />
     766                <input type="hidden" name="action" value="press-this-save-post" />
     767                <input type="hidden" name="post_status" id="post_status" value="draft" />
     768                <?php
     769                wp_nonce_field( 'press-this', 'pressthis-nonce', false );
     770                wp_nonce_field( 'add-category', '_ajax_nonce-add-category', false );
     771                ?>
     772                <input type="hidden" name="title" id="title-field" value="" />
     773
     774        <div class="wrapper">
     775                <div class="editor-wrapper">
     776                        <div class="alerts">
     777                                <p class="alert is-notice is-hidden should-upgrade-bookmarklet">
     778                                        <?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' ) ); ?>
     779                                </p>
     780                        </div>
     781
     782                        <div id='app-container' class="editor">
     783                                <span id="title-container-label" class="post-title-placeholder" aria-hidden="true"><?php _e( 'Post title' ); ?></span>
     784                                <h2 id="title-container" class="post-title" contenteditable="true" spellcheck="true" aria-label="<?php esc_attr_e( 'Post title' ); ?>" tabindex="0"></h2>
     785                                <div id='featured-media-container' class="featured-container no-media">
     786                                        <div id='all-media-widget' class="all-media">
     787                                                <div id='all-media-container'></div>
     788                                        </div>
     789                                </div>
     790
     791                                <?php
     792                                wp_editor( '', 'pressthis', array(
     793                                        'drag_drop_upload' => true,
     794                                        'editor_height'    => 600,
     795                                        'media_buttons'    => false,
     796                                        'teeny'            => true,
     797                                        'tinymce'          => array(
     798                                                'resize'                => false,
     799                                                'wordpress_adv_hidden'  => false,
     800                                                'add_unload_trigger'    => false,
     801                                                'statusbar'             => false,
     802                                                'autoresize_min_height' => 600,
     803                                                'wp_autoresize_on'      => true,
     804                                                'plugins'               => 'lists,media,paste,tabfocus,fullscreen,wordpress,wpautoresize,wpeditimage,wpgallery,wplink,wpview',
     805                                                'toolbar1'              => 'bold,italic,bullist,numlist,blockquote,link,unlink',
     806                                                'toolbar2'              => 'undo,redo',
     807                                        ),
     808                                        'quicktags'        => false,
     809                                ) );
     810
     811                                ?>
     812                        </div>
     813                </div>
     814
     815                <div class="options-panel is-off-screen is-hidden">
     816                        <div class="post-options">
     817
     818                                <?php if ( $supports_formats ) : ?>
     819                                        <button type="button" class="button-reset post-option">
     820                                                <span class="dashicons dashicons-admin-post"></span>
     821                                                <span class="post-option-title"><?php _e( 'Format' ); ?></span>
     822                                                <span class="post-option-contents" id="post-option-post-format"><?php echo esc_html( get_post_format_string( $post_format ) ); ?></span>
     823                                                <span class="dashicons dashicons-arrow-right-alt2"></span>
     824                                        </button>
     825                                <?php endif; ?>
     826
     827                                <button type="button" class="button-reset post-option">
     828                                        <span class="dashicons dashicons-category"></span>
     829                                        <span class="post-option-title"><?php _e( 'Categories' ); ?></span>
     830                                        <span class="post-option-contents" id="post-option-category"></span>
     831                                        <span class="dashicons dashicons-arrow-right-alt2"></span>
     832                                </button>
     833
     834                                <button type="button" class="button-reset post-option">
     835                                        <span class="dashicons dashicons-tag"></span>
     836                                        <span class="post-option-title"><?php _e( 'Tags' ); ?></span>
     837                                        <span class="post-option-contents" id="post-option-tags"></span>
     838                                        <span class="dashicons dashicons-arrow-right-alt2"></span>
     839                                </button>
     840                        </div>
     841
     842                        <?php if ( $supports_formats ) : ?>
     843                                <div class="setting-modal is-off-screen is-hidden">
     844                                        <button type="button" class="button-reset modal-close">
     845                                                <span class="dashicons dashicons-arrow-left-alt2"></span><span class="setting-title"><?php _e( 'Post format' ); ?></span>
     846                                        </button>
     847                                        <?php $this->post_formats_html( $post ); ?>
     848                                </div>
     849                        <?php endif; ?>
     850
     851                        <div class="setting-modal is-off-screen is-hidden">
     852                                <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>
     853                                <?php $this->categories_html( $post ); ?>
     854                        </div>
     855
     856                        <div class="setting-modal tags is-off-screen is-hidden">
     857                                <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>
     858                                <?php $this->tags_html( $post ); ?>
     859                        </div>
     860                </div><!-- .options-panel -->
     861        </div><!-- .wrapper -->
     862
     863        <div class="press-this-actions">
     864                <div class="pressthis-media-buttons">
     865                        <button type="button" class="insert-media button-subtle" data-editor="pressthis">
     866                                <span class="dashicons dashicons-admin-media"></span>
     867                                <span class="screen-reader-text"><?php _e( 'Add Media' ); ?></span>
     868                        </button>
     869                </div>
     870                <div class="post-actions">
     871                        <button type="button" class="button-subtle" id="draft-field"><?php _e( 'Save Draft' ); ?></button>
     872                        <button type="button" class="button-primary" id="publish-field"><?php _e( 'Publish' ); ?></button>
     873                </div>
     874        </div>
     875        </form>
     876
     877        <?php
     878
     879                // TODO: consider running "special" press-this hooks here?
     880                // Maybe better so we don't output stuff accidentaly added by plugins. Would probably prevent some errors.
     881                do_action( 'admin_footer', '' );
     882                do_action( 'admin_print_footer_scripts' );
     883
     884        ?>
     885</body>
     886</html>
     887<?php
     888                die();
     889        }
     890}
     891$GLOBALS['wp_press_this'] = new WP_Press_This;
  • src/wp-admin/js/bookmarklet.js

     
     1( function( window, document, href, pt_url ) {
     2        var encodeURI = window.encodeURIComponent,
     3                form = document.createElement( 'form' ),
     4                head = document.getElementsByTagName( 'head' )[0],
     5                img = new Image(),
     6                target = '_press_this_app',
     7                windowWidth, windowHeight,
     8                metas, links, content, imgs, ifrs,
     9                vid, selection;
     10
     11        if ( ! pt_url ) {
     12                return;
     13        }
     14
     15        if ( window.getSelection ) {
     16                selection = window.getSelection() + '';
     17        } else if ( document.getSelection ) {
     18                selection = document.getSelection() + '';
     19        } else if ( document.selection ) {
     20                selection = document.selection.createRange().text;
     21        }
     22
     23        pt_url += ( pt_url.indexOf( '?' ) > -1 ? '&' : '?' ) + 'buster=' + ( new Date().getTime() );
     24
     25        if ( document.title.length && document.title.length <= 512 ) {
     26                pt_url += '&t=' + encodeURI( document.title );
     27        }
     28
     29        if ( selection && selection.length <= 512 ) {
     30                pt_url += '&s=' + encodeURI( selection );
     31        }
     32
     33        if ( href.match( /^https?:/ ) ) {
     34                pt_url += '&u=' + encodeURI( href );
     35        } else {
     36                top.location.href = pt_url;
     37                return;
     38        }
     39
     40        function add( name, value ) {
     41                if ( typeof value === 'undefined' ) {
     42                        return;
     43                }
     44
     45                var input = document.createElement( 'input' );
     46
     47                input.name = name;
     48                input.value = value;
     49                input.type = 'hidden';
     50
     51                form.appendChild( input );
     52        }
     53
     54        if ( href.match( /\/\/www\.youtube\.com\/watch/ ) ) {
     55                add( '_embed[]', href );
     56        } else if ( href.match( /\/\/vimeo\.com\/(.+\/)?([\d]+)$/ ) ) {
     57                add( '_embed[]', href );
     58        } else if ( href.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
     59                add( '_embed[]', href );
     60        } else if ( href.match( /\/\/soundcloud\.com\/.+$/ ) ) {
     61                add( '_embed[]', href );
     62        } else if ( href.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
     63                add( '_embed[]', href );
     64        } else if ( href.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
     65                add( '_embed[]', href );
     66        }
     67
     68        metas = head.getElementsByTagName( 'meta' ) || [];
     69
     70        for ( var m = 0; m < metas.length; m++ ) {
     71                if ( m >= 50 ) {
     72                        break;
     73                }
     74
     75                var q = metas[ m ],
     76                        q_name = q.getAttribute( 'name' ),
     77                        q_prop = q.getAttribute( 'property' ),
     78                        q_cont = q.getAttribute( 'content' );
     79
     80                if ( q_name ) {
     81                        add( '_meta[' + q_name + ']', q_cont );
     82                } else if ( q_prop ) {
     83                        add( '_meta[' + q_prop + ']', q_cont );
     84                }
     85        }
     86
     87        links = head.getElementsByTagName( 'link' ) || [];
     88
     89        for ( var y = 0; y < links.length; y++ ) {
     90                if ( y >= 50 ) {
     91                        break;
     92                }
     93
     94                var g = links[ y ],
     95                        g_rel = g.getAttribute( 'rel' );
     96
     97                if ( g_rel ) {
     98                        switch ( g_rel ) {
     99                                case 'canonical':
     100                                case 'icon':
     101                                case 'shortlink':
     102                                        add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
     103                                        break;
     104                                case 'alternate':
     105                                        if ( 'application/json+oembed' === g.getAttribute( 'type' ) ) {
     106                                                add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
     107                                        } else if ( 'handheld' === g.getAttribute( 'media' ) ) {
     108                                                add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
     109                                        }
     110                        }
     111                }
     112        }
     113
     114        if ( document.body.getElementsByClassName ) {
     115                content = document.body.getElementsByClassName( 'hfeed' )[0];
     116        }
     117
     118        content = document.getElementById( 'content' ) || content || document.body;
     119        imgs = content.getElementsByTagName( 'img' ) || [];
     120
     121        for ( var n = 0; n < imgs.length; n++ ) {
     122                if ( n >= 100 ) {
     123                        break;
     124                }
     125
     126                if ( imgs[ n ].src.indexOf( 'avatar' ) > -1 || imgs[ n ].className.indexOf( 'avatar' ) > -1 ) {
     127                        continue;
     128                }
     129
     130                img.src = imgs[ n ].src;
     131
     132                if ( img.width >= 256 && img.height >= 128 ) {
     133                        add( '_img[]', img.src );
     134                }
     135        }
     136
     137        ifrs = document.body.getElementsByTagName( 'iframe' ) || [];
     138
     139        for ( var p = 0; p < ifrs.length; p++ ) {
     140                if ( p >= 100 ) {
     141                        break;
     142                }
     143
     144                vid = ifrs[ p ].src.match(/\/\/www\.youtube\.com\/embed\/([^\?]+)\?.+$/);
     145
     146                if ( vid && 2 === vid.length ) {
     147                        add( '_embed[]', 'https://www.youtube.com/watch?v=' + vid[1] );
     148                }
     149
     150                vid = ifrs[ p ].src.match( /\/\/player\.vimeo\.com\/video\/([\d]+)$/ );
     151
     152                if ( vid && 2 === vid.length ) {
     153                        add( '_embed[]', 'https://vimeo.com/' + vid[1] );
     154                }
     155
     156                vid = ifrs[ p ].src.match( /\/\/vine\.co\/v\/([^\/]+)\/embed/ );
     157
     158                if ( vid && 2 === vid.length ) {
     159                        add( '_embed[]', 'https://vine.co/v/' + vid[1] );
     160                }
     161        }
     162
     163        if ( document.title && document.title > 512 ) {
     164                add( 't', document.title );
     165        }
     166
     167        if ( selection && selection.length > 512 ) {
     168                add( 's', selection );
     169        }
     170
     171        form.setAttribute( 'method', 'POST' );
     172        form.setAttribute( 'action', pt_url );
     173        form.setAttribute( 'target', target );
     174        form.setAttribute( 'style', 'display: none;' );
     175
     176        windowWidth  = window.outerWidth || document.documentElement.clientWidth || 600;
     177        windowHeight = window.outerHeight || document.documentElement.clientHeight || 700;
     178
     179        windowWidth = ( windowWidth < 800 || windowWidth > 5000 ) ? 600 : ( windowWidth * 0.7 );
     180        windowHeight = ( windowHeight < 800 || windowHeight > 3000 ) ? 700 : ( windowHeight * 0.9 );
     181
     182        window.open( 'about:blank', target, 'width=' + windowWidth + ',height=' + windowHeight );
     183
     184        document.body.appendChild( form );
     185
     186        form.submit();
     187} )( window, document, top.location.href, window.pt_url );
     188( function( window, document, href, pt_url ) {
     189        var encodeURI = window.encodeURIComponent,
     190                form = document.createElement( 'form' ),
     191                head = document.getElementsByTagName( 'head' )[0],
     192                img = new Image(),
     193                target = '_press_this_app',
     194                windowWidth, windowHeight,
     195                metas, links, content, imgs, ifrs,
     196                vid, selection;
     197
     198        if ( ! pt_url ) {
     199                return;
     200        }
     201
     202        if ( window.getSelection ) {
     203                selection = window.getSelection() + '';
     204        } else if ( document.getSelection ) {
     205                selection = document.getSelection() + '';
     206        } else if ( document.selection ) {
     207                selection = document.selection.createRange().text;
     208        }
     209
     210        pt_url += ( pt_url.indexOf( '?' ) > -1 ? '&' : '?' ) + 'buster=' + ( new Date().getTime() );
     211
     212        if ( document.title.length && document.title.length <= 512 ) {
     213                pt_url += '&t=' + encodeURI( document.title );
     214        }
     215
     216        if ( selection && selection.length <= 512 ) {
     217                pt_url += '&s=' + encodeURI( selection );
     218        }
     219
     220        if ( href.match( /^https?:/ ) ) {
     221                pt_url += '&u=' + encodeURI( href );
     222        } else {
     223                top.location.href = pt_url;
     224                return;
     225        }
     226
     227        function add( name, value ) {
     228                if ( typeof value === 'undefined' ) {
     229                        return;
     230                }
     231
     232                var input = document.createElement( 'input' );
     233
     234                input.name = name;
     235                input.value = value;
     236                input.type = 'hidden';
     237
     238                form.appendChild( input );
     239        }
     240
     241        if ( href.match( /\/\/www\.youtube\.com\/watch/ ) ) {
     242                add( '_embed[]', href );
     243        } else if ( href.match( /\/\/vimeo\.com\/(.+\/)?([\d]+)$/ ) ) {
     244                add( '_embed[]', href );
     245        } else if ( href.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
     246                add( '_embed[]', href );
     247        } else if ( href.match( /\/\/soundcloud\.com\/.+$/ ) ) {
     248                add( '_embed[]', href );
     249        } else if ( href.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
     250                add( '_embed[]', href );
     251        } else if ( href.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
     252                add( '_embed[]', href );
     253        }
     254
     255        metas = head.getElementsByTagName( 'meta' ) || [];
     256
     257        for ( var m = 0; m < metas.length; m++ ) {
     258                if ( m >= 50 ) {
     259                        break;
     260                }
     261
     262                var q = metas[ m ],
     263                        q_name = q.getAttribute( 'name' ),
     264                        q_prop = q.getAttribute( 'property' ),
     265                        q_cont = q.getAttribute( 'content' );
     266
     267                if ( q_name ) {
     268                        add( '_meta[' + q_name + ']', q_cont );
     269                } else if ( q_prop ) {
     270                        add( '_meta[' + q_prop + ']', q_cont );
     271                }
     272        }
     273
     274        links = head.getElementsByTagName( 'link' ) || [];
     275
     276        for ( var y = 0; y < links.length; y++ ) {
     277                if ( y >= 50 ) {
     278                        break;
     279                }
     280
     281                var g = links[ y ],
     282                        g_rel = g.getAttribute( 'rel' );
     283
     284                if ( g_rel ) {
     285                        switch ( g_rel ) {
     286                                case 'canonical':
     287                                case 'icon':
     288                                case 'shortlink':
     289                                        add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
     290                                        break;
     291                                case 'alternate':
     292                                        if ( 'application/json+oembed' === g.getAttribute( 'type' ) ) {
     293                                                add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
     294                                        } else if ( 'handheld' === g.getAttribute( 'media' ) ) {
     295                                                add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
     296                                        }
     297                        }
     298                }
     299        }
     300
     301        if ( document.body.getElementsByClassName ) {
     302                content = document.body.getElementsByClassName( 'hfeed' )[0];
     303        }
     304
     305        content = document.getElementById( 'content' ) || content || document.body;
     306        imgs = content.getElementsByTagName( 'img' ) || [];
     307
     308        for ( var n = 0; n < imgs.length; n++ ) {
     309                if ( n >= 100 ) {
     310                        break;
     311                }
     312
     313                if ( imgs[ n ].src.indexOf( 'avatar' ) > -1 || imgs[ n ].className.indexOf( 'avatar' ) > -1 ) {
     314                        continue;
     315                }
     316
     317                img.src = imgs[ n ].src;
     318
     319                if ( img.width >= 256 && img.height >= 128 ) {
     320                        add( '_img[]', img.src );
     321                }
     322        }
     323
     324        ifrs = document.body.getElementsByTagName( 'iframe' ) || [];
     325
     326        for ( var p = 0; p < ifrs.length; p++ ) {
     327                if ( p >= 100 ) {
     328                        break;
     329                }
     330
     331                vid = ifrs[ p ].src.match(/\/\/www\.youtube\.com\/embed\/([^\?]+)\?.+$/);
     332
     333                if ( vid && 2 === vid.length ) {
     334                        add( '_embed[]', 'https://www.youtube.com/watch?v=' + vid[1] );
     335                }
     336
     337                vid = ifrs[ p ].src.match( /\/\/player\.vimeo\.com\/video\/([\d]+)$/ );
     338
     339                if ( vid && 2 === vid.length ) {
     340                        add( '_embed[]', 'https://vimeo.com/' + vid[1] );
     341                }
     342
     343                vid = ifrs[ p ].src.match( /\/\/vine\.co\/v\/([^\/]+)\/embed/ );
     344
     345                if ( vid && 2 === vid.length ) {
     346                        add( '_embed[]', 'https://vine.co/v/' + vid[1] );
     347                }
     348        }
     349
     350        if ( document.title && document.title > 512 ) {
     351                add( 't', document.title );
     352        }
     353
     354        if ( selection && selection.length > 512 ) {
     355                add( 's', selection );
     356        }
     357
     358        form.setAttribute( 'method', 'POST' );
     359        form.setAttribute( 'action', pt_url );
     360        form.setAttribute( 'target', target );
     361        form.setAttribute( 'style', 'display: none;' );
     362
     363        windowWidth  = window.outerWidth || document.documentElement.clientWidth || 600;
     364        windowHeight = window.outerHeight || document.documentElement.clientHeight || 700;
     365
     366        windowWidth = ( windowWidth < 800 || windowWidth > 5000 ) ? 600 : ( windowWidth * 0.7 );
     367        windowHeight = ( windowHeight < 800 || windowHeight > 3000 ) ? 700 : ( windowHeight * 0.9 );
     368
     369        window.open( 'about:blank', target, 'width=' + windowWidth + ',height=' + windowHeight );
     370
     371        document.body.appendChild( form );
     372
     373        form.submit();
     374} )( window, document, top.location.href, window.pt_url );
     375( function( window, document, href, pt_url ) {
     376        var encodeURI = window.encodeURIComponent,
     377                form = document.createElement( 'form' ),
     378                head = document.getElementsByTagName( 'head' )[0],
     379                img = new Image(),
     380                target = '_press_this_app',
     381                windowWidth, windowHeight,
     382                metas, links, content, imgs, ifrs,
     383                vid, selection;
     384
     385        if ( ! pt_url ) {
     386                return;
     387        }
     388
     389        if ( window.getSelection ) {
     390                selection = window.getSelection() + '';
     391        } else if ( document.getSelection ) {
     392                selection = document.getSelection() + '';
     393        } else if ( document.selection ) {
     394                selection = document.selection.createRange().text;
     395        }
     396
     397        pt_url += ( pt_url.indexOf( '?' ) > -1 ? '&' : '?' ) + 'buster=' + ( new Date().getTime() );
     398
     399        if ( document.title.length && document.title.length <= 512 ) {
     400                pt_url += '&t=' + encodeURI( document.title );
     401        }
     402
     403        if ( selection && selection.length <= 512 ) {
     404                pt_url += '&s=' + encodeURI( selection );
     405        }
     406
     407        if ( href.match( /^https?:/ ) ) {
     408                pt_url += '&u=' + encodeURI( href );
     409        } else {
     410                top.location.href = pt_url;
     411                return;
     412        }
     413
     414        function add( name, value ) {
     415                if ( typeof value === 'undefined' ) {
     416                        return;
     417                }
     418
     419                var input = document.createElement( 'input' );
     420
     421                input.name = name;
     422                input.value = value;
     423                input.type = 'hidden';
     424
     425                form.appendChild( input );
     426        }
     427
     428        if ( href.match( /\/\/www\.youtube\.com\/watch/ ) ) {
     429                add( '_embed[]', href );
     430        } else if ( href.match( /\/\/vimeo\.com\/(.+\/)?([\d]+)$/ ) ) {
     431                add( '_embed[]', href );
     432        } else if ( href.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
     433                add( '_embed[]', href );
     434        } else if ( href.match( /\/\/soundcloud\.com\/.+$/ ) ) {
     435                add( '_embed[]', href );
     436        } else if ( href.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
     437                add( '_embed[]', href );
     438        } else if ( href.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
     439                add( '_embed[]', href );
     440        }
     441
     442        metas = head.getElementsByTagName( 'meta' ) || [];
     443
     444        for ( var m = 0; m < metas.length; m++ ) {
     445                if ( m >= 50 ) {
     446                        break;
     447                }
     448
     449                var q = metas[ m ],
     450                        q_name = q.getAttribute( 'name' ),
     451                        q_prop = q.getAttribute( 'property' ),
     452                        q_cont = q.getAttribute( 'content' );
     453
     454                if ( q_name ) {
     455                        add( '_meta[' + q_name + ']', q_cont );
     456                } else if ( q_prop ) {
     457                        add( '_meta[' + q_prop + ']', q_cont );
     458                }
     459        }
     460
     461        links = head.getElementsByTagName( 'link' ) || [];
     462
     463        for ( var y = 0; y < links.length; y++ ) {
     464                if ( y >= 50 ) {
     465                        break;
     466                }
     467
     468                var g = links[ y ],
     469                        g_rel = g.getAttribute( 'rel' );
     470
     471                if ( g_rel ) {
     472                        switch ( g_rel ) {
     473                                case 'canonical':
     474                                case 'icon':
     475                                case 'shortlink':
     476                                        add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
     477                                        break;
     478                                case 'alternate':
     479                                        if ( 'application/json+oembed' === g.getAttribute( 'type' ) ) {
     480                                                add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
     481                                        } else if ( 'handheld' === g.getAttribute( 'media' ) ) {
     482                                                add( '_links[' + g_rel + ']', g.getAttribute( 'href' ) );
     483                                        }
     484                        }
     485                }
     486        }
     487
     488        if ( document.body.getElementsByClassName ) {
     489                content = document.body.getElementsByClassName( 'hfeed' )[0];
     490        }
     491
     492        content = document.getElementById( 'content' ) || content || document.body;
     493        imgs = content.getElementsByTagName( 'img' ) || [];
     494
     495        for ( var n = 0; n < imgs.length; n++ ) {
     496                if ( n >= 100 ) {
     497                        break;
     498                }
     499
     500                if ( imgs[ n ].src.indexOf( 'avatar' ) > -1 || imgs[ n ].className.indexOf( 'avatar' ) > -1 ) {
     501                        continue;
     502                }
     503
     504                img.src = imgs[ n ].src;
     505
     506                if ( img.width >= 256 && img.height >= 128 ) {
     507                        add( '_img[]', img.src );
     508                }
     509        }
     510
     511        ifrs = document.body.getElementsByTagName( 'iframe' ) || [];
     512
     513        for ( var p = 0; p < ifrs.length; p++ ) {
     514                if ( p >= 100 ) {
     515                        break;
     516                }
     517
     518                vid = ifrs[ p ].src.match(/\/\/www\.youtube\.com\/embed\/([^\?]+)\?.+$/);
     519
     520                if ( vid && 2 === vid.length ) {
     521                        add( '_embed[]', 'https://www.youtube.com/watch?v=' + vid[1] );
     522                }
     523
     524                vid = ifrs[ p ].src.match( /\/\/player\.vimeo\.com\/video\/([\d]+)$/ );
     525
     526                if ( vid && 2 === vid.length ) {
     527                        add( '_embed[]', 'https://vimeo.com/' + vid[1] );
     528                }
     529
     530                vid = ifrs[ p ].src.match( /\/\/vine\.co\/v\/([^\/]+)\/embed/ );
     531
     532                if ( vid && 2 === vid.length ) {
     533                        add( '_embed[]', 'https://vine.co/v/' + vid[1] );
     534                }
     535        }
     536
     537        if ( document.title && document.title > 512 ) {
     538                add( 't', document.title );
     539        }
     540
     541        if ( selection && selection.length > 512 ) {
     542                add( 's', selection );
     543        }
     544
     545        form.setAttribute( 'method', 'POST' );
     546        form.setAttribute( 'action', pt_url );
     547        form.setAttribute( 'target', target );
     548        form.setAttribute( 'style', 'display: none;' );
     549
     550        windowWidth  = window.outerWidth || document.documentElement.clientWidth || 600;
     551        windowHeight = window.outerHeight || document.documentElement.clientHeight || 700;
     552
     553        windowWidth = ( windowWidth < 800 || windowWidth > 5000 ) ? 600 : ( windowWidth * 0.7 );
     554        windowHeight = ( windowHeight < 800 || windowHeight > 3000 ) ? 700 : ( windowHeight * 0.9 );
     555
     556        window.open( 'about:blank', target, 'width=' + windowWidth + ',height=' + windowHeight );
     557
     558        document.body.appendChild( form );
     559
     560        form.submit();
     561} )( window, document, top.location.href, window.pt_url );
  • src/wp-admin/js/post.js

     
    77
    88window.wp = window.wp || {};
    99
    10 // return an array with any duplicate, whitespace or values removed
    11 function array_unique_noempty(a) {
    12         var out = [];
    13         jQuery.each( a, function(key, val) {
    14                 val = jQuery.trim(val);
    15                 if ( val && jQuery.inArray(val, out) == -1 )
    16                         out.push(val);
    17                 } );
    18         return out;
    19 }
    20 
    21 ( function($) {
     10( function( $ ) {
    2211        var titleHasFocus = false;
    2312
    24 tagBox = {
    25         clean : function(tags) {
    26                 var comma = postL10n.comma;
    27                 if ( ',' !== comma )
    28                         tags = tags.replace(new RegExp(comma, 'g'), ',');
    29                 tags = tags.replace(/\s*,\s*/g, ',').replace(/,+/g, ',').replace(/[,\s]+$/, '').replace(/^[,\s]+/, '');
    30                 if ( ',' !== comma )
    31                         tags = tags.replace(/,/g, comma);
    32                 return tags;
    33         },
    34 
    35         parseTags : function(el) {
    36                 var id = el.id, num = id.split('-check-num-')[1], taxbox = $(el).closest('.tagsdiv'),
    37                         thetags = taxbox.find('.the-tags'), comma = postL10n.comma,
    38                         current_tags = thetags.val().split(comma), new_tags = [];
    39                 delete current_tags[num];
    40 
    41                 $.each( current_tags, function(key, val) {
    42                         val = $.trim(val);
    43                         if ( val ) {
    44                                 new_tags.push(val);
    45                         }
    46                 });
    47 
    48                 thetags.val( this.clean( new_tags.join(comma) ) );
    49 
    50                 this.quickClicks(taxbox);
    51                 return false;
    52         },
    53 
    54         quickClicks : function(el) {
    55                 var thetags = $('.the-tags', el),
    56                         tagchecklist = $('.tagchecklist', el),
    57                         id = $(el).attr('id'),
    58                         current_tags, disabled;
    59 
    60                 if ( !thetags.length )
    61                         return;
    62 
    63                 disabled = thetags.prop('disabled');
    64 
    65                 current_tags = thetags.val().split(postL10n.comma);
    66                 tagchecklist.empty();
    67 
    68                 $.each( current_tags, function( key, val ) {
    69                         var span, xbutton;
    70 
    71                         val = $.trim( val );
    72 
    73                         if ( ! val )
    74                                 return;
    75 
    76                         // Create a new span, and ensure the text is properly escaped.
    77                         span = $('<span />').text( val );
    78 
    79                         // If tags editing isn't disabled, create the X button.
    80                         if ( ! disabled ) {
    81                                 xbutton = $( '<a id="' + id + '-check-num-' + key + '" class="ntdelbutton">X</a>' );
    82                                 xbutton.click( function(){ tagBox.parseTags(this); });
    83                                 span.prepend('&nbsp;').prepend( xbutton );
    84                         }
    85 
    86                         // Append the span to the tag list.
    87                         tagchecklist.append( span );
    88                 });
    89         },
    90 
    91         flushTags : function(el, a, f) {
    92                 var tagsval, newtags, text,
    93                         tags = $('.the-tags', el),
    94                         newtag = $('input.newtag', el),
    95                         comma = postL10n.comma;
    96                 a = a || false;
    97 
    98                 text = a ? $(a).text() : newtag.val();
    99                 tagsval = tags.val();
    100                 newtags = tagsval ? tagsval + comma + text : text;
    101 
    102                 newtags = this.clean( newtags );
    103                 newtags = array_unique_noempty( newtags.split(comma) ).join(comma);
    104                 tags.val(newtags);
    105                 this.quickClicks(el);
    106 
    107                 if ( !a )
    108                         newtag.val('');
    109                 if ( 'undefined' == typeof(f) )
    110                         newtag.focus();
    111 
    112                 return false;
    113         },
    114 
    115         get : function(id) {
    116                 var tax = id.substr(id.indexOf('-')+1);
    117 
    118                 $.post(ajaxurl, {'action':'get-tagcloud', 'tax':tax}, function(r, stat) {
    119                         if ( 0 === r || 'success' != stat )
    120                                 r = wpAjax.broken;
    121 
    122                         r = $('<p id="tagcloud-'+tax+'" class="the-tagcloud">'+r+'</p>');
    123                         $('a', r).click(function(){
    124                                 tagBox.flushTags( $(this).closest('.inside').children('.tagsdiv'), this);
    125                                 return false;
    126                         });
    127 
    128                         $('#'+id).after(r);
    129                 });
    130         },
    131 
    132         init : function() {
    133                 var t = this, ajaxtag = $('div.ajaxtag');
    134 
    135                 $('.tagsdiv').each( function() {
    136                         tagBox.quickClicks(this);
    137                 });
    138 
    139                 $('input.tagadd', ajaxtag).click(function(){
    140                         t.flushTags( $(this).closest('.tagsdiv') );
    141                 });
    142 
    143                 $('div.taghint', ajaxtag).click(function(){
    144                         $(this).css('visibility', 'hidden').parent().siblings('.newtag').focus();
    145                 });
    146 
    147                 $('input.newtag', ajaxtag).blur(function() {
    148                         if ( '' === this.value )
    149                                 $(this).parent().siblings('.taghint').css('visibility', '');
    150                 }).focus(function(){
    151                         $(this).parent().siblings('.taghint').css('visibility', 'hidden');
    152                 }).keyup(function(e){
    153                         if ( 13 == e.which ) {
    154                                 tagBox.flushTags( $(this).closest('.tagsdiv') );
    155                                 return false;
    156                         }
    157                 }).keypress(function(e){
    158                         if ( 13 == e.which ) {
    159                                 e.preventDefault();
    160                                 return false;
    161                         }
    162                 }).each(function(){
    163                         var tax = $(this).closest('div.tagsdiv').attr('id');
    164                         $(this).suggest( ajaxurl + '?action=ajax-tag-search&tax=' + tax, { delay: 500, minchars: 2, multiple: true, multipleSep: postL10n.comma + ' ' } );
    165                 });
    166 
    167                 // save tags on post save/publish
    168                 $('#post').submit(function(){
    169                         $('div.tagsdiv').each( function() {
    170                                 tagBox.flushTags(this, false, 1);
    171                         });
    172                 });
    173 
    174                 // tag cloud
    175                 $('a.tagcloud-link').click(function(){
    176                         tagBox.get( $(this).attr('id') );
    177                         $(this).unbind().click(function(){
    178                                 $(this).siblings('.the-tagcloud').toggle();
    179                                 return false;
    180                         });
    181                         return false;
    182                 });
    183         }
    184 };
    185 
    18613commentsBox = {
    18714        st : 0,
    18815
     
    572399
    573400        // multi-taxonomies
    574401        if ( $('#tagsdiv-post_tag').length ) {
    575                 tagBox.init();
     402                window.tagBox && window.tagBox.init();
    576403        } else {
    577404                $('#side-sortables, #normal-sortables, #advanced-sortables').children('div.postbox').each(function(){
    578405                        if ( this.id.indexOf('tagsdiv-') === 0 ) {
    579                                 tagBox.init();
     406                                window.tagBox && window.tagBox.init();
    580407                                return false;
    581408                        }
    582409                });
  • src/wp-admin/js/press-this.js

     
     1/**
     2 * PressThis App
     3 *
     4 */
     5( function( $, window ) {
     6        var PressThis = function() {
     7                var editor,
     8                        saveAlert             = false,
     9                        $div                  = $( '<div>' ),
     10                        siteConfig            = window.wpPressThisConfig || {},
     11                        data                  = window.wpPressThisData || {},
     12                        smallestWidth         = 128,
     13                        interestingImages         = getInterestingImages( data ) || [],
     14                        interestingEmbeds         = getInterestingEmbeds( data ) || [],
     15                        hasEmptyTitleStr      = false,
     16                        suggestedTitleStr     = getSuggestedTitle( data ),
     17                        suggestedContentStr   = getSuggestedContent( data ),
     18                        hasSetFocus           = false,
     19                        catsCache             = [],
     20                        transitionEndEvent    = ( function() {
     21                                var style = document.documentElement.style;
     22
     23                                if ( typeof style.transition !== 'undefined' ) {
     24                                        return 'transitionend';
     25                                }
     26
     27                                if ( typeof style.WebkitTransition !== 'undefined' ) {
     28                                        return 'webkitTransitionEnd';
     29                                }
     30
     31                                return false;
     32                        }() );
     33
     34                /* ***************************************************************
     35                 * HELPER FUNCTIONS
     36                 *************************************************************** */
     37
     38                /**
     39                 * Emulates our PHP __() gettext function, powered by the strings exported in pressThisL10n.
     40                 *
     41                 * @param key string Key of the string to be translated, as found in pressThisL10n.
     42                 * @returns string Original or translated string, or empty string if no key.
     43                 */
     44                function __( key ) {
     45                        if ( key && window.pressThisL10n ) {
     46                                return window.pressThisL10n[key] || key;
     47                        }
     48
     49                        return key || '';
     50                }
     51
     52                /**
     53                 * Strips HTML tags
     54                 *
     55                 * @param string string Text to have the HTML tags striped out of.
     56                 * @returns string Stripped text.
     57                 */
     58                function stripTags( string ) {
     59                        string = string || '';
     60
     61                        return string
     62                                .replace( /<!--[\s\S]*?(-->|$)/g, '' )
     63                                .replace( /<(script|style)[^>]*>[\s\S]*?(<\/\1>|$)/ig, '' )
     64                                .replace( /<\/?[a-z][^>]*>/ig, '' );
     65                }
     66
     67                // TODO: needed?
     68                function entityEncode( text ) {
     69                        return $div.text( text ).html();
     70                }
     71
     72                /**
     73                 * Strip HTML tags and entity encode some of the HTML special chars.
     74                 *
     75                 * @param text string Text.
     76                 * @returns string Sanitized text.
     77                 */
     78                function sanitizeText( text ) {
     79                        text = stripTags( text );
     80
     81                        return text
     82                                .replace( /\\/, '' )
     83                                .replace( /</g, '&lt;' )
     84                                .replace( />/g, '&gt;' )
     85                                .replace( /"/g, '&quot;' )
     86                                .replace( /'/g, '&#039;' );
     87                }
     88
     89                /**
     90                 * Allow only HTTP or protocol relative URLs.
     91                 *
     92                 * @param url string The URL.
     93                 * @returns string Processed URL.
     94                 */
     95                function checkUrl( url ) {
     96                        url = $.trim( url || '' );
     97
     98                        if ( /^(?:https?:)?\/\//.test( url ) ) {
     99                                url = stripTags( url );
     100                                return url.replace( /["\\]+/g, '' );
     101                        }
     102
     103                        return '';
     104                }
     105
     106                /**
     107                 * Gets the source page's canonical link, based on passed location and meta data.
     108                 *
     109                 * @param data object Usually WpPressThis_App.data
     110                 * @returns string Discovered canonical URL, or empty
     111                 */
     112                function getCanonicalLink( data ) {
     113                        if ( ! data || data.length ) {
     114                                return '';
     115                        }
     116
     117                        var link = '';
     118
     119                        if ( data._links ) {
     120                                if ( data._links.canonical && data._links.canonical.length ) {
     121                                        link = data._links.canonical;
     122                                }
     123                        }
     124
     125                        if ( ! link.length && data.u ) {
     126                                link = data.u;
     127                        }
     128
     129                        if ( ! link.length && data._meta ) {
     130                                if ( data._meta['twitter:url'] && data._meta['twitter:url'].length ) {
     131                                        link = data._meta['twitter:url'];
     132                                } else if ( data._meta['og:url'] && data._meta['og:url'].length ) {
     133                                        link = data._meta['og:url'];
     134                                }
     135                        }
     136
     137                        return decodeURI( link );
     138                }
     139
     140                /**
     141                 * Gets the source page's site name, based on passed meta data.
     142                 *
     143                 * @param data object Usually WpPressThis_App.data
     144                 * @returns string Discovered site name, or empty
     145                 */
     146                function getSourceSiteName( data ) {
     147                        if ( ! data || data.length ) {
     148                                return '';
     149                        }
     150
     151                        var name='';
     152
     153                        if ( data._meta ) {
     154                                if ( data._meta['og:site_name'] && data._meta['og:site_name'].length ) {
     155                                        name = data._meta['og:site_name'];
     156                                } else if ( data._meta['application-name'] && data._meta['application-name'].length ) {
     157                                        name = data._meta['application-name'];
     158                                }
     159                        }
     160
     161                        return name.replace( /\\/g, '' );
     162                }
     163
     164                /**
     165                 * Gets the source page's title, based on passed title and meta data.
     166                 *
     167                 * @param data object Usually WpPressThis_App.data
     168                 * @returns string Discovered page title, or empty
     169                 */
     170                function getSuggestedTitle( data ) {
     171                        if ( ! data || data.length ) {
     172                                return __( 'newPost' );
     173                        }
     174
     175                        var title = '';
     176
     177                        if ( data.t ) {
     178                                title = data.t;
     179                        }
     180
     181                        if ( ! title.length && data._meta ) {
     182                                if ( data._meta['twitter:title'] && data._meta['twitter:title'].length ) {
     183                                        title = data._meta['twitter:title'];
     184                                } else if ( data._meta['og:title'] && data._meta['og:title'].length ) {
     185                                        title = data._meta['og:title'];
     186                                } else if ( data._meta.title && data._meta.title.length ) {
     187                                        title = data._meta.title;
     188                                }
     189                        }
     190
     191                        if ( ! title.length ) {
     192                                title = __( 'newPost' );
     193                                hasEmptyTitleStr = true;
     194                        }
     195
     196                        return title.replace( /\\/g, '' );
     197                }
     198
     199                /**
     200                 * Gets the source page's suggested content, based on passed data (description, selection, etc).
     201                 * Features a blockquoted excerpt, as well as content attribution, if any.
     202                 *
     203                 * @param data object Usually WpPressThis_App.data
     204                 * @returns string Discovered content, or empty
     205                 */
     206                function getSuggestedContent( data ) {
     207                        if ( ! data || data.length ) {
     208                                return '';
     209                        }
     210
     211                        var content   = '',
     212                                title     = getSuggestedTitle( data ),
     213                                url       = getCanonicalLink( data ),
     214                                siteName  = getSourceSiteName( data );
     215
     216                        if ( data.s && data.s.length ) {
     217                                content = data.s;
     218                        } else if ( data._meta ) {
     219                                if ( data._meta['twitter:description'] && data._meta['twitter:description'].length ) {
     220                                        content = data._meta['twitter:description'];
     221                                } else if ( data._meta['og:description'] && data._meta['og:description'].length ) {
     222                                        content = data._meta['og:description'];
     223                                } else if ( data._meta.description && data._meta.description.length ) {
     224                                        content = data._meta.description;
     225                                }
     226                        }
     227
     228                        // Wrap suggested content in blockquote tag, if we have any.
     229                        content = ( content.length ? '<blockquote class="press-this-suggested-content">' + sanitizeText( content ) + '</blockquote>' : '' );
     230
     231                        // Add a source attribution if there is one available.
     232                        if ( ( ( title.length && __( 'newPost' ) !== title ) || siteName.length ) && url.length ) {
     233                                content += '<p class="press-this-suggested-source">';
     234                                content += __( 'source' );
     235                                content += ' <cite>';
     236                                content += __( 'sourceLink').replace( '%1$s', encodeURI( url ) ).replace( '%2$s', sanitizeText( title || siteName ) );
     237                                content += '</cite></p>';
     238                        }
     239
     240                        if ( ! content ) {
     241                                content = '';
     242                        }
     243
     244                        return content.replace( /\\/g, '' );
     245                }
     246
     247                /**
     248                 * Tests if what was passed as an embed URL is deemed to be embeddable in the editor.
     249                 *
     250                 * @param url string Passed URl, usually from WpPressThis_App.data._embed
     251                 * @returns boolean
     252                 */
     253                function isEmbeddable( url ) {
     254                        if ( ! url ) {
     255                                return false;
     256                        } else if ( url.match( /\/\/(m\.|www\.)?youtube\.com\/watch\?/ ) || url.match( /\/youtu\.be\/.+$/ ) ) {
     257                                return true;
     258                        } else if ( url.match( /\/\/vimeo\.com\/(.+\/)?[\d]+$/ ) ) {
     259                                return true;
     260                        } else if ( url.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
     261                                return true;
     262                        } else if ( url.match( /\/\/soundcloud\.com\/.+$/ ) ) {
     263                                return true;
     264                        } else if ( url.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
     265                                return true;
     266                        } else if ( url.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
     267                                return true;
     268                        }
     269
     270                        return false;
     271                }
     272
     273                /**
     274                 * Tests if what was passed as an image URL is deemed to be interesting enough to offer to the user for selection.
     275                 *
     276                 * @param src string Passed URl, usually from WpPressThis_App.data._ing
     277                 * @returns boolean Test for false
     278                 */
     279                function isSrcUninterestingPath( src ) {
     280                        if ( src.match( /\/ad[sx]{1}?\// ) ) {
     281                                // Ads
     282                                return true;
     283                        } else if ( src.match( /(\/share-?this[^\.]+?\.[a-z0-9]{3,4})(\?.*)?$/ ) ) {
     284                                // Share-this type button
     285                                return true;
     286                        } else if ( src.match( /\/(spinner|loading|spacer|blank|rss)\.(gif|jpg|png)/ ) ) {
     287                                // Loaders, spinners, spacers
     288                                return true;
     289                        } else if ( src.match( /\/([^\.\/]+[-_]{1})?(spinner|loading|spacer|blank)s?([-_]{1}[^\.\/]+)?\.[a-z0-9]{3,4}/ ) ) {
     290                                // Fancy loaders, spinners, spacers
     291                                return true;
     292                        } else if ( src.match( /([^\.\/]+[-_]{1})?thumb[^.]*\.(gif|jpg|png)$/ ) ) {
     293                                // Thumbnails, too small, usually irrelevant to context
     294                                return true;
     295                        } else if ( src.match( /\/wp-includes\// ) ) {
     296                                // Classic WP interface images
     297                                return true;
     298                        } else if ( src.match( /[^\d]{1}\d{1,2}x\d+\.(gif|jpg|png)$/ ) ) {
     299                                // Most often tiny buttons/thumbs (< 100px wide)
     300                                return true;
     301                        } else if ( src.indexOf( '/g.gif' ) > -1 ) {
     302                                // Classic WP stats gif
     303                                return true;
     304                        } else if ( src.indexOf( '/pixel.mathtag.com' ) > -1 ) {
     305                                // See mathtag.com
     306                                return true;
     307                        }
     308                        return false;
     309                }
     310
     311                /**
     312                 * Get a list of valid embeds from what was passed via WpPressThis_App.data._embed on page load.
     313                 *
     314                 * @returns array
     315                 */
     316                function getInterestingEmbeds() {
     317                        var embeds             = data._embed || [],
     318                                interestingEmbeds  = [],
     319                                alreadySelected    = [];
     320
     321                        if ( embeds.length ) {
     322                                $.each( embeds, function ( i, src ) {
     323                                        if ( !src || !src.length ) {
     324                                                // Skip: no src value
     325                                                return;
     326                                        } else if ( !isEmbeddable( src ) ) {
     327                                                // Skip: not deemed embeddable
     328                                                return;
     329                                        }
     330
     331                                        var schemelessSrc = src.replace( /^https?:/, '' );
     332
     333                                        if ( $.inArray( schemelessSrc, alreadySelected ) > -1 ) {
     334                                                // Skip: already shown
     335                                                return;
     336                                        }
     337
     338                                        interestingEmbeds.push( src );
     339                                        alreadySelected.push( schemelessSrc );
     340                                } );
     341                        }
     342
     343                        return interestingEmbeds;
     344                }
     345
     346                /**
     347                 * 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.
     348                 *
     349                 * @returns array
     350                 */
     351                function getFeaturedImage( data ) {
     352                        var featured = '';
     353
     354                        if ( ! data || ! data._meta ) {
     355                                return '';
     356                        }
     357
     358                        if ( data._meta['twitter:image0:src'] && data._meta['twitter:image0:src'].length ) {
     359                                featured = data._meta['twitter:image0:src'];
     360                        } else if ( data._meta['twitter:image0'] && data._meta['twitter:image0'].length ) {
     361                                featured = data._meta['twitter:image0'];
     362                        } else if ( data._meta['twitter:image:src'] && data._meta['twitter:image:src'].length ) {
     363                                featured = data._meta['twitter:image:src'];
     364                        } else if ( data._meta['twitter:image'] && data._meta['twitter:image'].length ) {
     365                                featured = data._meta['twitter:image'];
     366                        } else if ( data._meta['og:image'] && data._meta['og:image'].length ) {
     367                                featured = data._meta['og:image'];
     368                        } else if ( data._meta['og:image:secure_url'] && data._meta['og:image:secure_url'].length ) {
     369                                featured = data._meta['og:image:secure_url'];
     370                        }
     371
     372                        featured = checkUrl( featured );
     373
     374                        return ( isSrcUninterestingPath( featured ) ) ? '' : featured;
     375                }
     376
     377                /**
     378                 * Get a list of valid images from what was passed via WpPressThis_App.data._img and WpPressThis_App.data._meta on page load.
     379                 *
     380                 * @returns array
     381                 */
     382                function getInterestingImages( data ) {
     383                        var imgs             = data._img || [],
     384                                featuredPict     = getFeaturedImage( data ) || '',
     385                                interestingImgs  = [],
     386                                alreadySelected  = [];
     387
     388                        if ( featuredPict.length ) {
     389                                interestingImgs.push( featuredPict );
     390                                alreadySelected.push( featuredPict.replace(/^https?:/, '') );
     391                        }
     392
     393                        if ( imgs.length ) {
     394                                $.each( imgs, function ( i, src ) {
     395                                        src = src.replace( /http:\/\/[\d]+\.gravatar\.com\//, 'https://secure.gravatar.com/' );
     396                                        src = checkUrl( src );
     397
     398                                        if ( ! src || ! src.length ) {
     399                                                // Skip: no src value
     400                                                return;
     401                                        }
     402
     403                                        var schemelessSrc = src.replace( /^https?:/, '' );
     404
     405                                        if ( Array.prototype.indexOf && alreadySelected.indexOf( schemelessSrc ) > -1 ) {
     406                                                // Skip: already shown
     407                                                return;
     408                                        } else if ( isSrcUninterestingPath( src ) ) {
     409                                                // Skip: spinner, stat, ad, or spacer pict
     410                                                return;
     411                                        } else if ( src.indexOf( 'avatar' ) > -1 && interestingImgs.length >= 15 ) {
     412                                                // Skip:  some type of avatar and we've already gathered more than 23 diff images to show
     413                                                return;
     414                                        }
     415
     416                                        interestingImgs.push( src );
     417                                        alreadySelected.push( schemelessSrc );
     418                                } );
     419                        }
     420
     421                        return interestingImgs;
     422                }
     423
     424                /**
     425                 * Show UX spinner
     426                 */
     427                function showSpinner() {
     428                        $( '#spinner' ).addClass( 'show' );
     429                        $( '.post-actions button' ).each( function() {
     430                                $( this ).attr( 'disabled', 'disabled' );
     431                        } );
     432                }
     433
     434                /**
     435                 * Hide UX spinner
     436                 */
     437                function hideSpinner() {
     438                        $( '#spinner' ).removeClass( 'show' );
     439                        $( '.post-actions button' ).each( function() {
     440                                $( this ).removeAttr( 'disabled' );
     441                        } );
     442                }
     443
     444                /**
     445                 * Submit the post form via AJAX, and redirect to the proper screen if published vs saved as a draft.
     446                 *
     447                 * @param action string publish|draft
     448                 */
     449                function submitPost( action ) {
     450                        saveAlert = false;
     451                        showSpinner();
     452
     453                        var $form = $( '#pressthis-form' );
     454
     455                        if ( 'publish' === action ) {
     456                                $( '#post_status' ).val( 'publish' );
     457                        }
     458
     459                        editor && editor.save();
     460
     461                        $( '#title-field' ).val( sanitizeText( $( '#title-container' ).text() ) );
     462
     463                        // Make sure to flush out the tags with tagBox before saving
     464                        if ( window.tagBox ) {
     465                                $( 'div.tagsdiv' ).each( function() {
     466                                        window.tagBox.flushTags( this, false, 1 );
     467                                } );
     468                        }
     469
     470                        var data = $form.serialize();
     471
     472                        $.ajax( {
     473                                type: 'post',
     474                                url: window.ajaxurl,
     475                                data: data,
     476                                success: function( response ) {
     477                                        if ( ! response.success ) {
     478                                                renderError( response.data.errorMessage );
     479                                                hideSpinner();
     480                                        } else if ( response.data.redirect ) {
     481                                                if ( window.opener && siteConfig.redir_in_parent ) {
     482                                                        try {
     483                                                                window.opener.location.href = response.data.redirect;
     484                                                        } catch( er ) {}
     485
     486                                                        window.self.close();
     487                                                } else {
     488                                                        window.location.href = response.data.redirect;
     489                                                }
     490                                        }
     491                                }
     492                        } );
     493                }
     494
     495                /**
     496                 * Inserts the media a user has selected from the presented list inside the editor, as an image or embed, based on type
     497                 *
     498                 * @param type string img|embed
     499                 * @param src string Source URL
     500                 * @param link string Optional destination link, for images (defaults to src)
     501                 */
     502                function insertSelectedMedia( type, src, link ) {
     503                        var newContent = '';
     504
     505                        if ( ! editor ) {
     506                                return;
     507                        }
     508
     509                        src = checkUrl( src );
     510                        link = checkUrl( link );
     511
     512                        if ( 'img' === type ) {
     513                                if ( ! link || ! link.length ) {
     514                                        link = src;
     515                                }
     516
     517                                newContent = '<a href="' + link + '"><img class="alignnone size-full" src="' + src + '" /></a>\n';
     518                        } else {
     519                                newContent = '[embed]' + src + '[/embed]\n';
     520                        }
     521
     522                        if ( ! hasSetFocus ) {
     523                                // Append to top of content on 1st media insert
     524                                editor.setContent( newContent + editor.getContent() );
     525                        } else {
     526                                // Or add where the cursor was last positioned in TinyMCE
     527                                editor.execCommand( 'mceInsertContent', false, newContent );
     528                        }
     529
     530                        hasSetFocus = true;
     531                }
     532
     533                /**
     534                 * Adds the currently selected post format next to the option, in the options panel.
     535                 *
     536                 * @param format string Post format to be displayed
     537                 */
     538                function setPostFormatString( format ) {
     539                        if ( ! format || ! siteConfig || ! siteConfig.post_formats || ! siteConfig.post_formats[ format ] ) {
     540                                return;
     541                        }
     542                        $( '#post-option-post-format' ).text( siteConfig.post_formats[ format ] );
     543                }
     544
     545                /**
     546                 * Save a new user-generated category via AJAX
     547                 */
     548                function saveNewCategory() {
     549                        var data = {
     550                                action: 'press-this-add-category',
     551                                post_id: $( '#post_ID' ).val() || 0,
     552                                name: $( '#new-category' ).val() || '',
     553                                new_cat_nonce: $( '#_ajax_nonce-add-category' ).val() || '',
     554                                parent: $( '#new-category-parent' ).val() || 0
     555                        };
     556
     557                        $.post( window.ajaxurl, data, function( response ) {
     558                                if ( ! response.success ) {
     559                                        renderError( response.data.errorMessage );
     560                                } else {
     561                                        // TODO: change if/when the html changes.
     562                                        var $parent, $ul,
     563                                                $wrap = $( 'ul.categories-select' );
     564
     565                                        $.each( response.data, function( i, newCat ) {
     566                                                var $node = $( '<li>' ).attr( 'id', 'category-' + newCat.term_id )
     567                                                        .append( $( '<label class="selectit">' ).text( newCat.name )
     568                                                                .append( $( '<input type="checkbox" name="post_category[]" checked>' ).attr( 'value', newCat.term_id ) ) );
     569
     570                                                if ( newCat.parent ) {
     571                                                        if ( ! $ul || ! $ul.length ) {
     572                                                                $parent = $wrap.find( '#category-' + newCat.parent );
     573                                                                $ul = $parent.find( 'ul.children:first' );
     574
     575                                                                if ( ! $ul.length ) {
     576                                                                        $ul = $( '<ul class="children">' ).appendTo( $parent );
     577                                                                }
     578                                                        }
     579
     580                                                        $ul.append( $node );
     581                                                        // TODO: set focus on
     582                                                } else {
     583                                                        $wrap.prepend( $node );
     584                                                }
     585                                        } );
     586
     587                                        refreshCatsCache();
     588                                }
     589                        } );
     590                }
     591
     592                /* ***************************************************************
     593                 * RENDERING FUNCTIONS
     594                 *************************************************************** */
     595
     596                /**
     597                 * Hide the form letting users enter a URL to be scanned, if a URL was already passed.
     598                 */
     599                function renderToolsVisibility() {
     600                        if ( data.u && data.u.match( /^https?:/ ) ) {
     601                                $( '#scanbar' ).hide();
     602                        }
     603                }
     604
     605                /**
     606                 * Render error notice
     607                 *
     608                 * @param msg string Notice/error message
     609                 * @param error string error|notice CSS class for display
     610                 */
     611                function renderNotice( msg, error ) {
     612                        var $alerts = $( '.editor-wrapper div.alerts' ),
     613                                className = error ? 'is-error' : 'is-notice';
     614
     615                        $alerts.append( $( '<p class="' + className + '">' ).text( msg ) );
     616                }
     617
     618                /**
     619                 * Render error notice
     620                 *
     621                 * @param msg string Error message
     622                 */
     623                function renderError( msg ) {
     624                        renderNotice( msg, true );
     625                }
     626
     627                /**
     628                 * Render notices on page load, if any already
     629                 */
     630                function renderStartupNotices() {
     631                        // Render errors sent in the data, if any
     632                        if ( data.errors && data.errors.length ) {
     633                                $.each( data.errors, function( i, msg ) {
     634                                        renderError( msg );
     635                                } );
     636                        }
     637
     638                        // Prompt user to upgrade their bookmarklet if there is a version mismatch.
     639                        if ( data.v && data._version && data.v !== data._version ) {
     640                                $( '.should-upgrade-bookmarklet' ).removeClass( 'is-hidden' );
     641                        }
     642                }
     643
     644                /**
     645                 * Render the suggested title, if any
     646                 */
     647                function renderSuggestedTitle() {
     648                        var suggestedTitle = suggestedTitleStr || '',
     649                                $title = $( '#title-container' );
     650
     651                        if ( ! hasEmptyTitleStr ) {
     652                                $( '#title-field' ).val( suggestedTitle );
     653                                $title.text( suggestedTitle );
     654                                $( '.post-title-placeholder' ).addClass( 'is-hidden' );
     655                        }
     656
     657                        $title.on( 'keyup', function() {
     658                                saveAlert = true;
     659                        }).on( 'paste', function() {
     660                                saveAlert = true;
     661
     662                                setTimeout( function() {
     663                                        $title.text( $title.text() );
     664                                }, 100 );
     665                        } );
     666
     667                }
     668
     669                /**
     670                 * Render the suggested content, if any
     671                 */
     672                function renderSuggestedContent() {
     673                        if ( ! suggestedContentStr || ! suggestedContentStr.length ) {
     674                                return;
     675                        }
     676
     677                        if ( ! editor ) {
     678                                editor = window.tinymce.get( 'pressthis' );
     679                        }
     680
     681                        if ( editor ) {
     682                                editor.setContent( suggestedContentStr );
     683                                editor.on( 'focus', function() {
     684                                        hasSetFocus = true;
     685                                } );
     686                        }
     687
     688                }
     689
     690                /**
     691                 * Render the detected images and embed for selection, if any
     692                 */
     693                function renderDetectedMedia() {
     694                        var mediaContainer = $( '#featured-media-container'),
     695                                listContainer  = $( '#all-media-container' ),
     696                                found          = 0;
     697
     698                        listContainer.empty();
     699
     700                        if ( ( interestingEmbeds && interestingEmbeds.length ) || ( interestingImages && interestingImages.length ) ) {
     701                                listContainer.append( '<h2 class="screen-reader-text">' + __( 'allMediaHeading' ) + '</h2><ul class="wppt-all-media-list"/>' );
     702                        }
     703
     704                        if ( interestingEmbeds && interestingEmbeds.length ) {
     705                                $.each( interestingEmbeds, function ( i, src ) {
     706                                        src = checkUrl( src );
     707
     708                                        if ( ! isEmbeddable( src ) ) {
     709                                                return;
     710                                        }
     711
     712                                        var displaySrc = '',
     713                                                cssClass   = 'suggested-media-thumbnail suggested-media-embed';
     714
     715                                        if ( src.indexOf( 'youtube.com/' ) > -1 ) {
     716                                                displaySrc = 'https://i.ytimg.com/vi/' + src.replace( /.+v=([^&]+).*/, '$1' ) + '/hqdefault.jpg';
     717                                                cssClass += ' is-video';
     718                                        } else if ( src.indexOf( 'youtu.be/' ) > -1 ) {
     719                                                displaySrc = 'https://i.ytimg.com/vi/' + src.replace( /\/([^\/])$/, '$1' ) + '/hqdefault.jpg';
     720                                                cssClass += ' is-video';
     721                                        } else if ( src.indexOf( 'dailymotion.com' ) > -1 ) {
     722                                                displaySrc = src.replace( '/video/', '/thumbnail/video/' );
     723                                                cssClass += ' is-video';
     724                                        } else if ( src.indexOf( 'soundcloud.com' ) > -1 ) {
     725                                                cssClass += ' is-audio';
     726                                        } else if ( src.indexOf( 'twitter.com' ) > -1 ) {
     727                                                cssClass += ' is-tweet';
     728                                        } else {
     729                                                cssClass += ' is-video';
     730                                        }
     731
     732                                        $( '<li></li>', {
     733                                                'id': 'embed-' + i + '-container',
     734                                                'class': cssClass,
     735                                                'tabindex': '0'
     736                                        } ).css( {
     737                                                'background-image': ( displaySrc.length ) ? 'url(' + displaySrc + ')' : null
     738                                        } ).html(
     739                                                '<span class="screen-reader-text">' + __( 'suggestedEmbedAlt' ).replace( '%d', i + 1 ) + '</span>'
     740                                        ).on( 'click keypress', function ( e ) {
     741                                                if ( e.type === 'click' || e.which === 13 ) {
     742                                                        insertSelectedMedia( 'embed',src );
     743                                                }
     744                                        } ).appendTo( '.wppt-all-media-list', listContainer );
     745
     746                                        found++;
     747                                } );
     748                        }
     749
     750                        if ( interestingImages && interestingImages.length ) {
     751                                $.each( interestingImages, function ( i, src ) {
     752                                        src = checkUrl( src );
     753
     754                                        var displaySrc = src.replace(/^(http[^\?]+)(\?.*)?$/, '$1');
     755                                        if ( src.indexOf( 'files.wordpress.com/' ) > -1 ) {
     756                                                displaySrc = displaySrc.replace(/\?.*$/, '') + '?w=' + smallestWidth;
     757                                        } else if ( src.indexOf( 'gravatar.com/' ) > -1 ) {
     758                                                displaySrc = displaySrc.replace( /\?.*$/, '' ) + '?s=' + smallestWidth;
     759                                        } else {
     760                                                displaySrc = src;
     761                                        }
     762
     763                                        $( '<li></li>', {
     764                                                'id': 'img-' + i + '-container',
     765                                                'class': 'suggested-media-thumbnail is-image',
     766                                                'tabindex': '0'
     767                                        } ).css( {
     768                                                'background-image': 'url(' + displaySrc + ')'
     769                                        } ).html(
     770                                                '<span class="screen-reader-text">' +__( 'suggestedImgAlt' ).replace( '%d', i + 1 ) + '</span>'
     771                                        ).on( 'click keypress', function ( e ) {
     772                                                if ( e.type === 'click' || e.which === 13 ) {
     773                                                        insertSelectedMedia( 'img', src, data.u );
     774                                                }
     775                                        } ).appendTo( '.wppt-all-media-list', listContainer );
     776
     777                                        found++;
     778                                } );
     779                        }
     780
     781                        if ( ! found ) {
     782                                mediaContainer.removeClass( 'all-media-visible' ).addClass( 'no-media');
     783                                return;
     784                        }
     785
     786                        mediaContainer.removeClass( 'no-media' ).addClass( 'all-media-visible' );
     787                }
     788
     789                /* ***************************************************************
     790                 * MONITORING FUNCTIONS
     791                 *************************************************************** */
     792
     793                /**
     794                 * Interactive navigation behavior for the options modal (post format, tags, categories)
     795                 */
     796                function monitorOptionsModal() {
     797                        var isOffScreen   = 'is-off-screen',
     798                                isHidden      = 'is-hidden',
     799                                $postOptions  = $( '.post-options' ),
     800                                $postOption   = $( '.post-option' ),
     801                                $settingModal = $( '.setting-modal' ),
     802                                $modalClose   = $( '.modal-close' );
     803
     804                        $postOption.on( 'click', function( event ) {
     805                                var index = $( this ).index(),
     806                                        $targetSettingModal = $settingModal.eq( index );
     807
     808                                event.preventDefault();
     809
     810                                $postOptions
     811                                        .addClass( isOffScreen )
     812                                        .one( transitionEndEvent, function() {
     813                                                $( this ).addClass( isHidden );
     814                                        } );
     815
     816                                $targetSettingModal
     817                                        .removeClass( isOffScreen + ' ' + isHidden )
     818                                        .one( transitionEndEvent, function() {
     819                                                $( this ).find( $modalClose ).focus();
     820                                        } );
     821                        } );
     822
     823                        $modalClose.on( 'click', function( event ) {
     824                                var $targetSettingModal = $( this ).parent(),
     825                                        index = $targetSettingModal.index();
     826
     827                                event.preventDefault();
     828
     829                                $postOptions
     830                                        .removeClass( isOffScreen + ' ' + isHidden );
     831
     832                                $targetSettingModal
     833                                        .addClass( isOffScreen )
     834                                        .one( transitionEndEvent, function() {
     835                                                $( this ).addClass( isHidden );
     836                                        } );
     837
     838                                // For browser that don't support transitionend.
     839                                if ( ! transitionEndEvent ) {
     840                                        setTimeout( function() {
     841                                                $targetSettingModal.addClass( isHidden );
     842                                        }, 350 );
     843                                }
     844
     845                                $postOption.eq( index - 1 ).focus();
     846                        } );
     847                }
     848
     849                /**
     850                 * Interactive behavior for the sidebar toggle, to show the options modals
     851                 */
     852                function monitorSidebarToggle() {
     853                        var $optOpen  = $( '.options-open' ),
     854                                $optClose = $( '.options-close' ),
     855                                $postOption = $( '.post-option' ),
     856                                $sidebar = $( '.options-panel' ),
     857                                $postActions = $( '.press-this-actions' ),
     858                                $scanbar = $( '#scanbar' ),
     859                                isOffScreen = 'is-off-screen',
     860                                isHidden = 'is-hidden',
     861                                ifOffHidden = isOffScreen + ' ' + isHidden;
     862
     863                        $optOpen.on( 'click', function(){
     864                                $optOpen.addClass( isHidden );
     865                                $optClose.removeClass( isHidden );
     866                                $postActions.addClass( isHidden );
     867                                $scanbar.addClass( isHidden );
     868
     869                                $sidebar
     870                                        .removeClass( ifOffHidden )
     871                                        .one( 'transitionend', function() {
     872                                                $postOption.eq( 0 ).focus();
     873                                        } );
     874                        } );
     875
     876                        $optClose.on( 'click', function(){
     877                                $optClose.addClass( isHidden );
     878                                $optOpen.removeClass( isHidden );
     879                                $postActions.removeClass( isHidden );
     880                                $scanbar.removeClass( isHidden );
     881
     882                                $sidebar
     883                                        .addClass( isOffScreen )
     884                                        .one( 'transitionend', function() {
     885                                                $( this ).addClass( isHidden );
     886                                                // Reset to options list
     887                                                $( '.post-options' ).removeClass( ifOffHidden );
     888                                                $( '.setting-modal').addClass( ifOffHidden );
     889                                        } );
     890                        } );
     891                }
     892
     893                /**
     894                 * Interactive behavior for the post title's field placeholder
     895                 */
     896                function monitorPlaceholder() {
     897                        var $selector = $( '#title-container'),
     898                                $placeholder = $('.post-title-placeholder');
     899
     900                        $selector.on( 'focus', function() {
     901                                $placeholder.addClass('is-hidden');
     902                        } );
     903
     904                        $selector.on( 'blur', function() {
     905                                var textLength = $( this ).text().length;
     906
     907                                if ( ! textLength ) {
     908                                        $placeholder.removeClass('is-hidden');
     909                                }
     910                        } );
     911                }
     912
     913                /* ***************************************************************
     914                 * PROCESSING FUNCTIONS
     915                 *************************************************************** */
     916
     917                /**
     918                 * Calls all the rendring related functions to happen on page load
     919                 */
     920                function render(){
     921                        // We're on!
     922                        renderToolsVisibility();
     923                        renderSuggestedTitle();
     924                        renderDetectedMedia();
     925                        $( document ).on( 'tinymce-editor-init', renderSuggestedContent );
     926                        renderStartupNotices();
     927                }
     928
     929                /**
     930                 * Set app events and other state monitoring related code.
     931                 */
     932                function monitor(){
     933                        $( '#current-site a').click( function( e ) {
     934                                e.preventDefault();
     935                        } );
     936
     937                        // Publish and Draft buttons and submit
     938
     939                        $( '#draft-field' ).on( 'click', function() {
     940                                submitPost( 'draft' );
     941                        } );
     942
     943                        $( '#publish-field' ).on( 'click', function() {
     944                                submitPost( 'publish' );
     945                        } );
     946
     947                        monitorOptionsModal();
     948                        monitorSidebarToggle();
     949                        monitorPlaceholder();
     950
     951                        $( '#post-formats-select input' ).on( 'change', function() {
     952                                var $this = $( this );
     953
     954                                if ( $this.is( ':checked' ) ) {
     955                                        setPostFormatString( $this.attr( 'id' ).replace( /^post-format-(.+)$/, '$1' ) );
     956                                }
     957                        } );
     958
     959                        // Needs more work, doesn't detect when the other JS changes the value of #tax-input-post_tag
     960                        $( '#tax-input-post_tag' ).on( 'change', function() {
     961                                var val =  $( this ).val();
     962                                $( '#post-option-tags' ).text( ( val.length ) ? val.replace( /,([^\s])/g, ', $1' ) : '' );
     963                        } );
     964
     965                        $( window ).on( 'beforeunload.press-this', function() {
     966                                if ( saveAlert || ( editor && editor.isDirty() ) ) {
     967                                        return __( 'saveAlert' );
     968                                }
     969                        } );
     970
     971                        $( 'button.add-cat-toggle' ).on( 'click.press-this', function() {
     972                                $( this ).toggleClass( 'is-toggled' );
     973                                $( '.setting-modal .add-category' ).toggleClass( 'is-hidden' );
     974                                $( '.categories-search-wrapper' ).toggleClass( 'is-hidden' );
     975                        } );
     976
     977                        $( 'button.add-cat-submit' ).on( 'click.press-this', saveNewCategory );
     978
     979                        $( '.categories-search' ).on( 'keyup', function() {
     980                                var search = $( this ).val().toLowerCase() || '';
     981
     982                                // Don't search when less thasn 3 extended ASCII chars
     983                                if ( /[\x20-\xFF]+/.test( search ) && search.length < 2 ) {
     984                                        return;
     985                                }
     986
     987                                $.each( catsCache, function( i, cat ) {
     988                                        cat.node.removeClass( 'is-hidden searched-parent' );
     989                                } );
     990
     991                                if ( search ) {
     992                                        $.each( catsCache, function( i, cat ) {
     993                                                if ( cat.text.indexOf( search ) === -1 ) {
     994                                                        cat.node.addClass( 'is-hidden' );
     995                                                } else {
     996                                                        cat.parents.addClass( 'searched-parent' );
     997                                                }
     998                                        } );
     999                                }
     1000                        } );
     1001
     1002                        return true;
     1003                }
     1004
     1005                function refreshCatsCache() {
     1006                        $( '.categories-select' ).find( 'li' ).each( function() {
     1007                                var $this = $( this );
     1008
     1009                                catsCache.push( {
     1010                                        node: $this,
     1011                                        parents: $this.parents( 'li' ),
     1012                                        text: $this.children( 'label' ).text().toLowerCase()
     1013                                } );
     1014                        } );
     1015                }
     1016
     1017                // Let's go!
     1018                $( document ).ready( function() {
     1019                        render();
     1020                        monitor();
     1021                        refreshCatsCache();
     1022                });
     1023
     1024                // Expose public methods
     1025                // TODO: which are needed?
     1026                return {
     1027                        renderNotice: renderNotice,
     1028                        renderError: renderError
     1029                };
     1030        }
     1031
     1032        window.wp = window.wp || {};
     1033        window.wp.pressThis = new PressThis();
     1034
     1035}( jQuery, window ));
     1036/**
     1037 * PressThis App
     1038 *
     1039 */
     1040( function( $, window ) {
     1041        var PressThis = function() {
     1042                var editor,
     1043                        saveAlert             = false,
     1044                        $div                  = $( '<div>' ),
     1045                        siteConfig            = window.wpPressThisConfig || {},
     1046                        data                  = window.wpPressThisData || {},
     1047                        smallestWidth         = 128,
     1048                        interestingImages         = getInterestingImages( data ) || [],
     1049                        interestingEmbeds         = getInterestingEmbeds( data ) || [],
     1050                        hasEmptyTitleStr      = false,
     1051                        suggestedTitleStr     = getSuggestedTitle( data ),
     1052                        suggestedContentStr   = getSuggestedContent( data ),
     1053                        hasSetFocus           = false,
     1054                        catsCache             = [],
     1055                        transitionEndEvent    = ( function() {
     1056                                var style = document.documentElement.style;
     1057
     1058                                if ( typeof style.transition !== 'undefined' ) {
     1059                                        return 'transitionend';
     1060                                }
     1061
     1062                                if ( typeof style.WebkitTransition !== 'undefined' ) {
     1063                                        return 'webkitTransitionEnd';
     1064                                }
     1065
     1066                                return false;
     1067                        }() );
     1068
     1069                /* ***************************************************************
     1070                 * HELPER FUNCTIONS
     1071                 *************************************************************** */
     1072
     1073                /**
     1074                 * Emulates our PHP __() gettext function, powered by the strings exported in pressThisL10n.
     1075                 *
     1076                 * @param key string Key of the string to be translated, as found in pressThisL10n.
     1077                 * @returns string Original or translated string, or empty string if no key.
     1078                 */
     1079                function __( key ) {
     1080                        if ( key && window.pressThisL10n ) {
     1081                                return window.pressThisL10n[key] || key;
     1082                        }
     1083
     1084                        return key || '';
     1085                }
     1086
     1087                /**
     1088                 * Strips HTML tags
     1089                 *
     1090                 * @param string string Text to have the HTML tags striped out of.
     1091                 * @returns string Stripped text.
     1092                 */
     1093                function stripTags( string ) {
     1094                        string = string || '';
     1095
     1096                        return string
     1097                                .replace( /<!--[\s\S]*?(-->|$)/g, '' )
     1098                                .replace( /<(script|style)[^>]*>[\s\S]*?(<\/\1>|$)/ig, '' )
     1099                                .replace( /<\/?[a-z][^>]*>/ig, '' );
     1100                }
     1101
     1102                // TODO: needed?
     1103                function entityEncode( text ) {
     1104                        return $div.text( text ).html();
     1105                }
     1106
     1107                /**
     1108                 * Strip HTML tags and entity encode some of the HTML special chars.
     1109                 *
     1110                 * @param text string Text.
     1111                 * @returns string Sanitized text.
     1112                 */
     1113                function sanitizeText( text ) {
     1114                        text = stripTags( text );
     1115
     1116                        return text
     1117                                .replace( /\\/, '' )
     1118                                .replace( /</g, '&lt;' )
     1119                                .replace( />/g, '&gt;' )
     1120                                .replace( /"/g, '&quot;' )
     1121                                .replace( /'/g, '&#039;' );
     1122                }
     1123
     1124                /**
     1125                 * Allow only HTTP or protocol relative URLs.
     1126                 *
     1127                 * @param url string The URL.
     1128                 * @returns string Processed URL.
     1129                 */
     1130                function checkUrl( url ) {
     1131                        url = $.trim( url || '' );
     1132
     1133                        if ( /^(?:https?:)?\/\//.test( url ) ) {
     1134                                url = stripTags( url );
     1135                                return url.replace( /["\\]+/g, '' );
     1136                        }
     1137
     1138                        return '';
     1139                }
     1140
     1141                /**
     1142                 * Gets the source page's canonical link, based on passed location and meta data.
     1143                 *
     1144                 * @param data object Usually WpPressThis_App.data
     1145                 * @returns string Discovered canonical URL, or empty
     1146                 */
     1147                function getCanonicalLink( data ) {
     1148                        if ( ! data || data.length ) {
     1149                                return '';
     1150                        }
     1151
     1152                        var link = '';
     1153
     1154                        if ( data._links ) {
     1155                                if ( data._links.canonical && data._links.canonical.length ) {
     1156                                        link = data._links.canonical;
     1157                                }
     1158                        }
     1159
     1160                        if ( ! link.length && data.u ) {
     1161                                link = data.u;
     1162                        }
     1163
     1164                        if ( ! link.length && data._meta ) {
     1165                                if ( data._meta['twitter:url'] && data._meta['twitter:url'].length ) {
     1166                                        link = data._meta['twitter:url'];
     1167                                } else if ( data._meta['og:url'] && data._meta['og:url'].length ) {
     1168                                        link = data._meta['og:url'];
     1169                                }
     1170                        }
     1171
     1172                        return decodeURI( link );
     1173                }
     1174
     1175                /**
     1176                 * Gets the source page's site name, based on passed meta data.
     1177                 *
     1178                 * @param data object Usually WpPressThis_App.data
     1179                 * @returns string Discovered site name, or empty
     1180                 */
     1181                function getSourceSiteName( data ) {
     1182                        if ( ! data || data.length ) {
     1183                                return '';
     1184                        }
     1185
     1186                        var name='';
     1187
     1188                        if ( data._meta ) {
     1189                                if ( data._meta['og:site_name'] && data._meta['og:site_name'].length ) {
     1190                                        name = data._meta['og:site_name'];
     1191                                } else if ( data._meta['application-name'] && data._meta['application-name'].length ) {
     1192                                        name = data._meta['application-name'];
     1193                                }
     1194                        }
     1195
     1196                        return name.replace( /\\/g, '' );
     1197                }
     1198
     1199                /**
     1200                 * Gets the source page's title, based on passed title and meta data.
     1201                 *
     1202                 * @param data object Usually WpPressThis_App.data
     1203                 * @returns string Discovered page title, or empty
     1204                 */
     1205                function getSuggestedTitle( data ) {
     1206                        if ( ! data || data.length ) {
     1207                                return __( 'newPost' );
     1208                        }
     1209
     1210                        var title = '';
     1211
     1212                        if ( data.t ) {
     1213                                title = data.t;
     1214                        }
     1215
     1216                        if ( ! title.length && data._meta ) {
     1217                                if ( data._meta['twitter:title'] && data._meta['twitter:title'].length ) {
     1218                                        title = data._meta['twitter:title'];
     1219                                } else if ( data._meta['og:title'] && data._meta['og:title'].length ) {
     1220                                        title = data._meta['og:title'];
     1221                                } else if ( data._meta.title && data._meta.title.length ) {
     1222                                        title = data._meta.title;
     1223                                }
     1224                        }
     1225
     1226                        if ( ! title.length ) {
     1227                                title = __( 'newPost' );
     1228                                hasEmptyTitleStr = true;
     1229                        }
     1230
     1231                        return title.replace( /\\/g, '' );
     1232                }
     1233
     1234                /**
     1235                 * Gets the source page's suggested content, based on passed data (description, selection, etc).
     1236                 * Features a blockquoted excerpt, as well as content attribution, if any.
     1237                 *
     1238                 * @param data object Usually WpPressThis_App.data
     1239                 * @returns string Discovered content, or empty
     1240                 */
     1241                function getSuggestedContent( data ) {
     1242                        if ( ! data || data.length ) {
     1243                                return '';
     1244                        }
     1245
     1246                        var content   = '',
     1247                                title     = getSuggestedTitle( data ),
     1248                                url       = getCanonicalLink( data ),
     1249                                siteName  = getSourceSiteName( data );
     1250
     1251                        if ( data.s && data.s.length ) {
     1252                                content = data.s;
     1253                        } else if ( data._meta ) {
     1254                                if ( data._meta['twitter:description'] && data._meta['twitter:description'].length ) {
     1255                                        content = data._meta['twitter:description'];
     1256                                } else if ( data._meta['og:description'] && data._meta['og:description'].length ) {
     1257                                        content = data._meta['og:description'];
     1258                                } else if ( data._meta.description && data._meta.description.length ) {
     1259                                        content = data._meta.description;
     1260                                }
     1261                        }
     1262
     1263                        // Wrap suggested content in blockquote tag, if we have any.
     1264                        content = ( content.length ? '<blockquote class="press-this-suggested-content">' + sanitizeText( content ) + '</blockquote>' : '' );
     1265
     1266                        // Add a source attribution if there is one available.
     1267                        if ( ( ( title.length && __( 'newPost' ) !== title ) || siteName.length ) && url.length ) {
     1268                                content += '<p class="press-this-suggested-source">';
     1269                                content += __( 'source' );
     1270                                content += ' <cite>';
     1271                                content += __( 'sourceLink').replace( '%1$s', encodeURI( url ) ).replace( '%2$s', sanitizeText( title || siteName ) );
     1272                                content += '</cite></p>';
     1273                        }
     1274
     1275                        if ( ! content ) {
     1276                                content = '';
     1277                        }
     1278
     1279                        return content.replace( /\\/g, '' );
     1280                }
     1281
     1282                /**
     1283                 * Tests if what was passed as an embed URL is deemed to be embeddable in the editor.
     1284                 *
     1285                 * @param url string Passed URl, usually from WpPressThis_App.data._embed
     1286                 * @returns boolean
     1287                 */
     1288                function isEmbeddable( url ) {
     1289                        if ( ! url ) {
     1290                                return false;
     1291                        } else if ( url.match( /\/\/(m\.|www\.)?youtube\.com\/watch\?/ ) || url.match( /\/youtu\.be\/.+$/ ) ) {
     1292                                return true;
     1293                        } else if ( url.match( /\/\/vimeo\.com\/(.+\/)?[\d]+$/ ) ) {
     1294                                return true;
     1295                        } else if ( url.match( /\/\/(www\.)?dailymotion\.com\/video\/.+$/ ) ) {
     1296                                return true;
     1297                        } else if ( url.match( /\/\/soundcloud\.com\/.+$/ ) ) {
     1298                                return true;
     1299                        } else if ( url.match( /\/\/twitter\.com\/[^\/]+\/status\/[\d]+$/ ) ) {
     1300                                return true;
     1301                        } else if ( url.match( /\/\/vine\.co\/v\/[^\/]+/ ) ) {
     1302                                return true;
     1303                        }
     1304
     1305                        return false;
     1306                }
     1307
     1308                /**
     1309                 * Tests if what was passed as an image URL is deemed to be interesting enough to offer to the user for selection.
     1310                 *
     1311                 * @param src string Passed URl, usually from WpPressThis_App.data._ing
     1312                 * @returns boolean Test for false
     1313                 */
     1314                function isSrcUninterestingPath( src ) {
     1315                        if ( src.match( /\/ad[sx]{1}?\// ) ) {
     1316                                // Ads
     1317                                return true;
     1318                        } else if ( src.match( /(\/share-?this[^\.]+?\.[a-z0-9]{3,4})(\?.*)?$/ ) ) {
     1319                                // Share-this type button
     1320    &n