WordPress.org

Make WordPress Core

Ticket #31373: 31373.patch

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

    Property changes on: src/wp-admin/includes/class-wp-press-this.php
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
     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 );
  • src/wp-admin/js/post.js

    Property changes on: src/wp-admin/js/bookmarklet.js
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
    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 ));
  • src/wp-admin/js/tags-box.js

    Property changes on: src/wp-admin/js/press-this.js
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
     1/* jshint curly: false, eqeqeq: false */
     2/* global ajaxurl, wpAjax */
     3
     4/**
     5 * The functions and classes in that code are a straight cut-and-paste out of
     6 * /wp-admin/js/post.js, coupled with Press This' usage of the post_tags_meta_box()
     7 * PHP function.
     8 *
     9 * If Press This makes it into core, we can refactor that code out of post.js and
     10 * make it more reusable, as well as improve it to work better, everywhere.
     11 *
     12 * Copied-and-pasted instead of enqueuing post.js because the latter has much more,
     13 * and has processing instead of just functions/classes.
     14 */
     15var tagBox, array_unique_noempty;
     16
     17( function( $ ) {
     18        // Return an array with any duplicate, whitespace or empty values removed
     19        array_unique_noempty = function( array ) {
     20                var out = [];
     21
     22                $.each( array, function( key, val ) {
     23                        val = $.trim( val );
     24
     25                        if ( val && $.inArray( val, out ) === -1 ) {
     26                                out.push( val );
     27                        }
     28                } );
     29
     30                return out;
     31        }
     32       
     33        tagBox = {
     34                clean : function(tags) {
     35                        var comma = window.tagsBoxL10n.tagDelimiter;
     36                        if ( ',' !== comma )
     37                                tags = tags.replace(new RegExp(comma, 'g'), ',');
     38                        tags = tags.replace(/\s*,\s*/g, ',').replace(/,+/g, ',').replace(/[,\s]+$/, '').replace(/^[,\s]+/, '');
     39                        if ( ',' !== comma )
     40                                tags = tags.replace(/,/g, comma);
     41                        return tags;
     42                },
     43
     44                parseTags : function(el) {
     45                        var id = el.id,
     46                                num = id.split('-check-num-')[1],
     47                                taxbox = $(el).closest('.tagsdiv'),
     48                                thetags = taxbox.find('.the-tags'),
     49                                comma = window.tagsBoxL10n.tagDelimiter;
     50                                current_tags = thetags.val().split( comma ),
     51                                new_tags = [];
     52
     53                        delete current_tags[num];
     54
     55                        $.each( current_tags, function( key, val ) {
     56                                val = $.trim( val );
     57                                if ( val ) {
     58                                        new_tags.push( val );
     59                                }
     60                        });
     61
     62                        thetags.val( this.clean( new_tags.join( comma ) ) );
     63
     64                        this.quickClicks( taxbox );
     65                        return false;
     66                },
     67
     68                quickClicks : function( el ) {
     69                        var thetags = $('.the-tags', el),
     70                                tagchecklist = $('.tagchecklist', el),
     71                                id = $(el).attr('id'),
     72                                current_tags, disabled;
     73
     74                        if ( ! thetags.length )
     75                                return;
     76
     77                        disabled = thetags.prop('disabled');
     78
     79                        current_tags = thetags.val().split( window.tagsBoxL10n.tagDelimiter );
     80                        tagchecklist.empty();
     81
     82                        $.each( current_tags, function( key, val ) {
     83                                var span, xbutton;
     84
     85                                val = $.trim( val );
     86
     87                                if ( ! val )
     88                                        return;
     89
     90                                // Create a new span, and ensure the text is properly escaped.
     91                                span = $('<span />').text( val );
     92
     93                                // If tags editing isn't disabled, create the X button.
     94                                if ( ! disabled ) {
     95                                        xbutton = $( '<a id="' + id + '-check-num-' + key + '" class="ntdelbutton" tabindex="0">X</a>' );
     96
     97                                        xbutton.on( 'click keypress', function( e ) {
     98                                                // Trigger function if pressed Enter - keyboard navigation
     99                                                if ( e.type === 'click' || e.keyCode === 13 ) {
     100                                                        // When using keyboard, move focus back to the new tag field.
     101                                                        if ( e.keyCode === 13 ) {
     102                                                                $( this ).closest( '.tagsdiv' ).find( 'input.newtag' ).focus();
     103                                                        }
     104
     105                                                        tagBox.parseTags( this );
     106                                                }
     107                                        });
     108
     109                                        span.prepend( '&nbsp;' ).prepend( xbutton );
     110                                }
     111
     112                                // Append the span to the tag list.
     113                                tagchecklist.append( span );
     114                        });
     115                },
     116
     117                flushTags : function( el, a, f ) {
     118                        var tagsval, newtags, text,
     119                                tags = $( '.the-tags', el ),
     120                                newtag = $( 'input.newtag', el ),
     121                                comma = window.tagsBoxL10n.tagDelimiter;
     122
     123                        a = a || false;
     124
     125                        text = a ? $(a).text() : newtag.val();
     126                        tagsval = tags.val();
     127                        newtags = tagsval ? tagsval + comma + text : text;
     128
     129                        newtags = this.clean( newtags );
     130                        newtags = array_unique_noempty( newtags.split( comma ) ).join( comma );
     131                        tags.val( newtags );
     132                        this.quickClicks( el );
     133
     134                        if ( ! a )
     135                                newtag.val('');
     136                        if ( 'undefined' == typeof( f ) )
     137                                newtag.focus();
     138
     139                        return false;
     140                },
     141
     142                get : function( id ) {
     143                        var tax = id.substr( id.indexOf('-') + 1 );
     144
     145                        $.post( ajaxurl, { 'action': 'get-tagcloud', 'tax': tax }, function( r, stat ) {
     146                                if ( 0 === r || 'success' != stat ) {
     147                                        return;
     148                                }
     149
     150                                r = $( '<p id="tagcloud-' + tax + '" class="the-tagcloud">' + r + '</p>' );
     151
     152                                $( 'a', r ).click( function() {
     153                                        tagBox.flushTags( $( '#' + tax ), this );
     154                                        return false;
     155                                });
     156
     157                                $( '#' + id ).after( r );
     158                        });
     159                },
     160
     161                init : function() {
     162                        var t = this, ajaxtag = $('div.ajaxtag');
     163
     164                        $('.tagsdiv').each( function() {
     165                                tagBox.quickClicks(this);
     166                        });
     167
     168                        $('.tagadd', ajaxtag).click(function(){
     169                                t.flushTags( $(this).closest('.tagsdiv') );
     170                        });
     171
     172                        $('div.taghint', ajaxtag).click(function(){
     173                                $(this).css('visibility', 'hidden').parent().siblings('.newtag').focus();
     174                        });
     175
     176                        $('input.newtag', ajaxtag).blur(function() {
     177                                if ( '' === this.value )
     178                                        $(this).parent().siblings('.taghint').css('visibility', '');
     179                        }).focus(function(){
     180                                $(this).parent().siblings('.taghint').css('visibility', 'hidden');
     181                        }).keyup(function(e){
     182                                if ( 13 == e.which ) {
     183                                        tagBox.flushTags( $(this).closest('.tagsdiv') );
     184                                        return false;
     185                                }
     186                        }).keypress(function(e){
     187                                if ( 13 == e.which ) {
     188                                        e.preventDefault();
     189                                        return false;
     190                                }
     191                        }).each( function() {
     192                                var tax = $(this).closest('div.tagsdiv').attr('id');
     193                                $(this).suggest(
     194                                        ajaxurl + '?action=ajax-tag-search&tax=' + tax,
     195                                        { delay: 500, minchars: 2, multiple: true, multipleSep: window.tagsBoxL10n.tagDelimiter + ' ' }
     196                                );
     197                        });
     198
     199                        // save tags on post save/publish
     200                        $('#post').submit(function(){
     201                                $('div.tagsdiv').each( function() {
     202                                        tagBox.flushTags(this, false, 1);
     203                                });
     204                        });
     205
     206                        // tag cloud
     207                        $('a.tagcloud-link').click(function(){
     208                                tagBox.get( $(this).attr('id') );
     209                                $(this).unbind().click(function(){
     210                                        $(this).siblings('.the-tagcloud').toggle();
     211                                        return false;
     212                                });
     213                                return false;
     214                        });
     215                }
     216        };
     217
     218        $( document ).ready( function() {
     219                tagBox.init();
     220        });
     221
     222}( jQuery ));
  • src/wp-admin/options-writing.php

    Property changes on: src/wp-admin/js/tags-box.js
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
    113113?>
    114114</table>
    115115
    116 <h3 class="title"><?php _e('Press This') ?></h3>
    117 <p><?php _e('Press This is a bookmarklet: a little app that runs in your browser and lets you grab bits of the web.');?></p>
    118 <p><?php _e('Use Press This to clip text, images and videos from any web page. Then edit and add more straight from Press This before you save or publish it in a post on your site.'); ?></p>
    119 <p><?php _e('Drag-and-drop the following link to your bookmarks bar or right click it and add it to your favorites for a posting shortcut.') ?></p>
    120 <p class="pressthis"><a onclick="return false;" oncontextmenu="if(window.navigator.userAgent.indexOf('WebKit')!=-1||window.navigator.userAgent.indexOf('MSIE')!=-1){jQuery('.pressthis-code').show().find('textarea').focus().select();return false;}" href="<?php echo htmlspecialchars( get_shortcut_link() ); ?>"><span><?php _e('Press This') ?></span></a></p>
    121 <div class="pressthis-code" style="display:none;">
    122         <p class="description"><?php _e('If your bookmarks toolbar is hidden: copy the code below, open your Bookmarks manager, create new bookmark, type Press This into the name field and paste the code into the URL field.') ?></p>
    123         <p><textarea rows="5" cols="120" readonly="readonly"><?php echo htmlspecialchars( get_shortcut_link() ); ?></textarea></p>
    124 </div>
    125 
    126116<?php
    127117/** This filter is documented in wp-admin/options.php */
    128118if ( apply_filters( 'enable_post_by_email_configuration', true ) ) {
  • src/wp-admin/press-this.php

     
    1111/** WordPress Administration Bootstrap */
    1212require_once( dirname( __FILE__ ) . '/admin.php' );
    1313
    14 header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
    15 
    1614if ( ! current_user_can( 'edit_posts' ) || ! current_user_can( get_post_type_object( 'post' )->cap->create_posts ) )
    1715        wp_die( __( 'Cheatin&#8217; uh?' ), 403 );
    1816
    19 /**
    20  * Press It form handler.
    21  *
    22  * @since 2.6.0
    23  *
    24  * @return int Post ID
    25  */
    26 function press_it() {
    27 
    28         $post = get_default_post_to_edit();
    29         $post = get_object_vars($post);
    30         $post_ID = $post['ID'] = (int) $_POST['post_id'];
    31 
    32         if ( !current_user_can('edit_post', $post_ID) )
    33                 wp_die(__('You are not allowed to edit this post.'));
    34 
    35         $post['post_category'] = isset($_POST['post_category']) ? $_POST['post_category'] : '';
    36         $post['tax_input'] = isset($_POST['tax_input']) ? $_POST['tax_input'] : '';
    37         $post['post_title'] = isset($_POST['title']) ? $_POST['title'] : '';
    38         $content = isset($_POST['content']) ? $_POST['content'] : '';
    39 
    40         $upload = false;
    41         if ( !empty($_POST['photo_src']) && current_user_can('upload_files') ) {
    42                 foreach( (array) $_POST['photo_src'] as $key => $image) {
    43                         // See if files exist in content - we don't want to upload non-used selected files.
    44                         if ( strpos($_POST['content'], htmlspecialchars($image)) !== false ) {
    45                                 $desc = isset($_POST['photo_description'][$key]) ? $_POST['photo_description'][$key] : '';
    46                                 $upload = media_sideload_image($image, $post_ID, $desc);
    47 
    48                                 // Replace the POSTED content <img> with correct uploaded ones. Regex contains fix for Magic Quotes
    49                                 if ( !is_wp_error($upload) )
    50                                         $content = preg_replace('/<img ([^>]*)src=\\\?(\"|\')'.preg_quote(htmlspecialchars($image), '/').'\\\?(\2)([^>\/]*)\/*>/is', $upload, $content);
    51                         }
    52                 }
    53         }
    54         // Set the post_content and status.
    55         $post['post_content'] = $content;
    56         if ( isset( $_POST['publish'] ) && current_user_can( 'publish_posts' ) )
    57                 $post['post_status'] = 'publish';
    58         elseif ( isset( $_POST['review'] ) )
    59                 $post['post_status'] = 'pending';
    60         else
    61                 $post['post_status'] = 'draft';
    62 
    63         // Error handling for media_sideload.
    64         if ( is_wp_error($upload) ) {
    65                 wp_delete_post($post_ID);
    66                 wp_die( esc_html( $upload->get_error_message() ) );
    67         } else {
    68                 // Post formats.
    69                 if ( isset( $_POST['post_format'] ) ) {
    70                         if ( current_theme_supports( 'post-formats', $_POST['post_format'] ) )
    71                                 set_post_format( $post_ID, $_POST['post_format'] );
    72                         elseif ( '0' == $_POST['post_format'] )
    73                                 set_post_format( $post_ID, false );
    74                 }
    75 
    76                 $post_ID = wp_update_post($post);
    77         }
    78 
    79         return $post_ID;
     17if ( empty( $GLOBALS['wp_press_this'] ) ) {
     18        include( ABSPATH . 'wp-admin/includes/class-wp-press-this.php' );
    8019}
    8120
    82 // For submitted posts.
    83 if ( isset($_REQUEST['action']) && 'post' == $_REQUEST['action'] ) {
    84         check_admin_referer('press-this');
    85         $posted = $post_ID = press_it();
    86 } else {
    87         $post = get_default_post_to_edit('post', true);
    88         $post_ID = $post->ID;
    89 }
    90 
    91 // Set Variables
    92 $title = isset( $_GET['t'] ) ? trim( strip_tags( html_entity_decode( wp_unslash( $_GET['t'] ) , ENT_QUOTES) ) ) : '';
    93 
    94 $selection = '';
    95 if ( !empty($_GET['s']) ) {
    96         $selection = str_replace('&apos;', "'", wp_unslash($_GET['s']));
    97         $selection = trim( htmlspecialchars( html_entity_decode($selection, ENT_QUOTES) ) );
    98 }
    99 
    100 if ( ! empty($selection) ) {
    101         $selection = preg_replace('/(\r?\n|\r)/', '</p><p>', $selection);
    102         $selection = '<p>' . str_replace('<p></p>', '', $selection) . '</p>';
    103 }
    104 
    105 $url = isset($_GET['u']) ? esc_url($_GET['u']) : '';
    106 $image = isset($_GET['i']) ? $_GET['i'] : '';
    107 
    108 if ( !empty($_REQUEST['ajax']) ) {
    109         switch ($_REQUEST['ajax']) {
    110                 case 'video': ?>
    111                         <script type="text/javascript">
    112                                 jQuery('.select').click(function() {
    113                                         append_editor(jQuery('#embed-code').val());
    114                                         jQuery('#extra-fields').hide();
    115                                         jQuery('#extra-fields').html('');
    116                                 });
    117                                 jQuery('.close').click(function() {
    118                                         jQuery('#extra-fields').hide();
    119                                         jQuery('#extra-fields').html('');
    120                                 });
    121                         </script>
    122                         <div class="postbox">
    123                                 <h2><label for="embed-code"><?php _e('Embed Code') ?></label></h2>
    124                                 <div class="inside">
    125                                         <textarea name="embed-code" id="embed-code" rows="8" cols="40"><?php echo esc_textarea( $selection ); ?></textarea>
    126                                         <p id="options"><a href="#" class="select button"><?php _e('Insert Video'); ?></a> <a href="#" class="close button"><?php _e('Cancel'); ?></a></p>
    127                                 </div>
    128                         </div>
    129                         <?php break;
    130 
    131                 case 'photo_thickbox': ?>
    132                         <script type="text/javascript">
    133                                 jQuery('.cancel').click(function() {
    134                                         tb_remove();
    135                                 });
    136                                 jQuery('.select').click(function() {
    137                                         image_selector(this);
    138                                 });
    139                         </script>
    140                         <h3 class="tb"><label for="tb_this_photo_description"><?php _e('Description') ?></label></h3>
    141                         <div class="titlediv">
    142                                 <div class="titlewrap">
    143                                         <input id="tb_this_photo_description" name="photo_description" class="tb_this_photo_description tbtitle text" type="text" onkeypress="if(event.keyCode==13) image_selector(this);" value="<?php echo esc_attr($title);?>"/>
    144                                 </div>
    145                         </div>
    146 
    147                         <p class="centered">
    148                                 <input type="hidden" name="this_photo" value="<?php echo esc_attr( $image ); ?>" id="tb_this_photo" class="tb_this_photo" />
    149                                 <a href="#" class="select">
    150                                         <img src="<?php echo esc_url( $image ); ?>" alt="<?php esc_attr_e( 'Click to insert.' ); ?>" title="<?php esc_attr_e( 'Click to insert.' ); ?>" />
    151                                 </a>
    152                         </p>
    153 
    154                         <p id="options"><a href="#" class="select button"><?php _e('Insert Image'); ?></a> <a href="#" class="cancel button"><?php _e('Cancel'); ?></a></p>
    155                         <?php break;
    156         case 'photo_images':
    157                 /**
    158                  * Retrieve all image URLs from given URI.
    159                  *
    160                  * @since 2.6.0
    161                  *
    162                  * @param string $uri
    163                  * @return string
    164                  */
    165                 function get_images_from_uri($uri) {
    166                         $uri = preg_replace('/\/#.+?$/','', $uri);
    167                         if ( preg_match( '/\.(jpe?g|jpe|gif|png)\b/i', $uri ) && !strpos( $uri, 'blogger.com' ) )
    168                                 return "'" . esc_attr( html_entity_decode($uri) ) . "'";
    169                         $content = wp_remote_fopen($uri);
    170                         if ( false === $content )
    171                                 return '';
    172                         $host = parse_url($uri);
    173                         $pattern = '/<img ([^>]*)src=(\"|\')([^<>\'\"]+)(\2)([^>]*)\/*>/i';
    174                         $content = str_replace(array("\n","\t","\r"), '', $content);
    175                         preg_match_all($pattern, $content, $matches);
    176                         if ( empty($matches[0]) )
    177                                 return '';
    178                         $sources = array();
    179                         foreach ($matches[3] as $src) {
    180 
    181                                 // If no http in URL.
    182                                 if (strpos($src, 'http') === false)
    183                                         // If it doesn't have a relative URI.
    184                                         if ( strpos($src, '../') === false && strpos($src, './') === false && strpos($src, '/') === 0)
    185                                                 $src = 'http://'.str_replace('//','/', $host['host'].'/'.$src);
    186                                         else
    187                                                 $src = 'http://'.str_replace('//','/', $host['host'].'/'.dirname($host['path']).'/'.$src);
    188                                 $sources[] = esc_url($src);
    189                         }
    190                         return "'" . implode("','", $sources) . "'";
    191                 }
    192                 $url = wp_kses(urldecode($url), null);
    193                 echo 'new Array('.get_images_from_uri($url).')';
    194                 break;
    195 
    196         case 'photo_js': ?>
    197                 // Gather images and load some default JS.
    198                 var last = null
    199                 var img, img_tag, aspect, w, h, skip, i, strtoappend = "";
    200                 if(photostorage == false) {
    201                 var my_src = eval(
    202                         jQuery.ajax({
    203                                 type: "GET",
    204                                 url: "<?php echo esc_url($_SERVER['PHP_SELF']); ?>",
    205                                 cache : false,
    206                                 async : false,
    207                                 data: "ajax=photo_images&u=<?php echo urlencode($url); ?>",
    208                                 dataType : "script"
    209                         }).responseText
    210                 );
    211                 if(my_src.length == 0) {
    212                         var my_src = eval(
    213                                 jQuery.ajax({
    214                                         type: "GET",
    215                                         url: "<?php echo esc_url($_SERVER['PHP_SELF']); ?>",
    216                                         cache : false,
    217                                         async : false,
    218                                         data: "ajax=photo_images&u=<?php echo urlencode($url); ?>",
    219                                         dataType : "script"
    220                                 }).responseText
    221                         );
    222                         if(my_src.length == 0) {
    223                                 strtoappend = '<?php _e('Unable to retrieve images or no images on page.'); ?>';
    224                         }
    225                 }
    226                 }
    227                 for (i = 0; i < my_src.length; i++) {
    228                         img = new Image();
    229                         img.src = my_src[i];
    230                         img_attr = 'id="img' + i + '"';
    231                         skip = false;
    232 
    233                         maybeappend = '<a href="?ajax=photo_thickbox&amp;i=' + encodeURIComponent(img.src) + '&amp;u=<?php echo urlencode($url); ?>&amp;height=400&amp;width=500" title="" class="thickbox"><img src="' + img.src + '" ' + img_attr + '/></a>';
    234 
    235                         if (img.width && img.height) {
    236                                 if (img.width >= 30 && img.height >= 30) {
    237                                         aspect = img.width / img.height;
    238                                         scale = (aspect > 1) ? (71 / img.width) : (71 / img.height);
    239 
    240                                         w = img.width;
    241                                         h = img.height;
    242 
    243                                         if (scale < 1) {
    244                                                 w = parseInt(img.width * scale);
    245                                                 h = parseInt(img.height * scale);
    246                                         }
    247                                         img_attr += ' style="width: ' + w + 'px; height: ' + h + 'px;"';
    248                                         strtoappend += maybeappend;
    249                                 }
    250                         } else {
    251                                 strtoappend += maybeappend;
    252                         }
    253                 }
    254 
    255                 function pick(img, desc) {
    256                         if (img) {
    257                                 if('object' == typeof jQuery('.photolist input') && jQuery('.photolist input').length != 0) length = jQuery('.photolist input').length;
    258                                 if(length == 0) length = 1;
    259                                 jQuery('.photolist').append('<input name="photo_src[' + length + ']" value="' + img +'" type="hidden"/>');
    260                                 jQuery('.photolist').append('<input name="photo_description[' + length + ']" value="' + desc +'" type="hidden"/>');
    261                                 insert_editor( "\n\n" + encodeURI('<p style="text-align: center;"><a href="<?php echo $url; ?>"><img src="' + img +'" alt="' + desc + '" /></a></p>'));
    262                         }
    263                         return false;
    264                 }
    265 
    266                 function image_selector(el) {
    267                         var desc, src, parent = jQuery(el).closest('#photo-add-url-div');
    268 
    269                         if ( parent.length ) {
    270                                 desc = parent.find('input.tb_this_photo_description').val() || '';
    271                                 src = parent.find('input.tb_this_photo').val() || ''
    272                         } else {
    273                                 desc = jQuery('#tb_this_photo_description').val() || '';
    274                                 src = jQuery('#tb_this_photo').val() || ''
    275                         }
    276 
    277                         tb_remove();
    278                         pick(src, desc);
    279                         jQuery('#extra-fields').hide();
    280                         jQuery('#extra-fields').html('');
    281                         return false;
    282                 }
    283 
    284                 jQuery('#extra-fields').html('<div class="postbox"><h2><?php _e( 'Add Photos' ); ?> <small id="photo_directions">(<?php _e("click images to select") ?>)</small></h2><ul class="actions"><li><a href="#" id="photo-add-url" class="button button-small"><?php _e("Add from URL") ?> +</a></li></ul><div class="inside"><div class="titlewrap"><div id="img_container"></div></div><p id="options"><a href="#" class="close button"><?php _e('Cancel'); ?></a><a href="#" class="refresh button"><?php _e('Refresh'); ?></a></p></div>');
    285                 jQuery('#img_container').html(strtoappend);
    286                 <?php break;
    287 }
    288 die;
    289 }
    290 
    291         wp_enqueue_style( 'colors' );
    292         wp_enqueue_script( 'post' );
    293         add_thickbox();
    294         _wp_admin_html_begin();
    295 ?>
    296 <title><?php _e('Press This') ?></title>
    297 <script type="text/javascript">
    298 addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
    299 var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>', pagenow = 'press-this', isRtl = <?php echo (int) is_rtl(); ?>;
    300 var photostorage = false;
    301 </script>
    302 
    303 <?php
    304         /** This action is documented in wp-admin/admin-header.php */
    305         do_action( 'admin_enqueue_scripts', 'press-this.php' );
    306 
    307         /**
    308          * Fires when styles are printed for the Press This admin page.
    309          *
    310          * @since 3.7.0
    311          */
    312         do_action( 'admin_print_styles-press-this.php' );
    313 
    314         /** This action is documented in wp-admin/admin-header.php */
    315         do_action( 'admin_print_styles' );
    316 
    317         /**
    318          * Fires when scripts are printed for the Press This admin page.
    319          *
    320          * @since 3.7.0
    321          */
    322         do_action( 'admin_print_scripts-press-this.php' );
    323 
    324         /** This action is documented in wp-admin/admin-header.php */
    325         do_action( 'admin_print_scripts' );
    326 
    327         /**
    328          * Fires in the head tag on the Press This admin page.
    329          *
    330          * @since 3.7.0
    331          */
    332         do_action( 'admin_head-press-this.php' );
    333 
    334         /** This action is documented in wp-admin/admin-header.php */
    335         do_action( 'admin_head' );
    336 ?>
    337         <script type="text/javascript">
    338         var wpActiveEditor = 'content';
    339 
    340         function insert_plain_editor(text) {
    341                 if ( typeof(QTags) != 'undefined' )
    342                         QTags.insertContent(text);
    343         }
    344         function set_editor(text) {
    345                 if ( '' == text || '<p></p>' == text )
    346                         text = '<p><br /></p>';
    347 
    348                 if ( tinyMCE.activeEditor )
    349                         tinyMCE.execCommand('mceSetContent', false, text);
    350         }
    351         function insert_editor(text) {
    352                 if ( '' != text && tinyMCE.activeEditor && ! tinyMCE.activeEditor.isHidden()) {
    353                         tinyMCE.execCommand('mceInsertContent', false, '<p>' + decodeURI(tinymce.DOM.decode(text)) + '</p>', {format : 'raw'});
    354                 } else {
    355                         insert_plain_editor(decodeURI(text));
    356                 }
    357         }
    358         function append_editor(text) {
    359                 if ( '' != text && tinyMCE.activeEditor && ! tinyMCE.activeEditor.isHidden()) {
    360                         tinyMCE.execCommand('mceSetContent', false, tinyMCE.activeEditor.getContent({format : 'raw'}) + '<p>' + text + '</p>');
    361                 } else {
    362                         insert_plain_editor(text);
    363                 }
    364         }
    365 
    366         function show(tab_name) {
    367                 jQuery('#extra-fields').html('');
    368                 switch(tab_name) {
    369                         case 'video' :
    370                                 jQuery('#extra-fields').load('<?php echo esc_url($_SERVER['PHP_SELF']); ?>', { ajax: 'video', s: '<?php echo esc_attr($selection); ?>'}, function() {
    371                                         <?php
    372                                         $content = '';
    373                                         if ( preg_match("/youtube\.com\/watch/i", $url) ) {
    374                                                 list($domain, $video_id) = explode("v=", $url);
    375                                                 $video_id = esc_attr($video_id);
    376                                                 $content = '<object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/' . $video_id . '"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/' . $video_id . '" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object>';
    377 
    378                                         } elseif ( preg_match("/vimeo\.com\/[0-9]+/i", $url) ) {
    379                                                 list($domain, $video_id) = explode(".com/", $url);
    380                                                 $video_id = esc_attr($video_id);
    381                                                 $content = '<object width="400" height="225"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://www.vimeo.com/moogaloop.swf?clip_id=' . $video_id . '&amp;server=www.vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" />      <embed src="http://www.vimeo.com/moogaloop.swf?clip_id=' . $video_id . '&amp;server=www.vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="225"></embed></object>';
    382 
    383                                                 if ( trim($selection) == '' )
    384                                                         $selection = '<p><a href="http://www.vimeo.com/' . $video_id . '?pg=embed&sec=' . $video_id . '">' . $title . '</a> on <a href="http://vimeo.com?pg=embed&sec=' . $video_id . '">Vimeo</a></p>';
    385 
    386                                         } elseif ( strpos( $selection, '<object' ) !== false ) {
    387                                                 $content = $selection;
    388                                         }
    389                                         ?>
    390                                         jQuery('#embed-code').prepend('<?php echo htmlentities($content); ?>');
    391                                 });
    392                                 jQuery('#extra-fields').show();
    393                                 return false;
    394                                 break;
    395                         case 'photo' :
    396                                 function setup_photo_actions() {
    397                                         jQuery('.close').click(function() {
    398                                                 jQuery('#extra-fields').hide();
    399                                                 jQuery('#extra-fields').html('');
    400                                         });
    401                                         jQuery('.refresh').click(function() {
    402                                                 photostorage = false;
    403                                                 show('photo');
    404                                         });
    405                                         jQuery('#photo-add-url').click(function(){
    406                                                 var form = jQuery('#photo-add-url-div').clone();
    407                                                 jQuery('#img_container').empty().append( form.show() );
    408                                         });
    409                                         jQuery('#waiting').hide();
    410                                         jQuery('#extra-fields').show();
    411                                 }
    412 
    413                                 jQuery('#waiting').show();
    414                                 if(photostorage == false) {
    415                                         jQuery.ajax({
    416                                                 type: "GET",
    417                                                 cache : false,
    418                                                 url: "<?php echo esc_url($_SERVER['PHP_SELF']); ?>",
    419                                                 data: "ajax=photo_js&u=<?php echo urlencode($url)?>",
    420                                                 dataType : "script",
    421                                                 success : function(data) {
    422                                                         eval(data);
    423                                                         photostorage = jQuery('#extra-fields').html();
    424                                                         setup_photo_actions();
    425                                                 }
    426                                         });
    427                                 } else {
    428                                         jQuery('#extra-fields').html(photostorage);
    429                                         setup_photo_actions();
    430                                 }
    431                                 return false;
    432                                 break;
    433                 }
    434         }
    435         jQuery(document).ready(function($) {
    436                 var $contnet = $( '#content' );
    437 
    438                 // Resize screen.
    439                 window.resizeTo(760,580);
    440 
    441                 // Set button actions.
    442                 jQuery('#photo_button').click(function() { show('photo'); return false; });
    443                 jQuery('#video_button').click(function() { show('video'); return false; });
    444 
    445                 // Auto select.
    446                 <?php if ( preg_match("/youtube\.com\/watch/i", $url) ) { ?>
    447                         show('video');
    448                 <?php } elseif ( preg_match("/vimeo\.com\/[0-9]+/i", $url) ) { ?>
    449                         show('video');
    450                 <?php } elseif ( preg_match("/flickr\.com/i", $url) ) { ?>
    451                         show('photo');
    452                 <?php } ?>
    453                 jQuery('#title').unbind();
    454                 jQuery('#publish, #save').click(function() { jQuery('.press-this #publishing-actions .spinner').css('display', 'inline-block'); });
    455 
    456                 $('#tagsdiv-post_tag, #categorydiv').children('h3, .handlediv').click(function(){
    457                         $(this).siblings('.inside').toggle();
    458                 });
    459 
    460                 if ( $( '#wp-content-wrap' ).hasClass( 'html-active' ) && window.switchEditors &&
    461                         ( tinyMCEPreInit.mceInit.content && tinyMCEPreInit.mceInit.content.wpautop ) ) {
    462                         // The Text editor is default, run the initial content through pre_wpautop() to convert the paragraphs
    463                         $contnet.text( window.switchEditors.pre_wpautop( $contnet.text() ) );
    464                 }
    465         });
    466 </script>
    467 </head>
    468 <?php
    469 $admin_body_class = ( is_rtl() ) ? 'rtl' : '';
    470 $admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
    471 ?>
    472 <body class="press-this wp-admin wp-core-ui <?php echo $admin_body_class; ?>">
    473 <form action="press-this.php?action=post" method="post">
    474 <div id="poststuff" class="metabox-holder">
    475         <div id="side-sortables" class="press-this-sidebar">
    476                 <div class="sleeve">
    477                         <?php wp_nonce_field('press-this') ?>
    478                         <input type="hidden" name="post_type" id="post_type" value="text"/>
    479                         <input type="hidden" name="autosave" id="autosave" />
    480                         <input type="hidden" id="original_post_status" name="original_post_status" value="draft" />
    481                         <input type="hidden" id="prev_status" name="prev_status" value="draft" />
    482                         <input type="hidden" id="post_id" name="post_id" value="<?php echo (int) $post_ID; ?>" />
    483 
    484                         <!-- This div holds the photo metadata -->
    485                         <div class="photolist"></div>
    486 
    487                         <div id="submitdiv" class="postbox">
    488                                 <div class="handlediv" title="<?php esc_attr_e( 'Click to toggle' ); ?>"><br /></div>
    489                                 <h3 class="hndle"><?php _e('Press This') ?></h3>
    490                                 <div class="inside">
    491                                         <p id="publishing-actions">
    492                                         <?php
    493                                                 submit_button( __( 'Save Draft' ), 'button', 'draft', false, array( 'id' => 'save' ) );
    494                                                 if ( current_user_can('publish_posts') ) {
    495                                                         submit_button( __( 'Publish' ), 'primary', 'publish', false );
    496                                                 } else {
    497                                                         echo '<br /><br />';
    498                                                         submit_button( __( 'Submit for Review' ), 'primary', 'review', false );
    499                                                 } ?>
    500                                                 <span class="spinner" style="display: none;"></span>
    501                                         </p>
    502                                         <?php if ( current_theme_supports( 'post-formats' ) && post_type_supports( 'post', 'post-formats' ) ) :
    503                                                         $post_formats = get_theme_support( 'post-formats' );
    504                                                         if ( is_array( $post_formats[0] ) ) :
    505                                                                 $default_format = get_option( 'default_post_format', '0' );
    506                                                 ?>
    507                                         <p>
    508                                                 <label for="post_format"><?php _e( 'Post Format:' ); ?>
    509                                                 <select name="post_format" id="post_format">
    510                                                         <option value="0"><?php echo get_post_format_string( 'standard' ); ?></option>
    511                                                 <?php foreach ( $post_formats[0] as $format ): ?>
    512                                                         <option<?php selected( $default_format, $format ); ?> value="<?php echo esc_attr( $format ); ?>"> <?php echo esc_html( get_post_format_string( $format ) ); ?></option>
    513                                                 <?php endforeach; ?>
    514                                                 </select></label>
    515                                         </p>
    516                                         <?php endif; endif; ?>
    517                                 </div>
    518                         </div>
    519 
    520                         <?php $tax = get_taxonomy( 'category' ); ?>
    521                         <div id="categorydiv" class="postbox">
    522                                 <div class="handlediv" title="<?php esc_attr_e( 'Click to toggle' ); ?>"><br /></div>
    523                                 <h3 class="hndle"><?php _e('Categories') ?></h3>
    524                                 <div class="inside">
    525                                 <div id="taxonomy-category" class="categorydiv">
    526 
    527                                         <ul id="category-tabs" class="category-tabs">
    528                                                 <li class="tabs"><a href="#category-all"><?php echo $tax->labels->all_items; ?></a></li>
    529                                                 <li class="hide-if-no-js"><a href="#category-pop"><?php _e( 'Most Used' ); ?></a></li>
    530                                         </ul>
    531 
    532                                         <div id="category-pop" class="tabs-panel" style="display: none;">
    533                                                 <ul id="categorychecklist-pop" class="categorychecklist form-no-clear" >
    534                                                         <?php $popular_ids = wp_popular_terms_checklist( 'category' ); ?>
    535                                                 </ul>
    536                                         </div>
    537 
    538                                         <div id="category-all" class="tabs-panel">
    539                                                 <ul id="categorychecklist" data-wp-lists="list:category" class="categorychecklist form-no-clear">
    540                                                         <?php wp_terms_checklist($post_ID, array( 'taxonomy' => 'category', 'popular_cats' => $popular_ids ) ) ?>
    541                                                 </ul>
    542                                         </div>
    543 
    544                                         <?php if ( !current_user_can($tax->cap->assign_terms) ) : ?>
    545                                         <p><em><?php _e('You cannot modify this Taxonomy.'); ?></em></p>
    546                                         <?php endif; ?>
    547                                         <?php if ( current_user_can($tax->cap->edit_terms) ) : ?>
    548                                                 <div id="category-adder" class="wp-hidden-children">
    549                                                         <h4>
    550                                                                 <a id="category-add-toggle" href="#category-add" class="hide-if-no-js">
    551                                                                         <?php printf( __( '+ %s' ), $tax->labels->add_new_item ); ?>
    552                                                                 </a>
    553                                                         </h4>
    554                                                         <p id="category-add" class="category-add wp-hidden-child">
    555                                                                 <label class="screen-reader-text" for="newcategory"><?php echo $tax->labels->add_new_item; ?></label>