Plugin Directory

Changeset 1536575


Ignore:
Timestamp:
11/18/2016 09:21:24 PM (9 years ago)
Author:
goldenapples
Message:

Bump stable version tag

Location:
shortcode-ui/trunk
Files:
72 added
7 deleted
29 edited

Legend:

Unmodified
Added
Removed
  • shortcode-ui/trunk/Gruntfile.js

    r1278066 r1536575  
    33    'use strict';
    44    var remapify = require('remapify');
    5     var banner = '/**\n * <%= pkg.homepage %>\n * Copyright (c) <%= grunt.template.today("yyyy") %>\n * This file is generated automatically. Do not edit.\n */\n';
     5    var banner   = '/**\n * <%= pkg.homepage %>\n * Copyright (c) <%= grunt.template.today("yyyy") %>\n * This file is generated automatically. Do not edit.\n */\n';
     6
     7    // Scripts from WP Core required by Jasmine tests.
     8    var jasmineCoreScripts = [
     9        'wp-includes/js/jquery/jquery.js',
     10        'wp-includes/js/underscore.min.js',
     11        'wp-includes/js/backbone.min.js',
     12        'wp-includes/js/wp-util.js',
     13        'wp-includes/js/shortcode.js',
     14        'wp-admin/js/editor.js',
     15    ];
     16
    617    // Project configuration
    718    grunt.initConfig( {
     
    136147                    helpers: 'js-tests/build/helpers.js',
    137148                    vendor: [
    138                         'js-tests/vendor/jquery.js',
    139                         'js-tests/vendor/underscore.js',
    140                         'js-tests/vendor/backbone.js',
    141                         'js-tests/vendor/wp-shortcode.js',
    142                         'js-tests/vendor/wp-util.js',
    143                         'js-tests/vendor/wp-editors.js',
    144                         'js-tests/vendor/mock-ajax.js',
    145                     ],
     149                        'js-tests/vendor/mock-ajax.js'
     150                    ].concat( jasmineCoreScripts.map( function( script ) {
     151                        return 'js-tests/vendor/' + script
     152                    } ) ),
    146153                }
    147154            }
     
    187194    } );
    188195
     196    /**
     197     * Helper task to keep all the scripts from WordPress core that are required by the Jasmine tests up to date.
     198     *
     199     * Note the list of scripts needs to be kept up to date.
     200     *
     201     * Pass the location of your WordPress installation using --abspath.
     202     */
     203    grunt.registerTask( 'updateJasmineCoreScripts', function() {
     204
     205        var abspath = grunt.option( "abspath" );
     206
     207        if ( ! grunt.file.exists( abspath + '/wp-includes' ) ) {
     208            grunt.fail.fatal( 'WordPress install not found. Currently looking here: ' + abspath );
     209        }
     210
     211        for ( var i = 0; i < jasmineCoreScripts.length; i++ ) {
     212            if ( grunt.file.exists( abspath + '/' + jasmineCoreScripts[ i ] ) ) {
     213                grunt.file.copy(
     214                    abspath + '/' + jasmineCoreScripts[ i ] ,
     215                    'js-tests/vendor/' + jasmineCoreScripts[ i ]
     216                );
     217            } else {
     218                grunt.log.error( 'File not found: ' + abspath + '/' + jasmineCoreScripts[i] );
     219            }
     220        }
     221
     222    });
     223
    189224    grunt.loadNpmTasks( 'grunt-sass' );
    190225    grunt.loadNpmTasks( 'grunt-postcss' );
  • shortcode-ui/trunk/composer.json

    r1147525 r1536575  
    1212    ],
    1313    "require-dev": {
     14        "squizlabs/php_codesniffer": "2.x-dev",
    1415        "wp-coding-standards/wpcs": "dev-develop"
    1516    },
  • shortcode-ui/trunk/css/sass/_field-image.scss

    r1231560 r1536575  
    1 .edit-shortcode-form .shortcake-attachment-preview {
     1.edit-shortcode-form {
    22
    3     width: 150px;
    4     height: 150px;
    5     margin: 0 10px 10px 0;
    6     line-height: 150px;
    7     text-align: center;
    8     padding: 0;
    9 
    10     &:before {
    11         display: none;
     3    .button.shortcake-attachment-select {
     4        display: block;
     5        clear: both;
     6        margin-bottom: 15px;
    127    }
    138
    14     .thumbnail:hover:after {
    15         background: rgba(0,0,0,0.1);
    16         transition: all .3s linear;
    17      }
    18 
    19     &:not( .has-attachment ) {
    20         border: 2px dashed #DDD;
    21         border-radius: 2px;
    22         background: transparent;
    23         box-shadow: none;
     9    .shortcake-attachment-preview {
     10        float: left;
     11        margin: 0 20px 20px 0;
     12        width: 150px;
    2413    }
    2514
    26     .button.add {
    27         vertical-align: middle;
    28         z-index: 1;
     15    .shortcode-ui-field-attachment .description {
     16        margin: 10px 0;
    2917    }
    3018
    31     .button.remove {
     19    .shortcake-attachment-preview-container {
    3220
    33         z-index: 1;
    34         display: none;
    35         position: absolute;
    36         top: 5px;
    37         right: 5px;
    38         border: 1px solid #aaa;
    39         box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.15 );
    40         text-indent: 100%;
    41         whitespace: nowrap;
    42         width: 24px;
    43         height: 24px;
     21        width: 150px !important;
     22        height: 150px !important;
     23        margin: 0 10px 10px 0;
     24        line-height: 150px;
     25        text-align: center;
    4426        padding: 0;
    45         overflow:hidden;
    4627
    47         &:after {
    48             content: "\00d7";
     28        &:before {
     29            display: none;
     30        }
     31
     32        .button.remove {
     33
     34            z-index: 1;
     35            display: block;
    4936            position: absolute;
    50             top: -1px;
    51             left: 5px;
    52             font-size: 22px;
    53             text-indent: 0;
     37            top: 5px;
     38            right: 5px;
     39            border: 1px solid #aaa;
     40            box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.15 );
     41            text-indent: 100%;
     42            whitespace: nowrap;
     43            width: 24px;
     44            height: 24px;
     45            padding: 0;
     46            overflow:hidden;
     47
     48            &:after {
     49                content: "\00d7";
     50                position: absolute;
     51                top: -1px;
     52                left: 5px;
     53                font-size: 22px;
     54                text-indent: 0;
     55            }
    5456        }
    55     }
    5657
    57     .loading-indicator,
    58     &.loading .button.add {
    59         display: none;
    60     }
     58        .thumbnail img {
     59            max-width: 100%;
     60            max-height: 100%;
     61            width: auto;
     62            height: auto;
     63        }
    6164
    62     &.loading .loading-indicator {
    63         display: block;
    64         position: relative;
    65         width: 100%;
    66         height: 100%;
    67     }
     65        .loading-indicator,
     66        &.loading .button.add {
     67            display: none;
     68        }
    6869
    69     .loading-indicator {
    70         .dashicons {
    71             font-size: 80px;
    72             height: 100px;
    73             line-height: 100px;
     70        &.loading .loading-indicator {
     71            display: block;
     72            position: relative;
    7473            width: 100%;
    75             text-align: center;
    76             vertical-align: middle;
     74            height: 100%;
    7775        }
    78         .attachment-preview-loading {
    79             width: 60px;
    80             height: 5px;
    81             overflow: hidden;
    82             background-color: transparent;
    83             margin: -30px auto 0;
    8476
    85             ins {
    86                 background-color: #464646;
    87                 margin: 0 0 0 -60px;
     77        .loading-indicator {
     78            .dashicons {
     79                font-size: 80px;
     80                height: 100px;
     81                line-height: 100px;
     82                width: 100%;
     83                text-align: center;
     84                vertical-align: middle;
     85            }
     86            .attachment-preview-loading {
    8887                width: 60px;
    8988                height: 5px;
    90                 display: block;
    91                 -webkit-animation: attachment-preview-loading 1.3s infinite 1s linear;
    92                 animation: attachment-preview-loading 1.3s infinite 1s linear;
     89                overflow: hidden;
     90                background-color: transparent;
     91                margin: -30px auto 0;
     92
     93                ins {
     94                    background-color: #464646;
     95                    margin: 0 0 0 -60px;
     96                    width: 60px;
     97                    height: 5px;
     98                    display: block;
     99                    -webkit-animation: attachment-preview-loading 1.3s infinite 1s linear;
     100                    animation: attachment-preview-loading 1.3s infinite 1s linear;
     101                }
    93102            }
    94103        }
    95     }
    96104
    97     .filename {
    98         line-height: 1.4em
    99     }
     105        .filename {
     106            line-height: 1.4em
     107        }
    100108
    101     &.has-attachment  {
    102         .button.add {
    103             display: none;
    104         }
    105         .button.remove {
    106             display: block;
    107         }
    108109    }
    109110
  • shortcode-ui/trunk/css/sass/shortcode-ui.scss

    r1278066 r1536575  
    160160
    161161@import 'field-image';
     162@import 'select2-fields';
  • shortcode-ui/trunk/css/shortcode-ui-editor-styles.css

    r1278066 r1536575  
    11.wpview-wrap.wp-mce-view-show-toolbar .toolbar {
    22  display: block; }
     3
    34.wpview-wrap .shortcake-error {
    45  color: red;
    56  font-weight: bold; }
     7
    68.wpview-wrap .shortcake-empty {
    79  font-family: Consolas, Monaco, monospace;
  • shortcode-ui/trunk/css/shortcode-ui-editor-styles.css.map

    r1278066 r1536575  
    1 {"version":3,"sources":["../shortcode-ui-editor-styles.scss"],"names":[],"mappings":"AAGA;EACG,eAAA,EAAA;AAIH;EACE,WAAA;EACA,kBAAA,EAAA;AAGF;EACE,yCAAA;EACA,YAAA;EACA,gBAAA,EAAA;;AAIF;EACC,sBAAA;EACA,YAAA;EACA,iBAAA,EAAA","file":"shortcode-ui-editor-styles.css"}
     1{"version":3,"sources":["sass/shortcode-ui-editor-styles.scss"],"names":[],"mappings":"AAAA;EAIG,eAAe,EACf;;AALH;EASE,WAAW;EACX,kBAAkB,EAClB;;AAXF;EAcE,yCAAyC;EACzC,YAAY;EACZ,gBAAgB,EAChB;;AAGF;EACC,sBAAsB;EACtB,YAAY;EACZ,iBAAiB,EACjB","file":"shortcode-ui-editor-styles.css"}
  • shortcode-ui/trunk/css/shortcode-ui.css

    r1278066 r1536575  
    66  max-height: 800px;
    77  margin: auto; }
     8
    89.shortcode-ui-insert-modal .media-frame-content {
    910  top: 54px; }
     
    2526      height: 120px;
    2627      font-size: 64px; }
    27       .add-shortcode-list .shortcode-list-item .add-shortcode-list-item-icon .dashicons, .add-shortcode-list .shortcode-list-item .add-shortcode-list-item-icon img {
     28      .add-shortcode-list .shortcode-list-item .add-shortcode-list-item-icon .dashicons,
     29      .add-shortcode-list .shortcode-list-item .add-shortcode-list-item-icon img {
    2830        position: absolute;
    2931        top: 50%;
    3032        left: 50%;
    3133        -webkit-transform: translate(-50%, -50%);
    32             -ms-transform: translate(-50%, -50%);
    3334                transform: translate(-50%, -50%);
    3435        font-size: inherit;
     
    5859  height: 34px;
    5960  padding: 10px 10px 0; }
     61
    6062.shortcode-ui-content .edit-shortcode-tabs-content {
    6163  padding: 10px;
    6264  border-top: 1px solid #ddd; }
     65
    6366.shortcode-ui-content a.wp-color-result {
    6467  border-bottom: 1px solid #ccc; }
     68
    6569.shortcode-ui-content .media-toolbar {
    6670  position: relative;
     
    7276    display: block;
    7377    clear: both; }
    74   .edit-shortcode-form input, .edit-shortcode-form textarea {
     78  .edit-shortcode-form input,
     79  .edit-shortcode-form textarea {
    7580    border: 1px solid #ddd;
    7681    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.07);
     
    105110    clear: both; }
    106111
     112.edit-shortcode-form .button.shortcake-attachment-select {
     113  display: block;
     114  clear: both;
     115  margin-bottom: 15px; }
     116
    107117.edit-shortcode-form .shortcake-attachment-preview {
    108   width: 150px;
    109   height: 150px;
     118  float: left;
     119  margin: 0 20px 20px 0;
     120  width: 150px; }
     121
     122.edit-shortcode-form .shortcode-ui-field-attachment .description {
     123  margin: 10px 0; }
     124
     125.edit-shortcode-form .shortcake-attachment-preview-container {
     126  width: 150px !important;
     127  height: 150px !important;
    110128  margin: 0 10px 10px 0;
    111129  line-height: 150px;
    112130  text-align: center;
    113131  padding: 0; }
    114   .edit-shortcode-form .shortcake-attachment-preview:before {
     132  .edit-shortcode-form .shortcake-attachment-preview-container:before {
    115133    display: none; }
    116   .edit-shortcode-form .shortcake-attachment-preview .thumbnail:hover:after {
    117     background: rgba(0, 0, 0, 0.1);
    118     -webkit-transition: all .3s linear;
    119             transition: all .3s linear; }
    120   .edit-shortcode-form .shortcake-attachment-preview:not(.has-attachment) {
    121     border: 2px dashed #DDD;
    122     border-radius: 2px;
    123     background: transparent;
    124     box-shadow: none; }
    125   .edit-shortcode-form .shortcake-attachment-preview .button.add {
    126     vertical-align: middle;
    127     z-index: 1; }
    128   .edit-shortcode-form .shortcake-attachment-preview .button.remove {
     134  .edit-shortcode-form .shortcake-attachment-preview-container .button.remove {
    129135    z-index: 1;
    130     display: none;
     136    display: block;
    131137    position: absolute;
    132138    top: 5px;
     
    140146    padding: 0;
    141147    overflow: hidden; }
    142     .edit-shortcode-form .shortcake-attachment-preview .button.remove:after {
     148    .edit-shortcode-form .shortcake-attachment-preview-container .button.remove:after {
    143149      content: "\00d7";
    144150      position: absolute;
     
    147153      font-size: 22px;
    148154      text-indent: 0; }
    149   .edit-shortcode-form .shortcake-attachment-preview .loading-indicator, .edit-shortcode-form .shortcake-attachment-preview.loading .button.add {
     155  .edit-shortcode-form .shortcake-attachment-preview-container .thumbnail img {
     156    max-width: 100%;
     157    max-height: 100%;
     158    width: auto;
     159    height: auto; }
     160  .edit-shortcode-form .shortcake-attachment-preview-container .loading-indicator,
     161  .edit-shortcode-form .shortcake-attachment-preview-container.loading .button.add {
    150162    display: none; }
    151   .edit-shortcode-form .shortcake-attachment-preview.loading .loading-indicator {
     163  .edit-shortcode-form .shortcake-attachment-preview-container.loading .loading-indicator {
    152164    display: block;
    153165    position: relative;
    154166    width: 100%;
    155167    height: 100%; }
    156   .edit-shortcode-form .shortcake-attachment-preview .loading-indicator .dashicons {
     168  .edit-shortcode-form .shortcake-attachment-preview-container .loading-indicator .dashicons {
    157169    font-size: 80px;
    158170    height: 100px;
     
    161173    text-align: center;
    162174    vertical-align: middle; }
    163   .edit-shortcode-form .shortcake-attachment-preview .loading-indicator .attachment-preview-loading {
     175  .edit-shortcode-form .shortcake-attachment-preview-container .loading-indicator .attachment-preview-loading {
    164176    width: 60px;
    165177    height: 5px;
     
    167179    background-color: transparent;
    168180    margin: -30px auto 0; }
    169     .edit-shortcode-form .shortcake-attachment-preview .loading-indicator .attachment-preview-loading ins {
     181    .edit-shortcode-form .shortcake-attachment-preview-container .loading-indicator .attachment-preview-loading ins {
    170182      background-color: #464646;
    171183      margin: 0 0 0 -60px;
     
    175187      -webkit-animation: attachment-preview-loading 1.3s infinite 1s linear;
    176188      animation: attachment-preview-loading 1.3s infinite 1s linear; }
    177   .edit-shortcode-form .shortcake-attachment-preview .filename {
     189  .edit-shortcode-form .shortcake-attachment-preview-container .filename {
    178190    line-height: 1.4em; }
    179   .edit-shortcode-form .shortcake-attachment-preview.has-attachment .button.add {
    180     display: none; }
    181   .edit-shortcode-form .shortcake-attachment-preview.has-attachment .button.remove {
    182     display: block; }
    183191
    184192.edit-shortcode-form .thumbnail-details-container {
     
    190198  0% {
    191199    margin-left: -60px; }
    192 
    193200  100% {
    194201    margin-left: 60px; } }
     
    197204  0% {
    198205    margin-left: -60px; }
    199 
    200206  100% {
    201207    margin-left: 60px; } }
     208
     209.edit-shortcode-form .select2-container {
     210  min-width: 300px; }
     211
     212.edit-shortcode-form .select2-container a {
     213  transition: none;
     214  -webkit-transition: none; }
     215
     216.edit-shortcode-form .select2-drop {
     217  z-index: 160001; }
     218
     219.edit-shortcode-form .select2 li {
     220  margin: 0; }
     221
     222.edit-shortcode-form .select2-selection__rendered {
     223  vertical-align: top; }
     224
     225.edit-shortcode-form .select2-container .select2-search--inline .select2-search__field {
     226  margin-top: 7px; }
     227
     228.edit-shortcode-form .select2-container--default .select2-selection--multiple {
     229  border-radius: 0;
     230  border-color: #ddd;
     231  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.07);
     232  background-color: #fff;
     233  color: #333;
     234  outline: none; }
     235
     236.edit-shortcode-form .select2-container--default.select2-container--focus .select2-selection--multiple {
     237  border-color: #5b9dd9;
     238  box-shadow: 0 0 2px rgba(30, 140, 190, 0.8); }
     239
     240.select2-container {
     241  z-index: 160000;
     242  max-width: 300px; }
     243
     244.select2-results li {
     245  margin: 0; }
    202246/*# sourceMappingURL=shortcode-ui.css.map */
  • shortcode-ui/trunk/css/shortcode-ui.css.map

    r1278066 r1536575  
    1 {"version":3,"sources":["../shortcode-ui.scss","../_field-image.scss","shortcode-ui.css"],"names":[],"mappings":"AAAA;EACC,mBAAA,EAAA;;AAKD;EACE,iBAAA;EACA,kBAAA;EACA,aAAA,EAAA;AAGF;EACE,UAAA,EAAA;;AAKF;EACC,gBAAA,EAAA;EAED;IACE,aAAA;IACA,YAAA;IAEA,kFAAA;IACA,iBAAA;IACA,gBAAA;IACA,mBAAA;IACA,mBAAA;IACA,aAAA;IACA,cAAA,EAAA;IAEF;MACG,mBAAA;MACA,cAAA;MACA,gBAAA,EAAA;MAEH;QAEI,mBAAA;QACA,SAAA;QACA,UAAA;QACA,yCAAA;YAAA,qCAAA;gBAAA,iCAAA;QACA,mBAAA;QACA,qBAAA;QACA,YAAA;QACA,aAAA;QACA,eAAA;QACA,gBAAA,EAAA;IAKJ;MACG,uBAAA;MACA,mBAAA;MACA,UAAA;MACA,QAAA;MACA,YAAA;MACA,UAAA;MACA,iBAAA;MACA,aAAA;MACA,iBAAA;MACA,iBAAA;MACA,sBAAA;MACA,mBAAA;MACA,kBAAA;MACA,qCAAA;MAEA,gDAAA,EAAA;;AAOH;EACE,aAAA;EACA,qBAAA,EAAA;AAGF;EACE,cAAA;EACA,2BAAA,EAAA;AAGF;EACE,8BAAA,EAAA;AAGF;EACE,mBAAA;EACA,aAAA,EAAA;;AAIF;EAEC,kBAAA,EAAA;EAED;IACE,eAAA;IACA,YAAA,EAAA;EAGF;IAEE,uBAAA;IAEA,gDAAA;IACA,uBAAA;IACA,YAAA;IACA,cAAA;IACA,mDAAA;IACA,2CAAA;IACA,gBAAA,EAAA;EAGF;IAEE,iBAAA,EAAA;EAGF;IACE,sBAAA;IACA,iBAAA;IACA,oBAAA,EAAA;EAGF;IACE,YAAA;IACA,gBAAA;IACA,kBAAA,EAAA;EAIF;IAAU,oBAAA,EAAA;EAGV;IACE,eAAA,EAAA;IACF;MACG,eAAA;MACA,oBAAA,EAAA;EAIH;IAIE,kBAAA,EAAA;IAHF;MACG,sBAAA,EAAA;EAKH;IACE,YAAA,EAAA;;AC5JF;EAEC,aAAA;EACA,cAAA;EACA,sBAAA;EACA,mBAAA;EACA,mBAAA;EACA,WAAA,EAAA;EAED;IACE,cAAA,EAAA;EAGF;IACE,+BAAA;IACA,mCAAA;YAAA,2BAAA,EAAA;EAGF;IACE,wBAAA;IACA,mBAAA;IACA,wBAAA;IACA,iBAAA,EAAA;EAGF;IACE,uBAAA;IACA,WAAA,EAAA;EAGF;IAEE,WAAA;IACA,cAAA;IACA,mBAAA;IACA,SAAA;IACA,WAAA;IACA,uBAAA;IACA,0CAAA;IACA,kBAAA;IACA,mBAAA;IACA,YAAA;IACA,aAAA;IACA,WAAA;IACA,iBAAA,EAAA;IAEF;MACG,iBAAA;MACA,mBAAA;MACA,UAAA;MACA,UAAA;MACA,gBAAA;MACA,eAAA,EAAA;EAIH;IAEE,cAAA,EAAA;EAGF;IACE,eAAA;IACA,mBAAA;IACA,YAAA;IACA,aAAA,EAAA;EAIF;IACG,gBAAA;IACA,cAAA;IACA,mBAAA;IACA,YAAA;IACA,mBAAA;IACA,uBAAA,EAAA;EAEH;IACG,YAAA;IACA,YAAA;IACA,iBAAA;IACA,8BAAA;IACA,qBAAA,EAAA;IAEH;MACI,0BAAA;MACA,oBAAA;MACA,YAAA;MACA,YAAA;MACA,eAAA;MACA,sEAAA;MACA,8DAAA,EAAA;EAKJ;IACE,mBAAA,EAAA;EAIF;IACG,cAAA,EAAA;EAEH;IACG,eAAA,EAAA;;AAMH;EACC,cAAA,EAAA;EAED;IACE,eAAA,EAAA;;AC0EF;EDrEA;IACE,mBAAA,EAAA;;EAEF;IACE,kBAAA,EAAA,EAAA;;ACwEF;EDnEA;IACE,mBAAA,EAAA;;EAEF;IACE,kBAAA,EAAA,EAAA","file":"shortcode-ui.css"}
     1{"version":3,"sources":["sass/shortcode-ui.scss","sass/_field-image.scss","sass/_select2-fields.scss"],"names":[],"mappings":"AAAA;EACC,mBAAmB,EACnB;;AAED;EAGE,iBAAiB;EACjB,kBAAkB;EAClB,aAAa,EACb;;AANF;EASE,UAAU,EACV;;AAIF;EACC,gBAAgB,EAuDhB;EAxDD;IAIE,aAAa;IACb,YAAY;IAEZ,kFAAqE;IACrE,iBAAiB;IACjB,gBAAgB;IAChB,mBAAmB;IACnB,mBAAmB;IACnB,aAAa;IACb,cAAc,EAyCd;IAtDF;MAgBG,mBAAmB;MACnB,cAAc;MACd,gBAAgB,EAgBhB;MAlCH;;QAsBI,mBAAmB;QACnB,SAAS;QACT,UAAU;QACV,yCAAoB;gBAApB,iCAAoB;QACpB,mBAAmB;QACnB,qBAAqB;QACrB,YAAY;QACZ,aAAa;QACb,eAAe;QACf,gBAAgB,EAChB;IAhCJ;MAqCG,uBAAuB;MACvB,mBAAmB;MACnB,UAAU;MACV,QAAQ;MACR,YAAY;MACZ,UAAU;MACV,iBAAiB;MACjB,aAAa;MACb,iBAAiB;MACjB,iBAAiB;MACjB,sBAAsB;MACtB,mBAAmB;MACnB,kBAAkB;MAClB,qCAAgB;MAEhB,gDAAgC,EAChC;;AAKH;EAEE,aAAa;EACb,qBAAqB,EACrB;;AAJF;EAOE,cAAc;EACd,2BAA2B,EAC3B;;AATF;EAYE,8BAA8B,EAC9B;;AAbF;EAgBE,mBAAmB;EACnB,aAAa,EACb;;AAGF;EAEC,kBAAkB,EA2DlB;EA7DD;IAKE,eAAe;IACf,YAAY,EACZ;EAPF;;IAWE,uBAAuB;IAEvB,gDAAgC;IAChC,uBAAuB;IACvB,YAAY;IACZ,cAAc;IACd,mDAAmD;IACnD,2CAA2C;IAC3C,gBAAgB,EAChB;EApBF;IAwBE,iBAAiB,EACjB;EAzBF;IA4BE,sBAAsB;IACtB,iBAAiB;IACjB,oBAAoB,EACpB;EA/BF;IAkCE,YAAY;IACZ,gBAAgB;IAChB,kBAAkB,EAClB;EArCF;IAwCU,oBAAoB,EAAI;EAxClC;IA4CE,eAAe,EAKf;IAjDF;MA8CG,eAAe;MACf,oBAAoB,EACpB;EAhDH;IAuDE,kBAAkB,EAClB;IAxDF;MAqDG,sBAAsB,EACtB;EAtDH;IA2DE,YAAY,EACZ;;AC7JF;EAGE,eAAe;EACf,YAAY;EACZ,oBAAoB,EACpB;;AANF;EASE,YAAY;EACZ,sBAAsB;EACtB,aAAa,EACb;;AAZF;EAeE,eAAe,EACf;;AAhBF;EAoBE,wBAAwB;EACxB,yBAAyB;EACzB,sBAAsB;EACtB,mBAAmB;EACnB,mBAAmB;EACnB,WAAW,EAmFX;EA5GF;IA4BG,cAAc,EACd;EA7BH;IAiCG,WAAW;IACX,eAAe;IACf,mBAAmB;IACnB,SAAS;IACT,WAAW;IACX,uBAAuB;IACvB,0CAA0B;IAC1B,kBAAkB;IAClB,mBAAmB;IACnB,YAAY;IACZ,aAAa;IACb,WAAW;IACX,iBAAgB,EAUhB;IAvDH;MAgDI,iBAAiB;MACjB,mBAAmB;MACnB,UAAU;MACV,UAAU;MACV,gBAAgB;MAChB,eAAe,EACf;EAtDJ;IA0DG,gBAAgB;IAChB,iBAAiB;IACjB,YAAY;IACZ,aAAa,EACb;EA9DH;;IAkEG,cAAc,EACd;EAnEH;IAsEG,eAAe;IACf,mBAAmB;IACnB,YAAY;IACZ,aAAa,EACb;EA1EH;IA8EI,gBAAgB;IAChB,cAAc;IACd,mBAAmB;IACnB,YAAY;IACZ,mBAAmB;IACnB,uBAAuB,EACvB;EApFJ;IAsFI,YAAY;IACZ,YAAY;IACZ,iBAAiB;IACjB,8BAA8B;IAC9B,qBAAqB,EAWrB;IArGJ;MA6FK,0BAA0B;MAC1B,oBAAoB;MACpB,YAAY;MACZ,YAAY;MACZ,eAAe;MACf,sEAAsE;MACtE,8DAA8D,EAC9D;EApGL;IAyGG,mBACA,EAAC;;AAMJ;EACC,cAAc,EAKd;EAND;IAIE,eAAe,EACf;;AAGF;EACC;IACC,mBAAmB,EAAA;EAEpB;IACC,kBAAkB,EAAA,EAAA;;AAIpB;EACC;IACC,mBAAmB,EAAA;EAEpB;IACC,kBAAkB,EAAA,EAAA;;ACtIpB;EAEE,iBAAiB,EACjB;;AAHF;EAME,iBAAiB;EACjB,yBAAyB,EACzB;;AARF;EAWE,gBAAgB,EAChB;;AAZF;EAeE,UAAU,EACV;;AAhBF;EAmBE,oBAAoB,EACpB;;AApBF;EAuBE,gBAAgB,EAChB;;AAxBF;EA2BE,iBAAiB;EACjB,mBAAmB;EACnB,gDAAgC;EAChC,uBAAuB;EACvB,YAAY;EACZ,cAAc,EACd;;AAjCF;EAoCE,sBAAsB;EACtB,4CAAwB,EACxB;;AAIF;EACC,gBAAgB;EAChB,iBAAiB,EACjB;;AAED;EACC,UAAU,EACV","file":"shortcode-ui.css"}
  • shortcode-ui/trunk/inc/class-shortcode-ui.php

    r1284972 r1536575  
    6868        add_action( 'admin_enqueue_scripts',     array( $this, 'action_admin_enqueue_scripts' ) );
    6969        add_action( 'wp_enqueue_editor',         array( $this, 'action_wp_enqueue_editor' ) );
     70        add_action( 'media_buttons',             array( $this, 'action_media_buttons' ) );
    7071        add_action( 'wp_ajax_bulk_do_shortcode', array( $this, 'handle_ajax_bulk_do_shortcode' ) );
    7172        add_filter( 'wp_editor_settings',        array( $this, 'filter_wp_editor_settings' ), 10, 2 );
     
    196197    public function action_admin_enqueue_scripts( $editor_supports ) {
    197198        add_editor_style( trailingslashit( $this->plugin_url ) . 'css/shortcode-ui-editor-styles.css' );
     199
     200        $min = '';
     201
     202        wp_register_script( 'select2',
     203            trailingslashit( $this->plugin_url ) . "lib/select2/js/select2{$min}.js",
     204            array( 'jquery', 'jquery-ui-sortable' ), '4.0.3'
     205        );
     206        wp_register_style( 'select2',
     207            trailingslashit( $this->plugin_url ) . 'lib/select2/css/select2.css',
     208            null, '4.0.3'
     209        );
    198210    }
    199211
     
    213225        if ( $current_post_type ) {
    214226            foreach ( $shortcodes as $key => $args ) {
    215                 if ( ! empty( $args['post_type'] ) && ! in_array( $current_post_type, $args['post_type'] ) ) {
     227                if ( ! empty( $args['post_type'] ) && ! in_array( $current_post_type, $args['post_type'], true ) ) {
    216228                    unset( $shortcodes[ $key ] );
    217229                }
     
    226238
    227239        // Load minified version of wp-js-hooks if not debugging.
    228         $wp_js_hooks_file = 'wp-js-hooks' . ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.min' : '' ) . '.js';
     240        $wp_js_hooks_file = 'wp-js-hooks' . ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ) . '.js';
    229241
    230242        wp_enqueue_script( 'shortcode-ui-js-hooks', $this->plugin_url . 'lib/wp-js-hooks/' . $wp_js_hooks_file, array(), '2015-03-19' );
     
    275287
    276288    /**
     289     * Output an "Add Post Element" button with the media buttons.
     290     */
     291    public function action_media_buttons( $editor_id ) {
     292        printf( '<button type="button" class="button shortcake-add-post-element" data-editor="%s">' .
     293            '<span class="wp-media-buttons-icon dashicons dashicons-migrate"></span> %s' .
     294            '</button>',
     295            esc_attr( $editor_id ),
     296            esc_html__( 'Add Post Element', 'shortcode-ui' )
     297        );
     298    }
     299
     300    /**
    277301     * Output required underscore.js templates in the footer
    278302     */
    279303    public function action_admin_print_footer_scripts() {
     304
    280305        echo $this->get_view( 'media-frame' ); // WPCS: xss ok
    281306        echo $this->get_view( 'list-item' ); // WPCS: xss ok
  • shortcode-ui/trunk/inc/fields/class-field-attachment.php

    r1278066 r1536575  
    9393            <div class="field-block shortcode-ui-field-attachment shortcode-ui-attribute-{{ data.attr }}">
    9494                <label for="{{ data.attr }}">{{{ data.label }}}</label>
    95                 <div class="shortcake-attachment-preview attachment-preview attachment">
    96                     <button id="{{ data.attr }}" class="button button-small add">{{ data.addButton }}</button>
    97                     <button class="button button-small remove">&times;</button>
    98                     <div class="loading-indicator">
    99                         <span class="dashicons dashicons-format-image"></span>
    100                         <div class="attachment-preview-loading"><ins></ins></div>
    101                     </div>
    102                 </div>
    103                 <div class="thumbnail-details-container">
    104                     <strong><?php esc_html_e( 'Thumbnail Details', 'shortcode-ui' ); ?></strong>
    105                     <div class="filename"></div>
    106                     <div class="date-formatted"></div>
    107                     <div class="size"></div>
    108                     <div class="dimensions"></div>
    109                     <div class="edit-link"><a href="#"><?php esc_html_e( 'Edit Attachment', 'shortcode-ui' ); ?></a></div>
    110                 </div>
    11195                <# if ( typeof data.description == 'string' ) { #>
    11296                    <p class="description">{{{ data.description }}}</p>
    11397                <# } #>
     98                <button id="{{ data.attr }}" class="shortcake-attachment-select button button-small add">{{ data.addButton }}</button>
     99                <div class="attachment-previews"></div>
     100            </div>
     101        </script>
     102
     103        <script type="text/html" id="tmpl-shortcake-image-preview">
     104            <div class="shortcake-attachment-preview">
     105                <div class="shortcake-attachment-preview-container attachment-preview attachment <# if ( data.type === 'image' && ! data.sizes ) { #>loading<# } #>">
     106
     107                    <button class="button button-small remove" data-id="{{ data.id }}">×</button>
     108
     109                    <# if ( data.type === 'image' && data.sizes && data.sizes.thumbnail ) { #>
     110                        <div class="thumbnail">
     111                            <div class="centered">
     112                                <img src="{{ data.sizes.thumbnail.url }}" alt="" width="{{ data.sizes.thumbnail.width }}" height="{{ data.sizes.thumbnail.height }}" />
     113                            </div>
     114                        </div>
     115                    <# } else if ( data.type === 'image' && ( ! data.sizes || ! data.sizes.thumbnail ) ) { #>
     116                        <div class="thumbnail">
     117                            <div class="centered">
     118                                <img src="{{ data.url }}" alt="" width="{{ data.width }}" height="{{ data.height }}" />
     119                            </div>
     120                        </div>
     121                    <# } else if ( data.type !== 'image' ) { #>
     122                        <div class="thumbnail">
     123                            <div class="centered">
     124                                <img src="{{ data.icon }}" />
     125                            </div>
     126                            <div class="filename"><div>{{ data.filename }}</div></div>
     127                        </div>
     128                    <# } else { #>
     129                        <div class="loading-indicator">
     130                            <span class="dashicons dashicons-format-image"></span>
     131                            <div class="attachment-preview-loading"><ins></ins></div>
     132                        </div>
     133                    <# } #>
     134
     135                </div>
     136
     137                <div class="thumbnail-details-container has-attachment">
     138                    <strong>Thumbnail Details</strong>
     139                    <div class="filename">{{ data.filename }}</div>
     140                    <div class="date-formatted">{{ data.dateFormatted }}</div>
     141                    <div class="size">{{ data.filesizeHumanReadable }}</div>
     142                    <# if ( data.type === 'image' ) { #>
     143                        <div class="dimensions">{{ data.width }} &times; {{ data.height }}</div>
     144                    <# } #>
     145                    <div class="edit-link"><a href="{{ data.editLink }}">Edit Attachment</a></div>
     146                </div>
    114147            </div>
    115148        </script>
  • shortcode-ui/trunk/inc/fields/class-field-color.php

    r1278066 r1536575  
    113113                <label for="{{ data.attr }}">{{{ data.label }}}</label>
    114114                <input type="text" name="{{ data.attr }}" id="{{ data.attr }}" value="{{ data.value }}" data-default-color="{{ data.value }}" {{{ data.meta }}}/>
    115                 <# if ( typeof data.description == 'string' ) { #>
     115                <# if ( typeof data.description == 'string' && data.description.length ) { #>
    116116                    <p class="description">{{{ data.description }}}</p>
    117117                <# } #>
  • shortcode-ui/trunk/inc/fields/class-field-post-select.php

    r1281670 r1536575  
    3939    public function action_enqueue_shortcode_ui() {
    4040
    41         $plugin_dir = dirname( dirname( __FILE__ ) );
    42 
    43         wp_enqueue_script( 'select2', plugins_url( 'lib/select2/select2.min.js', $plugin_dir ) , array( 'jquery', 'jquery-ui-sortable' ), '3.5.2' );
    44         wp_enqueue_style( 'select2', plugins_url( 'lib/select2/select2.css', $plugin_dir ), null, '3.5.2' );
     41        wp_enqueue_script( 'select2' );
     42        wp_enqueue_style( 'select2' );
    4543
    4644        wp_localize_script( 'shortcode-ui', 'shortcodeUiPostFieldData', array(
     
    5755        ?>
    5856
    59         <style>
    60 
    61             .edit-shortcode-form .select2-container {
    62                 min-width: 300px;
    63             }
    64 
    65             .edit-shortcode-form .select2-container a {
    66                 transition: none;
    67                 -webkit-transition: none;
    68             }
    69 
    70             .wp-admin .select2-drop {
    71                 z-index: 160001;
    72             }
    73 
    74         </style>
    75 
    7657        <script type="text/html" id="tmpl-shortcode-ui-field-post-select">
    7758            <div class="field-block shortcode-ui-field-post-select shortcode-ui-attribute-{{ data.attr }}">
    7859                <label for="{{ data.id }}">{{{ data.label }}}</label>
    79                 <input type="text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" class="shortcode-ui-post-select" />
    80                 <# if ( typeof data.description == 'string' ) { #>
     60                <select id="{{ data.id }}" name="{{ data.name }}" class="shortcode-ui-post-select" ></select>
     61                <# if ( typeof data.description == 'string' && data.description.length ) { #>
    8162                    <p class="description">{{{ data.description }}}</p>
    8263                <# } #>
     
    10182        $requested_shortcode = isset( $_GET['shortcode'] ) ? sanitize_text_field( $_GET['shortcode'] ) : null;
    10283        $requested_attr      = isset( $_GET['attr'] ) ? sanitize_text_field( $_GET['attr'] ) : null;
    103         $response            = array( 'posts' => array(), 'found_posts' => 0, 'posts_per_page' => 0 );
     84        $response            = array( 'items' => array(), 'found_items' => 0, 'items_per_page' => 0 );
    10485
    10586        $shortcodes = Shortcode_UI::get_instance()->get_shortcodes();
     
    139120        }
    140121
    141         if ( ! empty( $_GET['post__in'] ) ) {
    142             $post__in = is_array( $_GET['post__in'] ) ? $_GET['post__in'] : explode( ',', $_GET['post__in'] );
     122        if ( ! empty( $_GET['include'] ) ) {
     123            $post__in = is_array( $_GET['include'] ) ? $_GET['include'] : explode( ',', $_GET['include'] );
    143124            $query_args['post__in'] = array_map( 'intval', $post__in );
    144125            $query_args['orderby']  = 'post__in';
     
    149130
    150131        foreach ( $query->posts as $post_id ) {
    151             array_push( $response['posts'], array( 'id' => $post_id, 'text' => html_entity_decode( get_the_title( $post_id ) ) ) );
     132            array_push( $response['items'], array( 'id' => $post_id, 'text' => html_entity_decode( get_the_title( $post_id ) ) ) );
    152133        }
    153134
    154         $response['found_posts']    = $query->found_posts;
    155         $response['posts_per_page'] = $query->query_vars['posts_per_page'];
     135        $response['found_items']    = $query->found_posts;
     136        $response['items_per_page'] = $query->query_vars['posts_per_page'];
    156137
    157138        wp_send_json_success( $response );
  • shortcode-ui/trunk/inc/templates/edit-form.tpl.php

    r1278066 r1536575  
    2020        <label for="{{ data.id }}">{{{ data.label }}}</label>
    2121        <input type="text" class="regular-text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" {{{ data.meta }}}/>
    22         <# if ( typeof data.description == 'string' ) { #>
     22        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    2323            <p class="description">{{{ data.description }}}</p>
    2424        <# } #>
     
    3030        <label for="{{ data.id }}">{{{ data.label }}}</label>
    3131        <input type="url" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" class="code" {{{ data.meta }}}/>
    32         <# if ( typeof data.description == 'string' ) { #>
     32        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    3333            <p class="description">{{{ data.description }}}</p>
    3434        <# } #>
     
    4040        <label for="{{ data.id }}">{{{ data.label }}}</label>
    4141        <textarea name="{{ data.attr }}" id="{{ data.id }}" {{{ data.meta }}}>{{ data.value }}</textarea>
    42         <# if ( typeof data.description == 'string' ) { #>
     42        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    4343            <p class="description">{{{ data.description }}}</p>
    4444        <# } #>
     
    5050        <label for="{{ data.id }}">{{{ data.label }}}</label>
    5151        <select name="{{ data.attr }}" id="{{ data.id }}" {{{ data.meta }}}>
    52             <# _.each( data.options, function( label, value ) { #>
    53                 <option value="{{ value }}" <# if ( value == data.value ){ print('selected'); } #>>{{ label }}</option>
     52            <# _.each( data.options, function( option ) { #>
     53
     54                <# if ( 'options' in option && 'label' in option ) { #>
     55                    <optgroup label="{{ option.label }}">
     56                        <# _.each( option.options, function( optgroupOption ) { #>
     57                            <option value="{{ optgroupOption.value }}" <# if ( optgroupOption.value === data.value ){ print('selected'); } #>>{{ optgroupOption.label }}</option>
     58                        <# }); #>
     59                    </optgroup>
     60                <# } else { #>
     61                    <option value="{{ option.value }}" <# if ( option.value === data.value ){ print('selected'); } #>>{{ option.label }}</option>
     62                <# } #>
     63
    5464            <# }); #>
    5565        </select>
    56         <# if ( typeof data.description == 'string' ) { #>
     66        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    5767            <p class="description">{{{ data.description }}}</p>
    5868        <# } #>
     
    6373    <div class="field-block shortcode-ui-field-radio shortcode-ui-attribute-{{ data.attr }}">
    6474        <label>{{{ data.label }}}</label>
    65         <# _.each( data.options, function( label, value ) { #>
     75        <# _.each( data.options, function( option ) { #>
    6676            <label>
    67                 <input type="radio" name="{{ data.attr }}" value="{{ value }}" <# if ( value == data.value ) { print('checked'); } #> />
    68                 {{ label }}
     77                <input type="radio" name="{{ data.attr }}" value="{{ option.value }}" <# if ( option.value == data.value ) { print('checked'); } #> />
     78                {{ option.label }}
    6979            </label>
    7080        <# }); #>
    71         <# if ( typeof data.description == 'string' ) { #>
     81        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    7282            <p class="description">{{{ data.description }}}</p>
    7383        <# } #>
     
    8191            {{{ data.label }}}
    8292        </label>
    83         <# if ( typeof data.description == 'string' ) { #>
     93        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    8494            <p class="description">{{{ data.description }}}</p>
    8595        <# } #>
     
    91101        <label for="{{ data.id }}">{{{ data.label }}}</label>
    92102        <input type="email" class="regular-text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value}}" {{{ data.meta }}}/>
    93         <# if ( typeof data.description == 'string' ) { #>
     103        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    94104            <p class="description">{{{ data.description }}}</p>
    95105        <# } #>
     
    101111        <label for="{{ data.id }}">{{{ data.label }}}</label>
    102112        <input type="number" class="regular-text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value}}" {{{ data.meta }}}/>
    103         <# if ( typeof data.description == 'string' ) { #>
     113        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    104114            <p class="description">{{{ data.description }}}</p>
    105115        <# } #>
     
    111121        <label for="{{ data.id }}">{{{ data.label }}}</label>
    112122        <input type="hidden" name="{{ data.attr }}" id="{{ data.id }}" value="true" {{{ data.meta }}}/>
    113         <# if ( typeof data.description == 'string' ) { #>
     123        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    114124            <p class="description">{{{ data.description }}}</p>
    115125        <# } #>
     
    121131        <label for="{{ data.id }}">{{{ data.label }}}</label>
    122132        <input type="date" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" {{{ data.meta }}}/>
    123         <# if ( typeof data.description == 'string' ) { #>
     133        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    124134            <p class="description">{{{ data.description }}}</p>
    125135        <# } #>
     
    131141        <label for="inner_content">{{{ data.label }}}</label>
    132142        <textarea id="inner_content" name="inner_content" class="content-edit" {{{ data.meta }}}>{{ data.value }}</textarea>
    133         <# if ( typeof data.description == 'string' ) { #>
     143        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    134144            <p class="description">{{{ data.description }}}</p>
    135145        <# } #>
     
    144154            <output class="range" for="{{ data.id }}" id="{{ data.id }}_indicator">{{ data.value }}</output>
    145155        </div>
    146         <# if ( typeof data.description == 'string' ) { #>
     156        <# if ( typeof data.description == 'string' && data.description.length ) { #>
    147157            <p class="description">{{{ data.description }}}</p>
    148158        <# } #>
  • shortcode-ui/trunk/js/build/shortcode-ui.js

    r1284972 r1536575  
    6464        var pattern = new RegExp( searchTerm, "gi" );
    6565        var filteredModels = sui.shortcodes.filter( function( model ) {
     66            pattern.lastIndex = 0;
    6667            return pattern.test( model.get( "label" ) );
    6768        });
     
    211212            // Encode textareas incase HTML
    212213            if ( attr.get( 'encode' ) ) {
    213                 attr.set( 'value', encodeURIComponent( decodeURIComponent( attr.get( 'value' ) ) ), { silent: true } );
     214                attr.set( 'value', encodeURIComponent( decodeURIComponent( attr.get( 'value' ).replace( "%", "&#37;" ) ) ), { silent: true } );
    214215            }
    215216
     
    229230
    230231        if ( attrs.length > 0 ) {
    231             template = "[{{ shortcode }} {{ attributes }}]";
     232            template = "[{{ shortcode }} {{ attributes }}";
    232233        } else {
    233             template = "[{{ shortcode }}]";
     234            template = "[{{ shortcode }}";
    234235        }
    235236
    236237        if ( content && content.length > 0 ) {
    237             template += "{{ content }}[/{{ shortcode }}]";
     238            template += "]{{ content }}[/{{ shortcode }}]";
     239        } else {
     240            // add closing slash to shortcodes without content
     241            template += "/]";
    238242        }
    239243
     
    271275            wp.mce.views.register(
    272276                shortcode.get('shortcode_tag'),
    273                 // Must extend for 4.1.
    274                 // This is handled by wp.mce.views.register in 4.2.
    275                 $.extend( true, {}, shortcodeViewConstructor )
     277                shortcodeViewConstructor
    276278            );
    277279        }
    278280    } );
    279281
     282    $(document.body).on( 'click', '.shortcake-add-post-element', function( event ) {
     283        var elem = $( event.currentTarget ),
     284            editor = elem.data('editor'),
     285            options = {
     286                frame: 'post',
     287                state: 'shortcode-ui',
     288                title: shortcodeUIData.strings.media_frame_title
     289            };
     290
     291        event.preventDefault();
     292
     293        // Remove focus from the `.shortcake-add-post-element` button.
     294        // Prevents Opera from showing the outline of the button above the modal.
     295        //
     296        // See: https://core.trac.wordpress.org/ticket/22445
     297        elem.blur();
     298
     299        wp.media.editor.remove( editor );
     300        wp.media.editor.open( editor, options );
     301    } );
     302
    280303});
    281304
    282305}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    283 },{"./collections/shortcodes.js":2,"./utils/shortcode-view-constructor.js":9,"./utils/sui.js":10,"./views/media-frame.js":18}],8:[function(require,module,exports){
     306},{"./collections/shortcodes.js":2,"./utils/shortcode-view-constructor.js":9,"./utils/sui.js":10,"./views/media-frame.js":20}],8:[function(require,module,exports){
    284307(function (global){
    285308var $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
     
    366389        }
    367390
    368         var request = $.post( ajaxurl + '?action=bulk_do_shortcode', {
    369                 queries: _.pluck( fetcher.queries, 'query' )
    370             }
    371         );
    372 
    373         request.done( function( response ) {
    374             _.each( response.data, function( result, index ) {
     391        var request = wp.ajax.post( 'bulk_do_shortcode', {
     392            queries: _.pluck( fetcher.queries, 'query' )
     393        });
     394
     395        request.done( function( responseData ) {
     396            _.each( responseData, function( result, index ) {
    375397                var matchedQuery = _.findWhere( fetcher.queries, {
    376398                    counter: parseInt( index ),
     
    484506            if ( attr && attr.get('encode') ) {
    485507                value = decodeURIComponent( value );
     508                value = value.replace( "&#37;", "%" );
    486509            }
    487510
     
    560583     */
    561584    edit: function( shortcodeString ) {
    562         var currentShortcode;
    563 
    564         // Backwards compatability for WP pre-4.2
    565         if ( 'object' === typeof( shortcodeString ) ) {
    566             shortcodeString = decodeURIComponent( $(shortcodeString).attr('data-wpview-text') );
    567         }
    568 
    569         currentShortcode = this.parseShortcodeString( shortcodeString );
     585
     586        var currentShortcode = this.parseShortcodeString( shortcodeString );
    570587
    571588        if ( currentShortcode ) {
     
    579596            wp_media_frame.open();
    580597
     598            /* Trigger render_edit */
     599            /*
     600             * Action run after an edit shortcode overlay is rendered.
     601             *
     602             * Called as `shortcode-ui.render_edit`.
     603             *
     604             * @param shortcodeModel (object)
     605             *           Reference to the shortcode model used in this overlay.
     606             */
     607            var hookName = 'shortcode-ui.render_edit';
     608            var shortcodeModel = this.shortcodeModel;
     609            wp.shortcake.hooks.doAction( hookName, shortcodeModel );
     610
    581611        }
    582612
     
    599629        var shortcode_tags = _.map( sui.shortcodes.pluck( 'shortcode_tag' ), this.pregQuote ).join( '|' );
    600630        var regexp = wp.shortcode.regexp( shortcode_tags );
     631        regexp.lastIndex = 0;
    601632        var matches = regexp.exec( shortcodeString );
    602633
     
    651682    },
    652683
    653     // Backwards compatability for Pre WP 4.2.
    654     View: {
    655 
    656         overlay: true,
    657 
    658         initialize: function( options ) {
    659             this.shortcode = this.getShortcode( options );
    660             this.fetch();
    661         },
    662 
    663         getShortcode: function( options ) {
    664 
    665             var shortcodeModel, shortcode;
    666 
    667             shortcodeModel = sui.shortcodes.findWhere( { shortcode_tag: options.shortcode.tag } );
    668 
    669             if (!shortcodeModel) {
    670                 return;
    671             }
    672 
    673             shortcode = shortcodeModel.clone();
    674 
    675             shortcode.get('attrs').each(
    676                     function(attr) {
    677 
    678                         if (attr.get('attr') in options.shortcode.attrs.named) {
    679                             attr.set('value',
    680                                     options.shortcode.attrs.named[attr
    681                                             .get('attr')]);
    682                         }
    683 
    684                     });
    685 
    686             if ('content' in options.shortcode) {
    687                 var inner_content = shortcode.get('inner_content');
    688                 if ( inner_content ) {
    689                     inner_content.set('value', options.shortcode.content);
    690                 }
    691             }
    692 
    693             return shortcode;
    694 
    695         },
    696 
    697         fetch : function() {
    698 
    699             var self = this;
    700 
    701             if ( ! this.parsed ) {
    702 
    703                 wp.ajax.post( 'do_shortcode', {
    704                     post_id: $( '#post_ID' ).val(),
    705                     shortcode: this.shortcode.formatShortcode(),
    706                     nonce: shortcodeUIData.nonces.preview,
    707                 }).done( function( response ) {
    708                     if ( response.indexOf( '<script' ) !== -1 ) {
    709                         self.setIframes( self.getEditorStyles(), response );
    710                     } else {
    711                         self.parsed = response;
    712                         self.render( true );
    713                     }
    714                 }).fail( function() {
    715                     self.parsed = '<span class="shortcake-error">' + shortcodeUIData.strings.mce_view_error + '</span>';
    716                     self.render( true );
    717                 } );
    718 
    719             }
    720 
    721         },
    722 
    723         /**
    724          * Render the shortcode
    725          *
    726          * To ensure consistent rendering - this makes an ajax request to the
    727          * admin and displays.
    728          *
    729          * @return string html
    730          */
    731         getHtml : function() {
    732             return this.parsed;
    733         },
    734 
    735         /**
    736          * Returns an array of <link> tags for stylesheets applied to the TinyMCE editor.
    737          *
    738          * @method getEditorStyles
    739          * @returns {Array}
    740          */
    741         getEditorStyles: function() {
    742 
    743             var styles = '';
    744 
    745             this.getNodes( function ( editor, node, content ) {
    746                 var dom = editor.dom,
    747                     bodyClasses = editor.getBody().className || '',
    748                     iframe, iframeDoc, i, resize;
    749 
    750                 tinymce.each( dom.$( 'link[rel="stylesheet"]', editor.getDoc().head ), function( link ) {
    751                     if ( link.href && link.href.indexOf( 'skins/lightgray/content.min.css' ) === -1 &&
    752                         link.href.indexOf( 'skins/wordpress/wp-content.css' ) === -1 ) {
    753 
    754                         styles += dom.getOuterHTML( link ) + '\n';
    755                     }
    756 
    757                 });
    758 
    759             } );
    760 
    761             return styles;
    762         },
    763 
    764     },
    765684};
    766685
     
    781700
    782701},{"./../collections/shortcodes.js":2}],11:[function(require,module,exports){
     702(function (global){
    783703var sui = require('./../utils/sui.js');
     704var $   = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
    784705
    785706var editAttributeFieldAttachment = sui.views.editAttributeField.extend( {
     707
     708    previewTemplate: wp.template( 'shortcake-image-preview' ),
    786709
    787710    events: {
     
    792715    },
    793716
     717    currentSelection: [],
     718
     719    initialize: function() {
     720
     721        var self = this;
     722
     723        _.bindAll( self, 'updateValue', 'initSelection', '_renderPreview', '_renderAll', '_removeAttachment' );
     724
     725        self.initSelection();
     726
     727        self.currentSelection.on( 'all', this.updateValue );
     728        self.currentSelection.on( 'add', this._renderPreview );
     729        self.currentSelection.on( 'reset', this._renderAll );
     730
     731    },
     732
     733    /**
     734     * Initialize Selection.
     735     *
     736     * Selection is an Attachment collection containing full models for the current value.
     737     *
     738     * @return null
     739     */
     740    initSelection: function() {
     741
     742        this.currentSelection = new wp.media.model.Selection( [], {
     743            multiple: this.model.get( 'multiple' ) ? true : false,
     744        } );
     745
     746        // Initialize selection.
     747        _.each( this.getValue(), function( item ) {
     748
     749            var model;
     750
     751            // Legacy. Handle storing full objects.
     752            item  = ( 'object' === typeof( item ) ) ? item.id : item;
     753            model = new wp.media.attachment( item );
     754
     755            this.currentSelection.add( model );
     756
     757            // Re-render after attachments have synced.
     758            model.fetch();
     759            model.on( 'sync', this._renderAll );
     760
     761        }.bind(this) );
     762
     763    },
     764
    794765    /**
    795766     * Update the field attachment.
     
    799770     * @param {int} id Attachment ID
    800771     */
    801     updateValue: function( id ) {
    802 
    803         if ( ! id ) {
    804             return;
    805         }
    806 
    807         this.setValue( id );
    808 
    809         var self = this;
    810 
    811         if ( editAttributeFieldAttachment.getFromCache( id ) ) {
    812             self._renderPreview( editAttributeFieldAttachment.getFromCache( id ) );
    813 
    814             // Call the updateValue() function, to trigger any listeners
    815             // hooked on it.
    816             self.triggerCallbacks();
    817             return;
    818         }
    819 
    820         this.$container.addClass( 'loading' );
    821 
    822         wp.ajax.post( 'get-attachment', {
    823             'id': id
    824         } ).done( function( attachment ) {
    825             // Cache for later.
    826             editAttributeFieldAttachment.setInCache( id, attachment );
    827             self._renderPreview( attachment );
    828 
    829             // Call the updateValue() function, to trigger any listeners
    830             // hooked on it.
    831             self.triggerCallbacks();
    832         } ).always( function( attachment ) {
    833             self.$container.removeClass( 'loading' );
    834         });
     772    updateValue: function() {
     773        var value = this.currentSelection.pluck( 'id' );
     774        this.setValue( value );
     775        this.triggerCallbacks();
    835776    },
    836777
     
    846787        this.$el.html( this.template( this.model.toJSON() ) );
    847788
    848         this.$container   = this.$el.find( '.shortcake-attachment-preview' );
     789        this.$container = this.$el.find( '.attachment-previews' );
    849790        this.$thumbnailDetailsContainer   = this.$el.find( '.thumbnail-details-container' );
    850         var $addButton    = this.$container.find( 'button.add' );
     791        var $addButton = this.$container.find( 'button.add' );
    851792
    852793        this.frame = wp.media( {
    853             multiple: false,
    854             title: this.model.get( 'frameTitle' ),
     794            multiple: this.model.get( 'multiple' ) ? true : false,
     795            title:    this.model.get( 'frameTitle' ),
    855796            library: {
    856797                type: this.model.get( 'libraryType' ),
     
    858799        } );
    859800
    860         // Add initial Attachment if available.
    861         this.updateValue( this.model.get( 'value' ) );
     801        this.frame.on( 'select', function() {
     802            this.$el.trigger( 'selectAttachment' );
     803        }.bind( this ) );
     804
     805        this._renderAll();
     806
     807    },
     808
     809    _renderAll: function() {
     810
     811        // Empty container.
     812        this.$container.html('');
     813
     814        // Render each attachment in current selection.
     815        this.currentSelection.each( function( attachment ) {
     816            this._renderPreview( attachment );
     817        }.bind(this) );
    862818
    863819    },
     
    870826    _renderPreview: function( attachment ) {
    871827
    872         var $thumbnail = jQuery('<div class="thumbnail"></div>');
    873 
    874         if ( 'image' !== attachment.type ) {
    875 
    876             jQuery( '<img/>', {
    877                 src: attachment.icon,
    878                 alt: attachment.title,
    879             } ).appendTo( $thumbnail );
    880 
    881             jQuery( '<div/>', {
    882                 class: 'filename',
    883                 html:  '<div>' + attachment.title + '</div>',
    884             } ).appendTo( $thumbnail );
    885 
    886         } else {
    887 
    888             attachmentThumb = (typeof attachment.sizes.thumbnail !== 'undefined') ?
    889                 attachment.sizes.thumbnail :
    890                 _.first( _.sortBy( attachment.sizes, 'width' ) );
    891 
    892             jQuery( '<img/>', {
    893                 src:    attachmentThumb.url,
    894                 width:  attachmentThumb.width,
    895                 height: attachmentThumb.height,
    896                 alt:    attachment.alt,
    897             } ) .appendTo( $thumbnail );
    898 
    899         }
    900 
    901         $thumbnail.find( 'img' ).wrap( '<div class="centered"></div>' );
    902         this.$container.append( $thumbnail );
    903         this.$container.toggleClass( 'has-attachment', true );
    904 
    905         this.$thumbnailDetailsContainer.find( '.filename' ).text( attachment.filename );
    906         this.$thumbnailDetailsContainer.find( '.date-formatted' ).text( attachment.dateFormatted );
    907         this.$thumbnailDetailsContainer.find( '.size' ).text( attachment.filesizeHumanReadable );
    908         this.$thumbnailDetailsContainer.find( '.dimensions' ).text( attachment.height + ' × ' + attachment.width );
    909         this.$thumbnailDetailsContainer.find( '.edit-link a' ).attr( "href", attachment.editLink );
    910         this.$thumbnailDetailsContainer.toggleClass( 'has-attachment', true );
     828        var $thumbnail = $( this.previewTemplate( attachment.toJSON() ) );
     829
     830        $thumbnail.appendTo( this.$container );
     831
     832        attachment.on( 'remove', function() {
     833            $thumbnail.remove();
     834        } );
     835
     836    },
     837
     838    getValue: function() {
     839
     840        var value = this.model.get( 'value' );
     841
     842        if ( ! ( value instanceof Array ) ) {
     843            value = value.split( ',' );
     844        }
     845
     846        value = value.map( function( id ) {
     847            return parseInt( id, 10 );
     848        } );
     849
     850        value = value.filter( function( id ) {
     851            return id > 0;
     852        } );
     853
     854        value.sort( function( a, b ) {
     855            return a < b;
     856        } );
     857
     858        return value;
    911859
    912860    },
     
    917865     */
    918866    _openMediaFrame: function(e) {
     867
    919868        e.preventDefault();
    920869        this.frame.open();
    921         if ( this.model.get( 'value' ) ) {
    922             var selection = this.frame.state().get('selection');
    923             attachment = wp.media.attachment( this.model.get( 'value' ) );
    924             attachment.fetch();
    925             selection.reset( attachment ? [ attachment ] : [] );
    926             this.frame.state().set('selection', selection);
    927         }
    928 
    929         var self = this;
    930         this.frame.on( 'select', function() {
    931             self.$el.trigger( 'selectAttachment'  );
    932         } );
     870
     871        var selection = this.frame.state().get('selection');
     872        selection.reset( this.currentSelection.models );
     873        this.frame.state('library').set( 'selection', selection );
    933874
    934875    },
     
    939880     */
    940881    _selectAttachment: function(e) {
     882
    941883        var selection  = this.frame.state().get('selection');
    942             attachment = selection.first();
    943         if ( attachment.id != this.model.get( 'value' ) ){
    944             this.model.set( 'value', null );
    945             this.$container.toggleClass( 'has-attachment', false );
    946             this.$container.find( '.thumbnail' ).remove();
    947             this.updateValue( attachment.id );
    948         }
     884        this.currentSelection.reset( selection.toJSON() );
     885
    949886        this.frame.close();
     887
    950888    },
    951889
     
    955893     */
    956894    _removeAttachment: function(e) {
     895
    957896        e.preventDefault();
    958897
    959         this.model.set( 'value', null );
    960 
    961         this.$container.toggleClass( 'has-attachment', false );
    962         this.$container.find( '.thumbnail' ).remove();
    963         this.$thumbnailDetailsContainer.toggleClass( 'has-attachment', false );
    964     },
    965 
    966 }, {
    967 
    968     _idCache: {},
    969 
    970     /**
    971      * Store attachments in a cache for quicker loading.
    972      */
    973     setInCache: function( id, attachment ) {
    974         this._idCache[ id ] = attachment;
    975     },
    976 
    977     /**
    978      * Retrieve an attachment from the cache.
    979      */
    980     getFromCache: function( id ){
    981         if ( 'undefined' === typeof this._idCache[ id ] ) {
    982             return false;
    983         }
    984         return this._idCache[ id ];
     898        var id = $( e.target ).attr( 'data-id' );
     899
     900        if ( ! id ) {
     901            return;
     902        }
     903
     904        var target = this.currentSelection.get( id );
     905
     906        if ( target ) {
     907            this.currentSelection.remove( target );
     908        }
     909
    985910    },
    986911
     
    990915
    991916
     917}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    992918},{"./../utils/sui.js":10}],12:[function(require,module,exports){
    993919(function (global){
     
    1048974
    1049975}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    1050 },{"./../utils/sui.js":10,"./edit-attribute-field.js":14}],13:[function(require,module,exports){
    1051 ( function( $ ) {
    1052 
    1053     var sui = window.Shortcode_UI;
    1054 
    1055     // Cached Data.
    1056     var postSelectCache = {};
    1057 
    1058     sui.views.editAttributeFieldPostSelect = sui.views.editAttributeField.extend( {
    1059 
    1060         events: {
    1061             'change .shortcode-ui-post-select': 'inputChanged',
    1062         },
    1063 
    1064         inputChanged: function(e) {
    1065             this.setValue( e.val );
    1066             this.triggerCallbacks();
    1067         },
    1068 
    1069         render: function() {
    1070 
    1071             var self = this,
    1072                 defaults = { multiple: false };
    1073 
    1074             for ( var arg in defaults ) {
    1075                 if ( ! this.model.get( arg ) ) {
    1076                     this.model.set( arg, defaults[ arg ] );
    1077                 }
    1078             }
    1079 
    1080             var data = this.model.toJSON();
    1081             data.id = 'shortcode-ui-' + this.model.get( 'attr' ) + '-' + this.model.cid;
    1082 
    1083             this.$el.html( this.template( data ) );
    1084 
    1085             var ajaxData = {
    1086                 action    : 'shortcode_ui_post_field',
    1087                 nonce     : shortcodeUiPostFieldData.nonce,
    1088                 shortcode : this.shortcode.get( 'shortcode_tag'),
    1089                 attr      : this.model.get( 'attr' )
    1090             };
    1091 
    1092             var $field = this.$el.find( '.shortcode-ui-post-select' );
    1093 
    1094             $field.select2({
    1095 
    1096                 placeholder: "Search",
    1097                 multiple: this.model.get( 'multiple' ),
    1098                 ajax: {
    1099                     url: ajaxurl,
    1100                     dataType: 'json',
    1101                     quietMillis: 250,
    1102                     data: function (term, page) {
    1103                         ajaxData.s    = term;
    1104                         ajaxData.page = page;
    1105                         return ajaxData;
    1106                     },
    1107                     results: function ( response, page ) {
    1108 
    1109                         if ( ! response.success ) {
    1110                             return { results: {}, more: false };
    1111                         }
    1112 
    1113                         // Cache data for quicker rendering later.
    1114                         postSelectCache = $.extend( postSelectCache, response.data.posts );
    1115 
    1116                         var more = ( page * response.data.posts_per_page ) < response.data.found_posts; // whether or not there are more results available
    1117                         return { results: response.data.posts, more: more };
    1118 
    1119                     },
    1120                 },
    1121 
    1122                 /**
    1123                  * Initialize Callback
    1124                  * Used to set render the initial value.
    1125                  * Has to make a request to get the title for the current ID.
    1126                  */
    1127                 initSelection: function(element, callback) {
    1128 
    1129                     var ids, parsedData = [], cached;
    1130 
    1131                     // Convert stored value to array of IDs (int).
    1132                     ids = $(element)
    1133                         .val()
    1134                         .split(',')
    1135                         .map( function (str) { return str.trim(); } )
    1136                         .map( function (str) { return parseInt( str ); } );
    1137 
    1138                     if ( ids.length < 1 ) {
    1139                         return;
    1140                     }
    1141 
    1142                     // Check if there is already cached data.
    1143                     for ( var i = 0; i < ids.length; i++ ) {
    1144                         cached = _.find( postSelectCache, _.matches( { id: ids[i] } ) );
    1145                         if ( cached ) {
    1146                             parsedData.push( cached );
    1147                         }
    1148                     }
    1149 
    1150                     // If not multiple - return single value if we have one.
    1151                     if ( parsedData.length && ! self.model.get( 'multiple' ) ) {
    1152                         callback( parsedData[0] );
    1153                         return;
    1154                     }
    1155 
    1156                     var uncachedIds = _.difference( ids, _.pluck( parsedData, 'id' ) );
    1157 
    1158                     if ( ! uncachedIds.length ) {
    1159 
    1160                         callback( parsedData );
    1161 
    1162                     } else {
    1163 
    1164                         var initAjaxData      = jQuery.extend( true, {}, ajaxData );
    1165                         initAjaxData.action   = 'shortcode_ui_post_field';
    1166                         initAjaxData.post__in = uncachedIds;
    1167 
    1168                         $.get( ajaxurl, initAjaxData ).done( function( response ) {
    1169 
    1170                             if ( ! response.success ) {
    1171                                 return { results: {}, more: false };
    1172                             }
    1173 
    1174                             postSelectCache = $.extend( postSelectCache, response.data.posts );
    1175 
    1176                             // If not multi-select, expects single object, not array of objects.
    1177                             if ( ! self.model.get( 'multiple' ) ) {
    1178                                 callback( response.data.posts[0] );
    1179                                 return;
    1180                             }
    1181 
    1182                             // Append new data to cached data.
    1183                             // Sort by original order.
    1184                             parsedData = parsedData
    1185                                 .concat( response.data.posts )
    1186                                 .sort(function (a, b) {
    1187                                     if ( ids.indexOf( a.id ) > ids.indexOf( b.id ) ) return 1;
    1188                                     if ( ids.indexOf( a.id ) < ids.indexOf( b.id ) ) return -1;
    1189                                     return 0;
    1190                                 });
    1191 
    1192                             callback( parsedData );
    1193                             return;
    1194 
    1195                         } );
    1196 
    1197                     }
    1198 
    1199                 },
    1200 
    1201             } );
    1202 
    1203             // Make multiple values sortable.
    1204             if ( this.model.get( 'multiple' ) ) {
    1205                 $field.select2('container').find('ul.select2-choices').sortable({
    1206                     containment: 'parent',
    1207                     start: function() { $('.shortcode-ui-post-select').select2('onSortStart'); },
    1208                     update: function() { $('.shortcode-ui-post-select').select2('onSortEnd'); }
    1209                 });
    1210             }
    1211 
    1212             return this;
    1213 
    1214         }
    1215 
    1216     } );
    1217 
    1218     /**
    1219      * Extending SUI Media Controller to hide Select2 UI Drop-Down when menu
    1220      * changes in Meida modal
    1221      * 1. going back/forth between different shortcakes (refresh)
    1222      * 2. changing the menu in left column (deactivate)
    1223      * 3. @TODO closing the modal.
    1224      */
    1225     var mediaController = sui.controllers.MediaController;
    1226     sui.controllers.MediaController = mediaController.extend({
    1227 
    1228         refresh: function(){
    1229             mediaController.prototype.refresh.apply( this, arguments );
    1230             this.destroySelect2UI();
    1231         },
    1232 
    1233         //doesn't need to call parent as it already an "abstract" method in parent to provide callback
    1234         deactivate: function() {
    1235             this.destroySelect2UI();
    1236         },
    1237 
    1238         destroySelect2UI: function() {
    1239             $('.shortcode-ui-post-select.select2-container').select2( "close" );
    1240         }
    1241 
    1242     });
    1243 
    1244 } )( jQuery );
    1245 
    1246 },{}],14:[function(require,module,exports){
     976},{"./../utils/sui.js":10,"./edit-attribute-field.js":16}],13:[function(require,module,exports){
     977(function (global){
     978var Backbone     = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
     979    sui          = require('./../utils/sui.js'),
     980    select2Field = require('./select2-field.js'),
     981    $            = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
     982
     983sui.views.editAttributeFieldPostSelect = sui.views.editAttributeSelect2Field.extend( {
     984
     985    selector: '.shortcode-ui-post-select',
     986
     987    ajaxData: {
     988        action    : 'shortcode_ui_post_field',
     989        nonce     : shortcodeUiPostFieldData.nonce,
     990    },
     991
     992    events: {
     993        'change .shortcode-ui-post-select': 'inputChanged',
     994    },
     995
     996    templateResult: function( post ) {
     997        if ( post.loading ) {
     998            return post.text;
     999        }
     1000
     1001        var markup = '<div class="clearfix select2-result-selectable">' +
     1002            post.text +
     1003        '</div>';
     1004
     1005        return markup;
     1006    },
     1007
     1008    templateSelection: function( post, container ) {
     1009        return post.text;
     1010    },
     1011
     1012
     1013} );
     1014
     1015}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
     1016},{"./../utils/sui.js":10,"./select2-field.js":23}],14:[function(require,module,exports){
     1017(function (global){
     1018var Backbone     = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
     1019    sui          = require('./../utils/sui.js'),
     1020    select2Field = require('./select2-field.js'),
     1021    $            = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
     1022
     1023sui.views.editAttributeFieldTermSelect = sui.views.editAttributeSelect2Field.extend( {
     1024
     1025    selector: '.shortcode-ui-term-select',
     1026
     1027    ajaxData: {
     1028        action    : 'shortcode_ui_term_field',
     1029        nonce     : shortcodeUiTermFieldData.nonce,
     1030    },
     1031
     1032    events: {
     1033        'change .shortcode-ui-term-select': 'inputChanged',
     1034    },
     1035
     1036    templateResult: function( post ) {
     1037        if ( post.loading ) {
     1038            return post.text;
     1039        }
     1040
     1041        var markup = '<div class="clearfix select2-result-selectable">' +
     1042            post.text +
     1043        '</div>';
     1044
     1045        return markup;
     1046    },
     1047
     1048    templateSelection: function( post, container ) {
     1049        return post.text;
     1050    },
     1051
     1052} );
     1053
     1054}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
     1055},{"./../utils/sui.js":10,"./select2-field.js":23}],15:[function(require,module,exports){
     1056(function (global){
     1057var Backbone     = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
     1058    sui          = require('./../utils/sui.js'),
     1059    select2Field = require('./select2-field.js'),
     1060    $            = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
     1061
     1062sui.views.editAttributeFieldUserSelect = sui.views.editAttributeSelect2Field.extend( {
     1063
     1064    selector: '.shortcode-ui-user-select',
     1065
     1066    ajaxData: {
     1067        action    : 'shortcode_ui_user_field',
     1068        nonce     : shortcodeUiUserFieldData.nonce,
     1069    },
     1070
     1071    events: {
     1072        'change .shortcode-ui-user-select': 'inputChanged',
     1073    },
     1074
     1075    templateResult: function( user ) {
     1076        if ( user.loading ) {
     1077            return user.text;
     1078        }
     1079
     1080        var markup = '<div class="clearfix select2-result-selectable">' +
     1081            user.text +
     1082        '</div>';
     1083
     1084        return markup;
     1085    },
     1086
     1087    templateSelection: function( user, container ) {
     1088        return user.text;
     1089    },
     1090
     1091
     1092} );
     1093
     1094}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
     1095},{"./../utils/sui.js":10,"./select2-field.js":23}],16:[function(require,module,exports){
    12471096(function (global){
    12481097var Backbone     = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
     
    12891138
    12901139        data.meta = _meta.join( ' ' );
     1140
     1141        // Ensure options are formatted correctly.
     1142        if ( 'options' in data ) {
     1143            data.options = this.parseOptions( data.options );
     1144        }
    12911145
    12921146        this.$el.html( this.template( data ) );
     
    13611215        wp.shortcake.hooks.doAction( hookName, changed, collection, shortcode );
    13621216
     1217    },
     1218
     1219    /**
     1220     * Parse Options to ensure they use the correct format.
     1221     *
     1222     * Backwards compatability for non-array options.
     1223     * Using objects was sub-optimal because properties don't have an order.
     1224     */
     1225    parseOptions: function( options ) {
     1226
     1227        if ( ! Array.isArray( options ) ) {
     1228            var _options = [];
     1229            _.each( Object.keys( options ), function( key ) {
     1230                _options.push( { value: key, label: options[ key ] } );
     1231            } );
     1232            options = _options;
     1233        } else {
     1234            options = options.map( function( option ) {
     1235                if ( 'object' !== typeof option ) {
     1236                    option = { value: option, label: option };
     1237                }
     1238                return option;
     1239            } );
     1240        }
     1241
     1242        return options;
     1243
    13631244    }
    13641245
     
    13871268
    13881269}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    1389 },{"./../utils/sui.js":10}],15:[function(require,module,exports){
     1270},{"./../utils/sui.js":10}],17:[function(require,module,exports){
    13901271(function (global){
    13911272var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null),
     
    13981279    editAttributeFieldAttachment = require('./edit-attribute-field-attachment.js'),
    13991280    editAttributeFieldPostSelect = require('./edit-attribute-field-post-select.js'),
    1400     editAttributeFieldColor = require('./edit-attribute-field-color.js');
     1281    editAttributeFieldTermSelect = require('./edit-attribute-field-term-select.js'),
     1282    editAttributeFieldUserSelect = require('./edit-attribute-field-user-select.js'),
     1283    editAttributeFieldColor      = require('./edit-attribute-field-color.js');
    14011284
    14021285
     
    14711354
    14721355}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    1473 },{"./../utils/sui.js":10,"./edit-attribute-field-attachment.js":11,"./edit-attribute-field-color.js":12,"./edit-attribute-field-post-select.js":13,"./edit-attribute-field.js":14}],16:[function(require,module,exports){
     1356},{"./../utils/sui.js":10,"./edit-attribute-field-attachment.js":11,"./edit-attribute-field-color.js":12,"./edit-attribute-field-post-select.js":13,"./edit-attribute-field-term-select.js":14,"./edit-attribute-field-user-select.js":15,"./edit-attribute-field.js":16}],18:[function(require,module,exports){
    14741357(function (global){
    14751358var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null),
     
    15051388
    15061389}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    1507 },{}],17:[function(require,module,exports){
     1390},{}],19:[function(require,module,exports){
    15081391(function (global){
    15091392var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null);
     
    15521435
    15531436}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    1554 },{"./../collections/shortcodes.js":2,"./insert-shortcode-list-item.js":16}],18:[function(require,module,exports){
     1437},{"./../collections/shortcodes.js":2,"./insert-shortcode-list-item.js":18}],20:[function(require,module,exports){
    15551438(function (global){
    15561439var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null),
     
    16681551
    16691552    insertAction: function() {
     1553        /* Trigger render_destroy */
     1554        /*
     1555         * Action run before the shortcode overlay is destroyed.
     1556         *
     1557         * Called as `shortcode-ui.render_destroy`.
     1558         *
     1559         * @param shortcodeModel (object)
     1560         *           Reference to the shortcode model used in this overlay.
     1561         */
     1562        var hookName = 'shortcode-ui.render_destroy';
     1563        var shortcodeModel = this.controller.state().props.get( 'currentShortcode' );
     1564        wp.shortcake.hooks.doAction( hookName, shortcodeModel );
     1565
    16701566        this.controller.state().insert();
     1567
    16711568    },
    16721569
     
    16761573
    16771574}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    1678 },{"./../controllers/media-controller.js":3,"./media-toolbar":19,"./shortcode-ui":22}],19:[function(require,module,exports){
     1575},{"./../controllers/media-controller.js":3,"./media-toolbar":21,"./shortcode-ui":24}],21:[function(require,module,exports){
    16791576(function (global){
    16801577var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null);
     
    17081605
    17091606}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    1710 },{}],20:[function(require,module,exports){
     1607},{}],22:[function(require,module,exports){
    17111608(function (global){
    17121609var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null);
     
    17561653
    17571654}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    1758 },{"./../utils/sui.js":10}],21:[function(require,module,exports){
    1759 (function (global){
    1760 var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
    1761     $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
     1655},{"./../utils/sui.js":10}],23:[function(require,module,exports){
     1656(function (global){
     1657var Backbone     = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
     1658    sui          = require('./../utils/sui.js'),
     1659    $            = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
    17621660
    17631661/**
    1764  * Preview of rendered shortcode.
    1765  * Asynchronously fetches rendered shortcode content from WordPress.
    1766  * Displayed in an iframe to isolate editor styles.
     1662 * Abstract field for all ajax Select2-powered field views
    17671663 *
    1768  * @class ShortcodePreview
    1769  * @constructor
    1770  * @params options
    1771  * @params options.model {Shortcode} Requires a valid shortcode.
     1664 * Adds useful helpers that are shared between all of the fields which use
     1665 * Select2 as their UI.
     1666 *
    17721667 */
    1773 var ShortcodePreview = Backbone.View.extend({
    1774     initialize: function( options ) {
    1775         this.head = this.getEditorStyles().join( "\n" );
    1776     },
    1777 
    1778     getLoading: function() {
    1779         return '<div class="loading-placeholder">' +
    1780             '<div class="dashicons dashicons-admin-media"></div>' +
    1781             '<div class="wpview-loading"><ins></ins></div>' +
    1782         '</div>';
    1783     },
    1784 
    1785     /**
    1786      * @method render
    1787      * @chainable
    1788      * @returns {ShortcodePreview}
    1789      */
     1668sui.views.editAttributeSelect2Field = sui.views.editAttributeField.extend( {
     1669
     1670    /**
     1671     * Store selection on model as a string. If this is a multiple selection,
     1672     * we'll be storing the value as a comma-separated list.
     1673     *
     1674     * @param jQuery.Event Change event triggered.
     1675     */
     1676    inputChanged: function(e) {
     1677        var _selected = $( e.currentTarget ).val();
     1678
     1679        // Store multiple selections as comma-delimited list
     1680        if ( Array.isArray( _selected ) ) {
     1681            _selected = _selected.join( ',' );
     1682        }
     1683
     1684        this.setValue( String( _selected ) );
     1685        this.triggerCallbacks();
     1686    },
     1687
     1688    /**
     1689     * Load the values to be preselected before initializing field
     1690     *
     1691     * @param $field jQuery object reference to the <select> field
     1692     * @param object ajaxData object containing ajax action, nonce, and shortcode & model data
     1693     * @param string includeField how to specify the current selection, ie 'post__in'
     1694     */
     1695    preselect: function( $field ) {
     1696        var _preselected = String( this.getValue() );
     1697
     1698        if ( _preselected.length ) {
     1699            var request = {
     1700                include   : _preselected,
     1701                shortcode : this.shortcode.get( 'shortcode_tag'),
     1702                attr      : this.model.get( 'attr' )
     1703            };
     1704
     1705            $.get( ajaxurl, $.extend( request, this.ajaxData ),
     1706                function( response ) {
     1707                    _.each( response.data.items, function( item ) {
     1708                        $('<option>')
     1709                            .attr( 'value', item.id )
     1710                            .text( item.text )
     1711                            .prop( 'selected', 'selected' )
     1712                            .appendTo( $field );
     1713                    } );
     1714                }
     1715            );
     1716        }
     1717    },
     1718
     1719    /**
     1720     * Make selections in this field sortable, if it's multiple select
     1721     *
     1722     * @param $field jQuery object reference to the <select> field
     1723     */
     1724    sortable: function( $field ) {
     1725        var ul = $field.next('.select2-container').first('ul.select2-selection__rendered');
     1726        ul.sortable({
     1727            placeholder : 'ui-state-highlight',
     1728            forcePlaceholderSize: true,
     1729            items       : 'li:not(.select2-search__field)',
     1730            tolerance   : 'pointer',
     1731            stop: function() {
     1732                $( $(ul).find('.select2-selection__choice').get().reverse() ).each(function() {
     1733                    var id = $(this).data('data').id;
     1734                    var option = $field.find('option[value="' + id + '"]')[0];
     1735                    $field.prepend(option);
     1736                });
     1737                $field.trigger( 'change' );
     1738            }
     1739        });
     1740    },
     1741
    17901742    render: function() {
    17911743
    1792         var self = this;
    1793 
    1794         // Render loading iFrame.
    1795         this.renderIFrame({
    1796             head: self.head,
    1797             body: self.getLoading(),
    1798         });
    1799 
    1800         // Fetch shortcode preview.
    1801         // Render iFrame with shortcode preview.
    1802         this.fetchShortcode( function( response ) {
    1803             self.renderIFrame({
    1804                 head: self.head,
    1805                 body: response,
    1806             });
    1807         });
     1744        var self = this,
     1745            defaults = { multiple: false };
     1746
     1747        for ( var arg in defaults ) {
     1748            if ( ! this.model.get( arg ) ) {
     1749                this.model.set( arg, defaults[ arg ] );
     1750            }
     1751        }
     1752
     1753        var data = this.model.toJSON();
     1754        data.id = 'shortcode-ui-' + this.model.get( 'attr' ) + '-' + this.model.cid;
     1755
     1756        this.$el.html( this.template( data ) );
     1757
     1758        var $field = this.$el.find( this.selector );
     1759
     1760        this.preselect( $field );
     1761
     1762        var $fieldSelect2 = $field.select2({
     1763            placeholder: "Search",
     1764            multiple: this.model.get( 'multiple' ),
     1765
     1766            ajax: {
     1767                url: ajaxurl,
     1768                dataType: 'json',
     1769                delay: 250,
     1770                data: function (params) {
     1771                    return $.extend( {
     1772                        s         : params.term, // search term
     1773                        page      : params.page,
     1774                        shortcode : self.shortcode.get( 'shortcode_tag'),
     1775                        attr      : self.model.get( 'attr' )
     1776                    }, self.ajaxData );
     1777                },
     1778                processResults: function (response, params) {
     1779                    if ( ! response.success || 'undefined' === typeof response.data ) {
     1780                        return { results: [] };
     1781                    }
     1782                    var data = response.data;
     1783                    params.page = params.page || 1;
     1784                    return {
     1785                        results: data.items,
     1786                        pagination: {
     1787                            more: ( params.page * data.items_per_page ) < data.found_items
     1788                        }
     1789                    };
     1790                },
     1791                cache: true
     1792            },
     1793            escapeMarkup: function( markup ) { return markup; },
     1794            minimumInputLength: 1,
     1795            templateResult: this.templateResult,
     1796            templateSelection: this.templateSelection,
     1797        } );
     1798
     1799        if ( this.model.get( 'multiple' ) ) {
     1800            this.sortable( $field );
     1801        }
    18081802
    18091803        return this;
    1810     },
    1811 
    1812     /**
    1813      * Render a child iframe, removing any previously rendered iframe. Additionally, observe the rendered iframe
    1814      * for mutations and resize as necessary to match content.
    1815      *
    1816      * @param params
    1817      */
    1818     renderIFrame: function( params ) {
    1819 
    1820         var self = this, $iframe, resize;
    1821 
    1822         _.defaults( params || {}, { 'head': '', 'body': '', 'body_classes': 'shortcake shortcake-preview' });
    1823 
    1824         var isIE = typeof tinymce != 'undefined' ? tinymce.Env.ie : false;
    1825 
    1826         $iframe = $( '<iframe/>', {
    1827             src: isIE ? 'javascript:""' : '', // jshint ignore:line
    1828             frameBorder: '0',
    1829             allowTransparency: 'true',
    1830             scrolling: 'no',
    1831             style: "width: 100%; display: block",
    1832         } );
    1833 
    1834         /**
    1835          * Render preview in iFrame once loaded.
    1836          * This is required because you can't write to
    1837          * an iFrame contents before it exists.
    1838          */
    1839         $iframe.load( function() {
    1840 
    1841             self.autoresizeIframe( $(this) );
    1842 
    1843             var head = $(this).contents().find('head'),
    1844                 body = $(this).contents().find('body');
    1845 
    1846             head.html( params.head );
    1847             body.html( params.body );
    1848             body.addClass( params.body_classes );
    1849 
    1850         } );
    1851 
    1852         this.$el.html( $iframe );
    1853 
    1854     },
    1855 
    1856     /**
    1857      * Watch for mutations in iFrame content.
    1858      * resize iFrame height on change.
    1859      *
    1860      * @param  $ object $iframe
    1861      */
    1862     autoresizeIframe: function( $iframe ) {
    1863 
    1864         var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
    1865 
    1866         // Resize iFrame to size inner document.
    1867         var resize = function() {
    1868             $iframe.height( $iframe.contents().find('html').height() );
    1869         };
    1870 
    1871         resize();
    1872 
    1873         if ( MutationObserver ) {
    1874 
    1875             var observer = new MutationObserver( function() {
    1876                 resize();
    1877                 $iframe.contents().find('img,link').load( resize );
    1878             } );
    1879 
    1880             observer.observe(
    1881                 $iframe.contents()[0],
    1882                 { attributes: true, childList: true, subtree: true }
    1883             );
    1884 
    1885         } else {
    1886 
    1887             for ( i = 1; i < 6; i++ ) {
    1888                 setTimeout( resize, i * 700 );
    1889             }
    1890 
    1891         }
    1892 
    1893     },
    1894 
    1895 
    1896     /**
    1897      * Makes an AJAX call to the server to render the shortcode based on user supplied attributes. Server-side
    1898      * rendering is necessary to allow for shortcodes that incorporate external content based on shortcode
    1899      * attributes.
    1900      *
    1901      * @method fetchShortcode
    1902      * @returns {String} Rendered shortcode markup (HTML).
    1903      */
    1904     fetchShortcode: function( callback ) {
    1905 
    1906         wp.ajax.post( 'do_shortcode', {
    1907             post_id: $( '#post_ID' ).val(),
    1908             shortcode: this.model.formatShortcode(),
    1909             nonce: shortcodeUIData.nonces.preview,
    1910         }).done( function( response ) {
    1911             callback( response );
    1912         }).fail( function() {
    1913             var span = $('<span />').addClass('shortcake-error').text( shortcodeUIData.strings.mce_view_error );
    1914             var wrapper = $('<div />').html( span );
    1915             callback( wrapper.html() );
    1916         } );
    1917 
    1918     },
    1919 
    1920     /**
    1921      * Returns an array of <link> tags for stylesheets applied to the TinyMCE editor.
    1922      *
    1923      * @method getEditorStyles
    1924      * @returns {Array}
    1925      */
    1926     getEditorStyles: function() {
    1927         var styles = {};
    1928 
    1929         var editors = typeof tinymce != 'undefined' ? tinymce.editors : [];
    1930         _.each( editors, function( editor ) {
    1931             _.each( editor.dom.$( 'link[rel="stylesheet"]', editor.getDoc().head ), function( link ) {
    1932                 if ( link.href ) {
    1933                     styles[ link.href ] = true;
    1934                 }
    1935             });
    1936         });
    1937 
    1938         styles = _.map( _.keys( styles ), function( href ) {
    1939             return $( '<link rel="stylesheet" type="text/css">' ).attr( 'href', href )[0].outerHTML;
    1940         });
    1941 
    1942         return styles;
    19431804    }
    19441805});
    19451806
    1946 module.exports = ShortcodePreview;
    1947 
    1948 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    1949 },{}],22:[function(require,module,exports){
     1807/**
     1808 * Extending SUI Media Controller to hide Select2 UI Drop-Down when menu
     1809 * changes in Meida modal
     1810 * 1. going back/forth between different shortcakes (refresh)
     1811 * 2. changing the menu in left column (deactivate)
     1812 * 3. @TODO closing the modal.
     1813 */
     1814var mediaController = sui.controllers.MediaController;
     1815sui.controllers.MediaController = mediaController.extend({
     1816
     1817    refresh: function(){
     1818        mediaController.prototype.refresh.apply( this, arguments );
     1819        this.destroySelect2UI();
     1820    },
     1821
     1822    //doesn't need to call parent as it already an "abstract" method in parent to provide callback
     1823    deactivate: function() {
     1824        this.destroySelect2UI();
     1825    },
     1826
     1827    destroySelect2UI: function() {
     1828        $fieldSelect2.select2( 'close' );
     1829    }
     1830
     1831});
     1832
     1833
     1834}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
     1835},{"./../utils/sui.js":10}],24:[function(require,module,exports){
    19501836(function (global){
    19511837var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
    19521838    insertShortcodeList = require('./insert-shortcode-list.js'),
    1953     ShortcodePreview = require('./shortcode-preview.js'),
    19541839    EditShortcodeForm = require('./edit-shortcode-form.js'),
    19551840    Toolbar = require('./media-toolbar.js'),
     
    20461931        this.render();
    20471932
     1933        /* Trigger render_new */
     1934        /*
     1935         * Action run after a new shortcode overlay is rendered.
     1936         *
     1937         * Called as `shortcode-ui.render_new`.
     1938         *
     1939         * @param shortcodeModel (object)
     1940         *           Reference to the shortcode model used in this overlay.
     1941         */
     1942        var hookName = 'shortcode-ui.render_new';
     1943        var shortcodeModel = this.controller.props.get( 'currentShortcode' );
     1944        wp.shortcake.hooks.doAction( hookName, shortcodeModel );
     1945
    20481946    },
    20491947
     
    20531951
    20541952}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    2055 },{"./../utils/sui.js":10,"./edit-shortcode-form.js":15,"./insert-shortcode-list.js":17,"./media-toolbar.js":19,"./search-shortcode.js":20,"./shortcode-preview.js":21}]},{},[7]);
     1953},{"./../utils/sui.js":10,"./edit-shortcode-form.js":17,"./insert-shortcode-list.js":19,"./media-toolbar.js":21,"./search-shortcode.js":22}]},{},[7]);
  • shortcode-ui/trunk/js/src/controllers/media-controller.js

    r1147525 r1536575  
    2727        var pattern = new RegExp( searchTerm, "gi" );
    2828        var filteredModels = sui.shortcodes.filter( function( model ) {
     29            pattern.lastIndex = 0;
    2930            return pattern.test( model.get( "label" ) );
    3031        });
  • shortcode-ui/trunk/js/src/models/shortcode.js

    r1278066 r1536575  
    7676            // Encode textareas incase HTML
    7777            if ( attr.get( 'encode' ) ) {
    78                 attr.set( 'value', encodeURIComponent( decodeURIComponent( attr.get( 'value' ) ) ), { silent: true } );
     78                attr.set( 'value', encodeURIComponent( decodeURIComponent( attr.get( 'value' ).replace( "%", "&#37;" ) ) ), { silent: true } );
    7979            }
    8080
     
    9494
    9595        if ( attrs.length > 0 ) {
    96             template = "[{{ shortcode }} {{ attributes }}]";
     96            template = "[{{ shortcode }} {{ attributes }}";
    9797        } else {
    98             template = "[{{ shortcode }}]";
     98            template = "[{{ shortcode }}";
    9999        }
    100100
    101101        if ( content && content.length > 0 ) {
    102             template += "{{ content }}[/{{ shortcode }}]";
     102            template += "]{{ content }}[/{{ shortcode }}]";
     103        } else {
     104            // add closing slash to shortcodes without content
     105            template += "/]";
    103106        }
    104107
  • shortcode-ui/trunk/js/src/shortcode-ui.js

    r1147525 r1536575  
    1818            wp.mce.views.register(
    1919                shortcode.get('shortcode_tag'),
    20                 // Must extend for 4.1.
    21                 // This is handled by wp.mce.views.register in 4.2.
    22                 $.extend( true, {}, shortcodeViewConstructor )
     20                shortcodeViewConstructor
    2321            );
    2422        }
    2523    } );
    2624
     25    $(document.body).on( 'click', '.shortcake-add-post-element', function( event ) {
     26        var elem = $( event.currentTarget ),
     27            editor = elem.data('editor'),
     28            options = {
     29                frame: 'post',
     30                state: 'shortcode-ui',
     31                title: shortcodeUIData.strings.media_frame_title
     32            };
     33
     34        event.preventDefault();
     35
     36        // Remove focus from the `.shortcake-add-post-element` button.
     37        // Prevents Opera from showing the outline of the button above the modal.
     38        //
     39        // See: https://core.trac.wordpress.org/ticket/22445
     40        elem.blur();
     41
     42        wp.media.editor.remove( editor );
     43        wp.media.editor.open( editor, options );
     44    } );
     45
    2746});
  • shortcode-ui/trunk/js/src/utils/fetcher.js

    r1278066 r1536575  
    8282        }
    8383
    84         var request = $.post( ajaxurl + '?action=bulk_do_shortcode', {
    85                 queries: _.pluck( fetcher.queries, 'query' )
    86             }
    87         );
     84        var request = wp.ajax.post( 'bulk_do_shortcode', {
     85            queries: _.pluck( fetcher.queries, 'query' )
     86        });
    8887
    89         request.done( function( response ) {
    90             _.each( response.data, function( result, index ) {
     88        request.done( function( responseData ) {
     89            _.each( responseData, function( result, index ) {
    9190                var matchedQuery = _.findWhere( fetcher.queries, {
    9291                    counter: parseInt( index ),
  • shortcode-ui/trunk/js/src/utils/shortcode-view-constructor.js

    r1281670 r1536575  
    8585            if ( attr && attr.get('encode') ) {
    8686                value = decodeURIComponent( value );
     87                value = value.replace( "&#37;", "%" );
    8788            }
    8889
     
    161162     */
    162163    edit: function( shortcodeString ) {
    163         var currentShortcode;
    164 
    165         // Backwards compatability for WP pre-4.2
    166         if ( 'object' === typeof( shortcodeString ) ) {
    167             shortcodeString = decodeURIComponent( $(shortcodeString).attr('data-wpview-text') );
    168         }
    169 
    170         currentShortcode = this.parseShortcodeString( shortcodeString );
     164
     165        var currentShortcode = this.parseShortcodeString( shortcodeString );
    171166
    172167        if ( currentShortcode ) {
     
    180175            wp_media_frame.open();
    181176
     177            /* Trigger render_edit */
     178            /*
     179             * Action run after an edit shortcode overlay is rendered.
     180             *
     181             * Called as `shortcode-ui.render_edit`.
     182             *
     183             * @param shortcodeModel (object)
     184             *           Reference to the shortcode model used in this overlay.
     185             */
     186            var hookName = 'shortcode-ui.render_edit';
     187            var shortcodeModel = this.shortcodeModel;
     188            wp.shortcake.hooks.doAction( hookName, shortcodeModel );
     189
    182190        }
    183191
     
    200208        var shortcode_tags = _.map( sui.shortcodes.pluck( 'shortcode_tag' ), this.pregQuote ).join( '|' );
    201209        var regexp = wp.shortcode.regexp( shortcode_tags );
     210        regexp.lastIndex = 0;
    202211        var matches = regexp.exec( shortcodeString );
    203212
     
    252261    },
    253262
    254     // Backwards compatability for Pre WP 4.2.
    255     View: {
    256 
    257         overlay: true,
    258 
    259         initialize: function( options ) {
    260             this.shortcode = this.getShortcode( options );
    261             this.fetch();
    262         },
    263 
    264         getShortcode: function( options ) {
    265 
    266             var shortcodeModel, shortcode;
    267 
    268             shortcodeModel = sui.shortcodes.findWhere( { shortcode_tag: options.shortcode.tag } );
    269 
    270             if (!shortcodeModel) {
    271                 return;
    272             }
    273 
    274             shortcode = shortcodeModel.clone();
    275 
    276             shortcode.get('attrs').each(
    277                     function(attr) {
    278 
    279                         if (attr.get('attr') in options.shortcode.attrs.named) {
    280                             attr.set('value',
    281                                     options.shortcode.attrs.named[attr
    282                                             .get('attr')]);
    283                         }
    284 
    285                     });
    286 
    287             if ('content' in options.shortcode) {
    288                 var inner_content = shortcode.get('inner_content');
    289                 if ( inner_content ) {
    290                     inner_content.set('value', options.shortcode.content);
    291                 }
    292             }
    293 
    294             return shortcode;
    295 
    296         },
    297 
    298         fetch : function() {
    299 
    300             var self = this;
    301 
    302             if ( ! this.parsed ) {
    303 
    304                 wp.ajax.post( 'do_shortcode', {
    305                     post_id: $( '#post_ID' ).val(),
    306                     shortcode: this.shortcode.formatShortcode(),
    307                     nonce: shortcodeUIData.nonces.preview,
    308                 }).done( function( response ) {
    309                     if ( response.indexOf( '<script' ) !== -1 ) {
    310                         self.setIframes( self.getEditorStyles(), response );
    311                     } else {
    312                         self.parsed = response;
    313                         self.render( true );
    314                     }
    315                 }).fail( function() {
    316                     self.parsed = '<span class="shortcake-error">' + shortcodeUIData.strings.mce_view_error + '</span>';
    317                     self.render( true );
    318                 } );
    319 
    320             }
    321 
    322         },
    323 
    324         /**
    325          * Render the shortcode
    326          *
    327          * To ensure consistent rendering - this makes an ajax request to the
    328          * admin and displays.
    329          *
    330          * @return string html
    331          */
    332         getHtml : function() {
    333             return this.parsed;
    334         },
    335 
    336         /**
    337          * Returns an array of <link> tags for stylesheets applied to the TinyMCE editor.
    338          *
    339          * @method getEditorStyles
    340          * @returns {Array}
    341          */
    342         getEditorStyles: function() {
    343 
    344             var styles = '';
    345 
    346             this.getNodes( function ( editor, node, content ) {
    347                 var dom = editor.dom,
    348                     bodyClasses = editor.getBody().className || '',
    349                     iframe, iframeDoc, i, resize;
    350 
    351                 tinymce.each( dom.$( 'link[rel="stylesheet"]', editor.getDoc().head ), function( link ) {
    352                     if ( link.href && link.href.indexOf( 'skins/lightgray/content.min.css' ) === -1 &&
    353                         link.href.indexOf( 'skins/wordpress/wp-content.css' ) === -1 ) {
    354 
    355                         styles += dom.getOuterHTML( link ) + '\n';
    356                     }
    357 
    358                 });
    359 
    360             } );
    361 
    362             return styles;
    363         },
    364 
    365     },
    366263};
    367264
  • shortcode-ui/trunk/js/src/views/edit-attribute-field-attachment.js

    r1278066 r1536575  
    11var sui = require('sui-utils/sui');
     2var $   = require('jquery');
    23
    34var editAttributeFieldAttachment = sui.views.editAttributeField.extend( {
     5
     6    previewTemplate: wp.template( 'shortcake-image-preview' ),
    47
    58    events: {
     
    1013    },
    1114
     15    currentSelection: [],
     16
     17    initialize: function() {
     18
     19        var self = this;
     20
     21        _.bindAll( self, 'updateValue', 'initSelection', '_renderPreview', '_renderAll', '_removeAttachment' );
     22
     23        self.initSelection();
     24
     25        self.currentSelection.on( 'all', this.updateValue );
     26        self.currentSelection.on( 'add', this._renderPreview );
     27        self.currentSelection.on( 'reset', this._renderAll );
     28
     29    },
     30
     31    /**
     32     * Initialize Selection.
     33     *
     34     * Selection is an Attachment collection containing full models for the current value.
     35     *
     36     * @return null
     37     */
     38    initSelection: function() {
     39
     40        this.currentSelection = new wp.media.model.Selection( [], {
     41            multiple: this.model.get( 'multiple' ) ? true : false,
     42        } );
     43
     44        // Initialize selection.
     45        _.each( this.getValue(), function( item ) {
     46
     47            var model;
     48
     49            // Legacy. Handle storing full objects.
     50            item  = ( 'object' === typeof( item ) ) ? item.id : item;
     51            model = new wp.media.attachment( item );
     52
     53            this.currentSelection.add( model );
     54
     55            // Re-render after attachments have synced.
     56            model.fetch();
     57            model.on( 'sync', this._renderAll );
     58
     59        }.bind(this) );
     60
     61    },
     62
    1263    /**
    1364     * Update the field attachment.
     
    1768     * @param {int} id Attachment ID
    1869     */
    19     updateValue: function( id ) {
    20 
    21         if ( ! id ) {
    22             return;
    23         }
    24 
    25         this.setValue( id );
    26 
    27         var self = this;
    28 
    29         if ( editAttributeFieldAttachment.getFromCache( id ) ) {
    30             self._renderPreview( editAttributeFieldAttachment.getFromCache( id ) );
    31 
    32             // Call the updateValue() function, to trigger any listeners
    33             // hooked on it.
    34             self.triggerCallbacks();
    35             return;
    36         }
    37 
    38         this.$container.addClass( 'loading' );
    39 
    40         wp.ajax.post( 'get-attachment', {
    41             'id': id
    42         } ).done( function( attachment ) {
    43             // Cache for later.
    44             editAttributeFieldAttachment.setInCache( id, attachment );
    45             self._renderPreview( attachment );
    46 
    47             // Call the updateValue() function, to trigger any listeners
    48             // hooked on it.
    49             self.triggerCallbacks();
    50         } ).always( function( attachment ) {
    51             self.$container.removeClass( 'loading' );
    52         });
     70    updateValue: function() {
     71        var value = this.currentSelection.pluck( 'id' );
     72        this.setValue( value );
     73        this.triggerCallbacks();
    5374    },
    5475
     
    6485        this.$el.html( this.template( this.model.toJSON() ) );
    6586
    66         this.$container   = this.$el.find( '.shortcake-attachment-preview' );
     87        this.$container = this.$el.find( '.attachment-previews' );
    6788        this.$thumbnailDetailsContainer   = this.$el.find( '.thumbnail-details-container' );
    68         var $addButton    = this.$container.find( 'button.add' );
     89        var $addButton = this.$container.find( 'button.add' );
    6990
    7091        this.frame = wp.media( {
    71             multiple: false,
    72             title: this.model.get( 'frameTitle' ),
     92            multiple: this.model.get( 'multiple' ) ? true : false,
     93            title:    this.model.get( 'frameTitle' ),
    7394            library: {
    7495                type: this.model.get( 'libraryType' ),
     
    7697        } );
    7798
    78         // Add initial Attachment if available.
    79         this.updateValue( this.model.get( 'value' ) );
     99        this.frame.on( 'select', function() {
     100            this.$el.trigger( 'selectAttachment' );
     101        }.bind( this ) );
     102
     103        this._renderAll();
     104
     105    },
     106
     107    _renderAll: function() {
     108
     109        // Empty container.
     110        this.$container.html('');
     111
     112        // Render each attachment in current selection.
     113        this.currentSelection.each( function( attachment ) {
     114            this._renderPreview( attachment );
     115        }.bind(this) );
    80116
    81117    },
     
    88124    _renderPreview: function( attachment ) {
    89125
    90         var $thumbnail = jQuery('<div class="thumbnail"></div>');
    91 
    92         if ( 'image' !== attachment.type ) {
    93 
    94             jQuery( '<img/>', {
    95                 src: attachment.icon,
    96                 alt: attachment.title,
    97             } ).appendTo( $thumbnail );
    98 
    99             jQuery( '<div/>', {
    100                 class: 'filename',
    101                 html:  '<div>' + attachment.title + '</div>',
    102             } ).appendTo( $thumbnail );
    103 
    104         } else {
    105 
    106             attachmentThumb = (typeof attachment.sizes.thumbnail !== 'undefined') ?
    107                 attachment.sizes.thumbnail :
    108                 _.first( _.sortBy( attachment.sizes, 'width' ) );
    109 
    110             jQuery( '<img/>', {
    111                 src:    attachmentThumb.url,
    112                 width:  attachmentThumb.width,
    113                 height: attachmentThumb.height,
    114                 alt:    attachment.alt,
    115             } ) .appendTo( $thumbnail );
    116 
    117         }
    118 
    119         $thumbnail.find( 'img' ).wrap( '<div class="centered"></div>' );
    120         this.$container.append( $thumbnail );
    121         this.$container.toggleClass( 'has-attachment', true );
    122 
    123         this.$thumbnailDetailsContainer.find( '.filename' ).text( attachment.filename );
    124         this.$thumbnailDetailsContainer.find( '.date-formatted' ).text( attachment.dateFormatted );
    125         this.$thumbnailDetailsContainer.find( '.size' ).text( attachment.filesizeHumanReadable );
    126         this.$thumbnailDetailsContainer.find( '.dimensions' ).text( attachment.height + ' × ' + attachment.width );
    127         this.$thumbnailDetailsContainer.find( '.edit-link a' ).attr( "href", attachment.editLink );
    128         this.$thumbnailDetailsContainer.toggleClass( 'has-attachment', true );
     126        var $thumbnail = $( this.previewTemplate( attachment.toJSON() ) );
     127
     128        $thumbnail.appendTo( this.$container );
     129
     130        attachment.on( 'remove', function() {
     131            $thumbnail.remove();
     132        } );
     133
     134    },
     135
     136    getValue: function() {
     137
     138        var value = this.model.get( 'value' );
     139
     140        if ( ! ( value instanceof Array ) ) {
     141            value = value.split( ',' );
     142        }
     143
     144        value = value.map( function( id ) {
     145            return parseInt( id, 10 );
     146        } );
     147
     148        value = value.filter( function( id ) {
     149            return id > 0;
     150        } );
     151
     152        value.sort( function( a, b ) {
     153            return a < b;
     154        } );
     155
     156        return value;
    129157
    130158    },
     
    135163     */
    136164    _openMediaFrame: function(e) {
     165
    137166        e.preventDefault();
    138167        this.frame.open();
    139         if ( this.model.get( 'value' ) ) {
    140             var selection = this.frame.state().get('selection');
    141             attachment = wp.media.attachment( this.model.get( 'value' ) );
    142             attachment.fetch();
    143             selection.reset( attachment ? [ attachment ] : [] );
    144             this.frame.state().set('selection', selection);
    145         }
    146 
    147         var self = this;
    148         this.frame.on( 'select', function() {
    149             self.$el.trigger( 'selectAttachment'  );
    150         } );
     168
     169        var selection = this.frame.state().get('selection');
     170        selection.reset( this.currentSelection.models );
     171        this.frame.state('library').set( 'selection', selection );
    151172
    152173    },
     
    157178     */
    158179    _selectAttachment: function(e) {
     180
    159181        var selection  = this.frame.state().get('selection');
    160             attachment = selection.first();
    161         if ( attachment.id != this.model.get( 'value' ) ){
    162             this.model.set( 'value', null );
    163             this.$container.toggleClass( 'has-attachment', false );
    164             this.$container.find( '.thumbnail' ).remove();
    165             this.updateValue( attachment.id );
    166         }
     182        this.currentSelection.reset( selection.toJSON() );
     183
    167184        this.frame.close();
     185
    168186    },
    169187
     
    173191     */
    174192    _removeAttachment: function(e) {
     193
    175194        e.preventDefault();
    176195
    177         this.model.set( 'value', null );
    178 
    179         this.$container.toggleClass( 'has-attachment', false );
    180         this.$container.find( '.thumbnail' ).remove();
    181         this.$thumbnailDetailsContainer.toggleClass( 'has-attachment', false );
    182     },
    183 
    184 }, {
    185 
    186     _idCache: {},
    187 
    188     /**
    189      * Store attachments in a cache for quicker loading.
    190      */
    191     setInCache: function( id, attachment ) {
    192         this._idCache[ id ] = attachment;
    193     },
    194 
    195     /**
    196      * Retrieve an attachment from the cache.
    197      */
    198     getFromCache: function( id ){
    199         if ( 'undefined' === typeof this._idCache[ id ] ) {
    200             return false;
    201         }
    202         return this._idCache[ id ];
     196        var id = $( e.target ).attr( 'data-id' );
     197
     198        if ( ! id ) {
     199            return;
     200        }
     201
     202        var target = this.currentSelection.get( id );
     203
     204        if ( target ) {
     205            this.currentSelection.remove( target );
     206        }
     207
    203208    },
    204209
  • shortcode-ui/trunk/js/src/views/edit-attribute-field-post-select.js

    r1231560 r1536575  
    1 ( function( $ ) {
     1var Backbone     = require('backbone'),
     2    sui          = require('sui-utils/sui'),
     3    select2Field = require('sui-views/select2-field.js'),
     4    $            = require('jquery');
    25
    3     var sui = window.Shortcode_UI;
     6sui.views.editAttributeFieldPostSelect = sui.views.editAttributeSelect2Field.extend( {
    47
    5     // Cached Data.
    6     var postSelectCache = {};
     8    selector: '.shortcode-ui-post-select',
    79
    8     sui.views.editAttributeFieldPostSelect = sui.views.editAttributeField.extend( {
     10    ajaxData: {
     11        action    : 'shortcode_ui_post_field',
     12        nonce     : shortcodeUiPostFieldData.nonce,
     13    },
    914
    10         events: {
    11             'change .shortcode-ui-post-select': 'inputChanged',
    12         },
     15    events: {
     16        'change .shortcode-ui-post-select': 'inputChanged',
     17    },
    1318
    14         inputChanged: function(e) {
    15             this.setValue( e.val );
    16             this.triggerCallbacks();
    17         },
    18 
    19         render: function() {
    20 
    21             var self = this,
    22                 defaults = { multiple: false };
    23 
    24             for ( var arg in defaults ) {
    25                 if ( ! this.model.get( arg ) ) {
    26                     this.model.set( arg, defaults[ arg ] );
    27                 }
    28             }
    29 
    30             var data = this.model.toJSON();
    31             data.id = 'shortcode-ui-' + this.model.get( 'attr' ) + '-' + this.model.cid;
    32 
    33             this.$el.html( this.template( data ) );
    34 
    35             var ajaxData = {
    36                 action    : 'shortcode_ui_post_field',
    37                 nonce     : shortcodeUiPostFieldData.nonce,
    38                 shortcode : this.shortcode.get( 'shortcode_tag'),
    39                 attr      : this.model.get( 'attr' )
    40             };
    41 
    42             var $field = this.$el.find( '.shortcode-ui-post-select' );
    43 
    44             $field.select2({
    45 
    46                 placeholder: "Search",
    47                 multiple: this.model.get( 'multiple' ),
    48                 ajax: {
    49                     url: ajaxurl,
    50                     dataType: 'json',
    51                     quietMillis: 250,
    52                     data: function (term, page) {
    53                         ajaxData.s    = term;
    54                         ajaxData.page = page;
    55                         return ajaxData;
    56                     },
    57                     results: function ( response, page ) {
    58 
    59                         if ( ! response.success ) {
    60                             return { results: {}, more: false };
    61                         }
    62 
    63                         // Cache data for quicker rendering later.
    64                         postSelectCache = $.extend( postSelectCache, response.data.posts );
    65 
    66                         var more = ( page * response.data.posts_per_page ) < response.data.found_posts; // whether or not there are more results available
    67                         return { results: response.data.posts, more: more };
    68 
    69                     },
    70                 },
    71 
    72                 /**
    73                  * Initialize Callback
    74                  * Used to set render the initial value.
    75                  * Has to make a request to get the title for the current ID.
    76                  */
    77                 initSelection: function(element, callback) {
    78 
    79                     var ids, parsedData = [], cached;
    80 
    81                     // Convert stored value to array of IDs (int).
    82                     ids = $(element)
    83                         .val()
    84                         .split(',')
    85                         .map( function (str) { return str.trim(); } )
    86                         .map( function (str) { return parseInt( str ); } );
    87 
    88                     if ( ids.length < 1 ) {
    89                         return;
    90                     }
    91 
    92                     // Check if there is already cached data.
    93                     for ( var i = 0; i < ids.length; i++ ) {
    94                         cached = _.find( postSelectCache, _.matches( { id: ids[i] } ) );
    95                         if ( cached ) {
    96                             parsedData.push( cached );
    97                         }
    98                     }
    99 
    100                     // If not multiple - return single value if we have one.
    101                     if ( parsedData.length && ! self.model.get( 'multiple' ) ) {
    102                         callback( parsedData[0] );
    103                         return;
    104                     }
    105 
    106                     var uncachedIds = _.difference( ids, _.pluck( parsedData, 'id' ) );
    107 
    108                     if ( ! uncachedIds.length ) {
    109 
    110                         callback( parsedData );
    111 
    112                     } else {
    113 
    114                         var initAjaxData      = jQuery.extend( true, {}, ajaxData );
    115                         initAjaxData.action   = 'shortcode_ui_post_field';
    116                         initAjaxData.post__in = uncachedIds;
    117 
    118                         $.get( ajaxurl, initAjaxData ).done( function( response ) {
    119 
    120                             if ( ! response.success ) {
    121                                 return { results: {}, more: false };
    122                             }
    123 
    124                             postSelectCache = $.extend( postSelectCache, response.data.posts );
    125 
    126                             // If not multi-select, expects single object, not array of objects.
    127                             if ( ! self.model.get( 'multiple' ) ) {
    128                                 callback( response.data.posts[0] );
    129                                 return;
    130                             }
    131 
    132                             // Append new data to cached data.
    133                             // Sort by original order.
    134                             parsedData = parsedData
    135                                 .concat( response.data.posts )
    136                                 .sort(function (a, b) {
    137                                     if ( ids.indexOf( a.id ) > ids.indexOf( b.id ) ) return 1;
    138                                     if ( ids.indexOf( a.id ) < ids.indexOf( b.id ) ) return -1;
    139                                     return 0;
    140                                 });
    141 
    142                             callback( parsedData );
    143                             return;
    144 
    145                         } );
    146 
    147                     }
    148 
    149                 },
    150 
    151             } );
    152 
    153             // Make multiple values sortable.
    154             if ( this.model.get( 'multiple' ) ) {
    155                 $field.select2('container').find('ul.select2-choices').sortable({
    156                     containment: 'parent',
    157                     start: function() { $('.shortcode-ui-post-select').select2('onSortStart'); },
    158                     update: function() { $('.shortcode-ui-post-select').select2('onSortEnd'); }
    159                 });
    160             }
    161 
    162             return this;
    163 
     19    templateResult: function( post ) {
     20        if ( post.loading ) {
     21            return post.text;
    16422        }
    16523
    166     } );
     24        var markup = '<div class="clearfix select2-result-selectable">' +
     25            post.text +
     26        '</div>';
    16727
    168     /**
    169      * Extending SUI Media Controller to hide Select2 UI Drop-Down when menu
    170      * changes in Meida modal
    171      * 1. going back/forth between different shortcakes (refresh)
    172      * 2. changing the menu in left column (deactivate)
    173      * 3. @TODO closing the modal.
    174      */
    175     var mediaController = sui.controllers.MediaController;
    176     sui.controllers.MediaController = mediaController.extend({
     28        return markup;
     29    },
    17730
    178         refresh: function(){
    179             mediaController.prototype.refresh.apply( this, arguments );
    180             this.destroySelect2UI();
    181         },
     31    templateSelection: function( post, container ) {
     32        return post.text;
     33    },
    18234
    183         //doesn't need to call parent as it already an "abstract" method in parent to provide callback
    184         deactivate: function() {
    185             this.destroySelect2UI();
    186         },
    18735
    188         destroySelect2UI: function() {
    189             $('.shortcode-ui-post-select.select2-container').select2( "close" );
    190         }
    191 
    192     });
    193 
    194 } )( jQuery );
     36} );
  • shortcode-ui/trunk/js/src/views/edit-attribute-field.js

    r1284972 r1536575  
    4242
    4343        data.meta = _meta.join( ' ' );
     44
     45        // Ensure options are formatted correctly.
     46        if ( 'options' in data ) {
     47            data.options = this.parseOptions( data.options );
     48        }
    4449
    4550        this.$el.html( this.template( data ) );
     
    114119        wp.shortcake.hooks.doAction( hookName, changed, collection, shortcode );
    115120
     121    },
     122
     123    /**
     124     * Parse Options to ensure they use the correct format.
     125     *
     126     * Backwards compatability for non-array options.
     127     * Using objects was sub-optimal because properties don't have an order.
     128     */
     129    parseOptions: function( options ) {
     130
     131        if ( ! Array.isArray( options ) ) {
     132            var _options = [];
     133            _.each( Object.keys( options ), function( key ) {
     134                _options.push( { value: key, label: options[ key ] } );
     135            } );
     136            options = _options;
     137        } else {
     138            options = options.map( function( option ) {
     139                if ( 'object' !== typeof option ) {
     140                    option = { value: option, label: option };
     141                }
     142                return option;
     143            } );
     144        }
     145
     146        return options;
     147
    116148    }
    117149
  • shortcode-ui/trunk/js/src/views/edit-shortcode-form.js

    r1278066 r1536575  
    88    editAttributeFieldAttachment = require( 'sui-views/edit-attribute-field-attachment' ),
    99    editAttributeFieldPostSelect = require( 'sui-views/edit-attribute-field-post-select' ),
    10     editAttributeFieldColor = require( 'sui-views/edit-attribute-field-color' );
     10    editAttributeFieldTermSelect = require( 'sui-views/edit-attribute-field-term-select' ),
     11    editAttributeFieldUserSelect = require( 'sui-views/edit-attribute-field-user-select' ),
     12    editAttributeFieldColor      = require( 'sui-views/edit-attribute-field-color' );
    1113
    1214
  • shortcode-ui/trunk/js/src/views/media-frame.js

    r1282644 r1536575  
    113113
    114114    insertAction: function() {
     115        /* Trigger render_destroy */
     116        /*
     117         * Action run before the shortcode overlay is destroyed.
     118         *
     119         * Called as `shortcode-ui.render_destroy`.
     120         *
     121         * @param shortcodeModel (object)
     122         *           Reference to the shortcode model used in this overlay.
     123         */
     124        var hookName = 'shortcode-ui.render_destroy';
     125        var shortcodeModel = this.controller.state().props.get( 'currentShortcode' );
     126        wp.shortcake.hooks.doAction( hookName, shortcodeModel );
     127
    115128        this.controller.state().insert();
     129
    116130    },
    117131
  • shortcode-ui/trunk/js/src/views/shortcode-ui.js

    r1231560 r1536575  
    11var Backbone = require('backbone'),
    22    insertShortcodeList = require('sui-views/insert-shortcode-list'),
    3     ShortcodePreview = require('sui-views/shortcode-preview'),
    43    EditShortcodeForm = require('sui-views/edit-shortcode-form'),
    54    Toolbar = require('sui-views/media-toolbar'),
     
    9695        this.render();
    9796
     97        /* Trigger render_new */
     98        /*
     99         * Action run after a new shortcode overlay is rendered.
     100         *
     101         * Called as `shortcode-ui.render_new`.
     102         *
     103         * @param shortcodeModel (object)
     104         *           Reference to the shortcode model used in this overlay.
     105         */
     106        var hookName = 'shortcode-ui.render_new';
     107        var shortcodeModel = this.controller.props.get( 'currentShortcode' );
     108        wp.shortcake.hooks.doAction( hookName, shortcodeModel );
     109
    98110    },
    99111
  • shortcode-ui/trunk/languages/shortcode-ui.pot

    r1278066 r1536575  
    1 # Copyright (C) 2015 Fusion Engineering and community
     1# Copyright (C) 2016 Fusion Engineering and community
    22# This file is distributed under the GPL v2 or later.
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Shortcake (Shortcode UI) 0.6.0-alpha\n"
     5"Project-Id-Version: Shortcake (Shortcode UI) 0.7.0-alpha\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/shortcode-ui\n"
    7 "POT-Creation-Date: 2015-10-09 18:13:32+00:00\n"
     7"POT-Creation-Date: 2016-04-20 14:44:36+00:00\n"
    88"MIME-Version: 1.0\n"
    99"Content-Type: text/plain; charset=utf-8\n"
    1010"Content-Transfer-Encoding: 8bit\n"
    11 "PO-Revision-Date: 2015-MO-DA HO:MI+ZONE\n"
     11"PO-Revision-Date: 2016-MO-DA HO:MI+ZONE\n"
    1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
    1313"Language-Team: LANGUAGE <LL@li.org>\n"
    14 "X-Generator: grunt-wp-i18n 0.5.3\n"
     14"X-Generator: grunt-wp-i18n 0.5.4\n"
    1515"X-Poedit-KeywordsList: "
    1616"__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
     
    2525"X-Textdomain-Support: yes\n"
    2626
    27 #: dev.php:75
     27#: dev.php:68
     28msgid ""
     29"Shortcode UI plugin must be active for Shortcode UI Example plugin to "
     30"function."
     31msgstr ""
     32
     33#: dev.php:119
     34msgid "Shortcake With No Attributes"
     35msgstr ""
     36
     37#: dev.php:159
    2838msgid "Attachment"
    2939msgstr ""
    3040
    31 #: dev.php:79 dev.php:80
     41#: dev.php:169 dev.php:170
    3242msgid "Select Image"
    3343msgstr ""
    3444
    35 #: dev.php:83
     45#: dev.php:173
    3646msgid "Citation Source"
     47msgstr ""
     48
     49#: dev.php:178
     50msgid "Test placeholder"
     51msgstr ""
     52
     53#: dev.php:183
     54msgid "Select Page"
     55msgstr ""
     56
     57#: dev.php:190
     58msgid "Background Color"
     59msgstr ""
     60
     61#: dev.php:195
     62msgid "Hex color code"
     63msgstr ""
     64
     65#: dev.php:199
     66msgid "Alignment"
     67msgstr ""
     68
     69#: dev.php:200
     70msgid ""
     71"Whether the quotation should be displayed as pull-left, pull-right, or "
     72"neither."
     73msgstr ""
     74
     75#: dev.php:204
     76msgid "None"
     77msgstr ""
     78
     79#: dev.php:205
     80msgid "Pull Left"
     81msgstr ""
     82
     83#: dev.php:206
     84msgid "Pull Right"
     85msgstr ""
     86
     87#: dev.php:210
     88msgid "Year"
     89msgstr ""
     90
     91#: dev.php:211
     92msgid "Optional. The year the quotation is from."
     93msgstr ""
     94
     95#: dev.php:230
     96msgid "Shortcake Dev"
     97msgstr ""
     98
     99#: dev.php:249
     100msgid "Quote"
     101msgstr ""
     102
     103#: dev.php:250
     104msgid "Include a statement from someone famous."
     105msgstr ""
     106
     107#: dev.php:288
     108msgid "Content:"
     109msgstr ""
     110
     111#: dev.php:289
     112msgid "Source:"
     113msgstr ""
     114
     115#: dev.php:290
     116msgid "Image:"
    37117msgstr ""
    38118
     
    41121msgstr ""
    42122
    43 #: inc/class-shortcode-ui.php:220 inc/class-shortcode-ui.php:221
     123#: inc/class-shortcode-ui.php:236 inc/class-shortcode-ui.php:237
    44124msgid "Insert Post Element"
    45125msgstr ""
    46126
    47 #: inc/class-shortcode-ui.php:222
     127#: inc/class-shortcode-ui.php:238
    48128msgid "%s Details"
    49129msgstr ""
    50130
    51 #: inc/class-shortcode-ui.php:223
     131#: inc/class-shortcode-ui.php:239
    52132msgid "Insert Element"
    53133msgstr ""
    54134
    55 #: inc/class-shortcode-ui.php:224
     135#: inc/class-shortcode-ui.php:240
    56136msgid "Update"
    57137msgstr ""
    58138
    59 #: inc/class-shortcode-ui.php:225
     139#: inc/class-shortcode-ui.php:241
    60140msgid "There are no attributes to configure for this Post Element."
    61141msgstr ""
    62142
    63 #: inc/class-shortcode-ui.php:226
     143#: inc/class-shortcode-ui.php:242
    64144msgid "Failed to load preview"
    65145msgstr ""
    66146
    67 #: inc/class-shortcode-ui.php:227
     147#: inc/class-shortcode-ui.php:243
    68148msgid "Search"
    69149msgstr ""
    70150
    71 #: inc/class-shortcode-ui.php:228
     151#: inc/class-shortcode-ui.php:244
    72152msgid "Insert Content"
    73153msgstr ""
    74154
    75 #: inc/class-shortcode-ui.php:323
     155#: inc/class-shortcode-ui.php:339
    76156msgid "Something's rotten in the state of Denmark"
    77157msgstr ""
  • shortcode-ui/trunk/package.json

    r1278066 r1536575  
    1111    "grunt": "^0.4.5",
    1212    "grunt-browserify": "^3.4.0",
    13     "grunt-contrib-jasmine": "^0.8.2",
     13    "grunt-contrib-jasmine": "^1.0.3",
    1414    "grunt-contrib-jshint": "^0.11.2",
    1515    "grunt-contrib-watch": "^0.6.1",
    1616    "grunt-phpcs": "^0.4.0",
    1717    "grunt-postcss": "^0.6.0",
    18     "grunt-sass": "^0.18.0",
     18    "grunt-sass": "^1.1.0",
    1919    "grunt-wp-i18n": "^0.5.0",
    2020    "grunt-wp-readme-to-markdown": "~1.0.0",
  • shortcode-ui/trunk/readme.txt

    r1284972 r1536575  
    11=== Shortcake (Shortcode UI) ===
    2 Contributors: fusionengineering, mattheu, danielbachhuber, zebulonj, goldenapples, jitendraharpalani, sanchothefat, bfintal, davisshaver, garyj, mte90, fredserva, khromov
     2Contributors: fusionengineering, mattheu, danielbachhuber, zebulonj, goldenapples, jitendraharpalani, sanchothefat, bfintal, davisshaver, garyj, mte90, fredserva, khromov, bronsonquick, dashaluna, mehigh, sc0ttkclark, kraftner, pravdomil
    33Tags: shortcodes
    4 Requires at least: 4.1
    5 Tested up to: 4.4
    6 Stable tag: 0.6.2
     4Requires at least: 4.5
     5Tested up to: 4.7
     6Stable tag: 0.7.0
    77License: GPLv2 or later
    88License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    3232Shortcake doesn't support custom key=>value pairs as shortcode attributes because it isn't a great user experience.
    3333
     34== Running tests ==
     35
     36We have test coverage for PHP using PHPunit, and JavaScript using Jasmine.
     37
     38= Running tests locally =
     39
     40Jasmine tests can be run using `grunt jasmine` and are also run as part of the `grunt scripts` task. To update the core WordPress files used by the Jasmine test suite, run `grunt updateJasmineCoreScripts --abspath="/path/to/wordpress-install"`.
    3441
    3542== Screenshots ==
     
    5158
    5259== Changelog ==
     60
     61= 0.7.0 (November 18, 2016) =
     62* Adds "Add post element" button to media buttons - one click to open the shortcode list, rather than clicking "Add media" button and then finding "insert post element" in the menu.
     63* Added "Term Select" field type.
     64* Added "User Select" field type.
     65* Added new hooks that fire on rendering/editing/closing a shortcode, which can be used for field types which require custom javascript initialization or cleanup.
     66* Select fields: add full support for multiple select fields.
     67* Select fields: support custom ordering of options.
     68* Select fields: support grouping option in `<optgroup>`s by passing them as a nested array.
     69* Attachment fields: support multiple selection.
     70* Attachment fields: support SVG images (if svg uploads are enabled by a plugin or theme).
     71* Bug fix: Handle percent signs when decoding fields with `encode=true` specified.
     72* Bug fix: fix issue where it takes two clicks on a shortcode in editor to bring up the Edit Shortcode modal.
     73* Bug fix: fix issue when searching for shortcodes by name where if multiple shortcodes start with the search string, only the first is returned.
     74* Bug fix: only output a description field on an attribute if it's not empty.
     75* Compatability: Remove shims for handling the media modal in WP 4.1 and 4.2.
     76* Compatability: Upgrade Select2 library to 4.0.3 to avoid conflicts with other plugins which use the latest version of Select2.
     77* Added Turkish translation.
     78* Added Finnish translation.
     79* Added Swedish translation.
     80* Added Hungarian translation.
    5381
    5482= 0.6.2 (November 12, 2015) =
  • shortcode-ui/trunk/shortcode-ui.php

    r1284972 r1536575  
    22/**
    33 * Plugin Name: Shortcake (Shortcode UI)
    4  * Version: 0.6.2
     4 * Version: 0.7.0
    55 * Description: User Interface for adding shortcodes.
    66 * Author: Fusion Engineering and community
     
    2020 */
    2121
    22 define( 'SHORTCODE_UI_VERSION', '0.6.2' );
     22define( 'SHORTCODE_UI_VERSION', '0.7.0-alpha' );
    2323
    2424require_once dirname( __FILE__ ) . '/inc/class-shortcode-ui.php';
     
    2727require_once dirname( __FILE__ ) . '/inc/fields/class-field-color.php';
    2828require_once dirname( __FILE__ ) . '/inc/fields/class-field-post-select.php';
     29require_once dirname( __FILE__ ) . '/inc/fields/class-field-term-select.php';
     30require_once dirname( __FILE__ ) . '/inc/fields/class-field-user-select.php';
    2931
    3032add_action( 'init', 'shortcode_ui_load_textdomain' );
     
    4345    $color_field      = Shortcake_Field_Color::get_instance();
    4446    $post_field       = Shortcode_UI_Field_Post_Select::get_instance();
     47    $term_field       = Shortcode_UI_Field_Term_Select::get_instance();
     48    $user_field       = Shortcode_UI_Field_User_Select::get_instance();
    4549}
    4650
     
    5963    // Load the textdomain according to the plugin first
    6064    $mofile = $domain . '-' . $locale . '.mo';
    61     if ( $loaded = load_textdomain( $domain, $path . '/'. $mofile ) ) {
     65    if ( $loaded = load_textdomain( $domain, $path . '/' . $mofile ) ) {
    6266        return;
    6367    }
Note: See TracChangeset for help on using the changeset viewer.