Shortcake (Shortcode UI) - Version 0.6.0

Version Description

(November 2, 2015) = * Supports an optional encode=true argument for attributes, to allow limited HTML support. Attributes need to be run through shortcode_atts() in order to be properly decoded. * Defines a SHORTCODE_UI_DOING_PREVIEW constant when rendering a shortcode preview, which enables callbacks to serve a different representation of the shortcode in TinyMCE. * When an attachment is already selected for a shortcode attribute, opening media library will include it selected. * Cleaned up icon vertical alignment in the Insert Post Element UI. * Added CSS utility classes to all field HTML. For instance, the attachment field is now wrapped with shortcode-ui-field-attachment. * Added filters to modify shortcode UI arguments on registration. * Cleaned up the example plugin, so it's a much more useful developer reference. * Uses core's JavaScript regex for parsing shortcodes, instead of maintaining separate regex. * Permits HTML in field labels and descriptions. * Added Danish translation. * Added Italian translation. * Added German translation. * Core integration: Fully supports PHP 5.2. * Bug fix: Persists shortcode attributes and inner content when there isn't UI registered for them. Previously, they would be discarded. * Bug fix: Display the description on the post select field. * Bug fix: Attribute field change event binds to input event rather than keyup. * Full release notes

Download this release

Release Info

Developer danielbachhuber
Plugin Icon 128x128 Shortcake (Shortcode UI)
Version 0.6.0
Comparing to
See all releases

Code changes from version 0.5.0 to 0.6.0

Gruntfile.js CHANGED
@@ -20,6 +20,19 @@ module.exports = function( grunt ) {
20
  }
21
  },
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  watch: {
24
 
25
  styles: {
@@ -125,6 +138,7 @@ module.exports = function( grunt ) {
125
  'js-tests/vendor/jquery.js',
126
  'js-tests/vendor/underscore.js',
127
  'js-tests/vendor/backbone.js',
 
128
  'js-tests/vendor/wp-util.js',
129
  'js-tests/vendor/wp-editors.js',
130
  'js-tests/vendor/mock-ajax.js',
@@ -150,7 +164,7 @@ module.exports = function( grunt ) {
150
  'README.md': 'readme.txt'
151
  },
152
  options: {
153
- screenshot_url: 'http://s.wordpress.org/extend/plugins/shortcode-ui/{screenshot}.png',
154
  }
155
  },
156
  },
@@ -173,6 +187,7 @@ module.exports = function( grunt ) {
173
  } );
174
 
175
  grunt.loadNpmTasks( 'grunt-sass' );
 
176
  grunt.loadNpmTasks( 'grunt-contrib-watch' );
177
  grunt.loadNpmTasks( 'grunt-browserify' );
178
  grunt.loadNpmTasks( 'grunt-phpcs' );
@@ -182,7 +197,7 @@ module.exports = function( grunt ) {
182
  grunt.loadNpmTasks( 'grunt-contrib-jshint' );
183
 
184
  grunt.registerTask( 'scripts', [ 'browserify', 'jasmine', 'jshint' ] );
185
- grunt.registerTask( 'styles', [ 'sass' ] );
186
  grunt.registerTask( 'default', [ 'scripts', 'styles' ] );
187
  grunt.registerTask( 'i18n', ['addtextdomain', 'makepot'] );
188
  grunt.registerTask( 'readme', ['wp_readme_to_markdown']);
20
  }
21
  },
22
 
23
+ // Autoprefix
24
+ postcss: {
25
+ options: {
26
+ map: true, // inline sourcemaps
27
+ processors: [
28
+ require('autoprefixer')(),
29
+ ]
30
+ },
31
+ dist: {
32
+ src: 'css/*.css'
33
+ }
34
+ },
35
+
36
  watch: {
37
 
38
  styles: {
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',
164
  'README.md': 'readme.txt'
165
  },
166
  options: {
167
+ screenshot_url: 'https://s.w.org/plugins/shortcode-ui/{screenshot}.png',
168
  }
169
  },
170
  },
187
  } );
188
 
189
  grunt.loadNpmTasks( 'grunt-sass' );
190
+ grunt.loadNpmTasks( 'grunt-postcss' );
191
  grunt.loadNpmTasks( 'grunt-contrib-watch' );
192
  grunt.loadNpmTasks( 'grunt-browserify' );
193
  grunt.loadNpmTasks( 'grunt-phpcs' );
197
  grunt.loadNpmTasks( 'grunt-contrib-jshint' );
198
 
199
  grunt.registerTask( 'scripts', [ 'browserify', 'jasmine', 'jshint' ] );
200
+ grunt.registerTask( 'styles', [ 'sass', 'postcss' ] );
201
  grunt.registerTask( 'default', [ 'scripts', 'styles' ] );
202
  grunt.registerTask( 'i18n', ['addtextdomain', 'makepot'] );
203
  grunt.registerTask( 'readme', ['wp_readme_to_markdown']);
css/sass/shortcode-ui.scss CHANGED
@@ -20,10 +20,8 @@
20
  padding: 0 10px;
21
 
22
  .shortcode-list-item {
23
-
24
  margin: 10px;
25
  float: left;
26
-
27
  -webkit-box-shadow: inset 0 0 15px rgba( 0, 0, 0, 0.1 ), inset 0 0 0 1px rgba( 0, 0, 0, 0.1 );
28
  box-shadow: inset 0 0 15px rgba( 0, 0, 0, 0.1 ), inset 0 0 0 1px rgba( 0, 0, 0, 0.1 );
29
  background: #eee;
@@ -34,30 +32,35 @@
34
  height: 150px;
35
 
36
  .add-shortcode-list-item-icon {
37
-
 
38
  font-size: 64px;
39
- line-height: 150px;
40
- vertical-align: middle;
41
 
42
- .dashicons {
43
- display: inline-block;
 
 
 
 
44
  font-size: inherit;
45
  line-height: inherit;
46
  width: auto;
47
  height: auto;
48
- position: relative;
49
- top: -14px;
50
  }
51
 
52
  }
53
 
54
  .add-shortcode-list-item-title {
55
- margin: 0;
56
- padding: 5px;
57
  position: absolute;
58
- left: 0;
59
- right: 0;
60
  bottom: 0;
 
 
 
 
 
61
  overflow: hidden;
62
  max-height: 100%;
63
  word-wrap: break-word;
20
  padding: 0 10px;
21
 
22
  .shortcode-list-item {
 
23
  margin: 10px;
24
  float: left;
 
25
  -webkit-box-shadow: inset 0 0 15px rgba( 0, 0, 0, 0.1 ), inset 0 0 0 1px rgba( 0, 0, 0, 0.1 );
26
  box-shadow: inset 0 0 15px rgba( 0, 0, 0, 0.1 ), inset 0 0 0 1px rgba( 0, 0, 0, 0.1 );
27
  background: #eee;
32
  height: 150px;
33
 
34
  .add-shortcode-list-item-icon {
35
+ position: relative;
36
+ height: 120px;
37
  font-size: 64px;
 
 
38
 
39
+ .dashicons,
40
+ img {
41
+ position: absolute;
42
+ top: 50%;
43
+ left: 50%;
44
+ transform: translate(-50%, -50%);
45
  font-size: inherit;
46
  line-height: inherit;
47
  width: auto;
48
  height: auto;
49
+ max-width: 80%;
50
+ max-height: 80%;
51
  }
52
 
53
  }
54
 
55
  .add-shortcode-list-item-title {
56
+ box-sizing: border-box;
 
57
  position: absolute;
 
 
58
  bottom: 0;
59
+ left: 0;
60
+ width: 100%;
61
+ margin: 0;
62
+ line-height: 1.2;
63
+ padding: 8px;
64
  overflow: hidden;
65
  max-height: 100%;
66
  word-wrap: break-word;
css/shortcode-ui-editor-styles.css CHANGED
@@ -12,5 +12,4 @@ body#wpview-iframe-sandbox {
12
  display: inline-block;
13
  width: 100%;
14
  overflow: hidden; }
15
-
16
  /*# sourceMappingURL=shortcode-ui-editor-styles.css.map */
12
  display: inline-block;
13
  width: 100%;
14
  overflow: hidden; }
 
15
  /*# sourceMappingURL=shortcode-ui-editor-styles.css.map */
css/shortcode-ui-editor-styles.css.map CHANGED
@@ -1,10 +1 @@
1
- {
2
- "version": 3,
3
- "file": "shortcode-ui-editor-styles.css",
4
- "sources": [
5
- "../shortcode-ui-editor-styles.scss"
6
- ],
7
- "sourcesContent": [],
8
- "mappings": "AAGA,AAAY,AAA0B;EACnC,AAAS;AAIZ,AAAa;EACX,AAAO;EACP,AAAa;AAGf,AAAa;EACX,AAAa;EACb,AAAO;EACP,AAAW;;AAIb,AAAI;EACH,AAAS;EACT,AAAO;EACP,AAAU",
9
- "names": []
10
- }
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"}
 
 
 
 
 
 
 
 
 
css/shortcode-ui.css CHANGED
@@ -13,7 +13,6 @@
13
  .add-shortcode-list .shortcode-list-item {
14
  margin: 10px;
15
  float: left;
16
- -webkit-box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.1), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
17
  box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.1), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
18
  background: #eee;
19
  cursor: pointer;
@@ -22,31 +21,37 @@
22
  width: 150px;
23
  height: 150px; }
24
  .add-shortcode-list .shortcode-list-item .add-shortcode-list-item-icon {
25
- font-size: 64px;
26
- line-height: 150px;
27
- vertical-align: middle; }
28
- .add-shortcode-list .shortcode-list-item .add-shortcode-list-item-icon .dashicons {
29
- display: inline-block;
 
 
 
 
 
30
  font-size: inherit;
31
  line-height: inherit;
32
  width: auto;
33
  height: auto;
34
- position: relative;
35
- top: -14px; }
36
  .add-shortcode-list .shortcode-list-item .add-shortcode-list-item-title {
37
- margin: 0;
38
- padding: 5px;
39
  position: absolute;
40
- left: 0;
41
- right: 0;
42
  bottom: 0;
 
 
 
 
 
43
  overflow: hidden;
44
  max-height: 100%;
45
  word-wrap: break-word;
46
  text-align: center;
47
  font-weight: bold;
48
  background: rgba(255, 255, 255, 0.8);
49
- -webkit-box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15);
50
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15); }
51
 
52
  .shortcode-ui-content .edit-shortcode-tabs {
@@ -68,7 +73,6 @@
68
  clear: both; }
69
  .edit-shortcode-form input, .edit-shortcode-form textarea {
70
  border: 1px solid #ddd;
71
- -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.07);
72
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.07);
73
  background-color: #fff;
74
  color: #333;
@@ -77,7 +81,6 @@
77
  transition: 0.05s border-color ease-in-out;
78
  max-width: 100%; }
79
  .edit-shortcode-form input[type="range"] {
80
- -webkit-box-shadow: none;
81
  box-shadow: none; }
82
  .edit-shortcode-form output.range {
83
  display: inline-block;
@@ -112,7 +115,8 @@
112
  display: none; }
113
  .edit-shortcode-form .shortcake-attachment-preview .thumbnail:hover:after {
114
  background: rgba(0, 0, 0, 0.1);
115
- transition: all .3s linear; }
 
116
  .edit-shortcode-form .shortcake-attachment-preview:not(.has-attachment) {
117
  border: 2px dashed #DDD;
118
  border-radius: 2px;
@@ -195,5 +199,4 @@
195
 
196
  100% {
197
  margin-left: 60px; } }
198
-
199
  /*# sourceMappingURL=shortcode-ui.css.map */
13
  .add-shortcode-list .shortcode-list-item {
14
  margin: 10px;
15
  float: left;
 
16
  box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.1), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
17
  background: #eee;
18
  cursor: pointer;
21
  width: 150px;
22
  height: 150px; }
23
  .add-shortcode-list .shortcode-list-item .add-shortcode-list-item-icon {
24
+ position: relative;
25
+ height: 120px;
26
+ 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
+ position: absolute;
29
+ top: 50%;
30
+ left: 50%;
31
+ -webkit-transform: translate(-50%, -50%);
32
+ -ms-transform: translate(-50%, -50%);
33
+ transform: translate(-50%, -50%);
34
  font-size: inherit;
35
  line-height: inherit;
36
  width: auto;
37
  height: auto;
38
+ max-width: 80%;
39
+ max-height: 80%; }
40
  .add-shortcode-list .shortcode-list-item .add-shortcode-list-item-title {
41
+ box-sizing: border-box;
 
42
  position: absolute;
 
 
43
  bottom: 0;
44
+ left: 0;
45
+ width: 100%;
46
+ margin: 0;
47
+ line-height: 1.2;
48
+ padding: 8px;
49
  overflow: hidden;
50
  max-height: 100%;
51
  word-wrap: break-word;
52
  text-align: center;
53
  font-weight: bold;
54
  background: rgba(255, 255, 255, 0.8);
 
55
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15); }
56
 
57
  .shortcode-ui-content .edit-shortcode-tabs {
73
  clear: both; }
74
  .edit-shortcode-form input, .edit-shortcode-form textarea {
75
  border: 1px solid #ddd;
 
76
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.07);
77
  background-color: #fff;
78
  color: #333;
81
  transition: 0.05s border-color ease-in-out;
82
  max-width: 100%; }
83
  .edit-shortcode-form input[type="range"] {
 
84
  box-shadow: none; }
85
  .edit-shortcode-form output.range {
86
  display: inline-block;
115
  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;
199
 
200
  100% {
201
  margin-left: 60px; } }
 
202
  /*# sourceMappingURL=shortcode-ui.css.map */
css/shortcode-ui.css.map CHANGED
@@ -1,11 +1 @@
1
- {
2
- "version": 3,
3
- "file": "shortcode-ui.css",
4
- "sources": [
5
- "../shortcode-ui.scss",
6
- "../_field-image.scss"
7
- ],
8
- "sourcesContent": [],
9
- "mappings": "AAAA,AAAY,AAAO;EAClB,AAAc;;AAKf,AAA2B;EACzB,AAAW;EACX,AAAY;EACZ,AAAQ;AAGV,AAA2B;EACzB,AAAK;;AAKP;EACC,AAAS;EAEV,AAAoB;IAElB,AAAQ;IACR,AAAO;IAEP,AAAsD;IACtD,AAA8C;IAC9C,AAAY;IACZ,AAAQ;IACR,AAAU;IACV,AAAY;IACZ,AAAO;IACP,AAAQ;IAEV,AAAoB,AAAqB;MAEtC,AAAW;MACX,AAAa;MACb,AAAgB;MAEnB,AAAoB,AAAqB,AAA8B;QACnE,AAAS;QACT,AAAW;QACX,AAAa;QACb,AAAO;QACP,AAAQ;QACR,AAAU;QACV,AAAK;IAKT,AAAoB,AAAqB;MACtC,AAAQ;MACR,AAAS;MACT,AAAU;MACV,AAAM;MACN,AAAO;MACP,AAAQ;MACR,AAAU;MACV,AAAY;MACZ,AAAW;MACX,AAAY;MACZ,AAAa;MACb,AAAY;MACZ,AAAoB;MACpB,AAAY;;AAOf,AAAsB;EACpB,AAAQ;EACR,AAAS;AAGX,AAAsB;EACpB,AAAS;EACT,AAAY;AAGd,AAAsB,AAAC;EACrB,AAAe;AAGjB,AAAsB;EACpB,AAAU;EACV,AAAQ;;AAIV;EAEC,AAAS;EAEV,AAAqB;IACnB,AAAS;IACT,AAAO;EAGT,AAAqB,AAAO,AAAqB;IAE/C,AAAQ;IACR,AAAoB;IACpB,AAAY;IACZ,AAAkB;IAClB,AAAO;IACP,AAAS;IACT,AAAoB;IACpB,AAAY;IACZ,AAAW;EAGb,AAAqB,AAAK;IACxB,AAAoB;IACpB,AAAY;EAGd,AAAqB,AAAM;IACzB,AAAS;IACT,AAAS;IACT,AAAgB;EAGlB,AAAqB;IACnB,AAAO;IACP,AAAW;IACX,AAAY;EAId,AAAqB,AAA8B;IAAzC,AAAe;EAGzB,AAAqB;IACnB,AAAS;IACX,AAAqB,AAAa;MAC/B,AAAS;MACT,AAAe;EAIlB,AAAqB;IAInB,AAAa;IAHf,AAAqB,AAAc;MAChC,AAAS;EAKZ,AAAqB;IACnB,AAAO;;ACzJT,AAAqB;EAEpB,AAAO;EACP,AAAQ;EACR,AAAQ;EACR,AAAa;EACb,AAAY;EACZ,AAAS;EAEV,AAAqB,AAA6B;IAChD,AAAS;EAGX,AAAqB,AAA8B,AAAU,AAAM;IACjE,AAAY;IACZ,AAAY;EAGd,AAAqB,AAA6B,AAAK;IACrD,AAAQ;IACR,AAAe;IACf,AAAY;IACZ,AAAY;EAGd,AAAqB,AAA8B,AAAO;IACxD,AAAgB;IAChB,AAAS;EAGX,AAAqB,AAA8B,AAAO;IAExD,AAAS;IACT,AAAS;IACT,AAAU;IACV,AAAK;IACL,AAAO;IACP,AAAQ;IACR,AAAY;IACZ,AAAa;IACb,AAAY;IACZ,AAAO;IACP,AAAQ;IACR,AAAS;IACT,AAAS;IAEX,AAAqB,AAA8B,AAAO,AAAO;MAC9D,AAAS;MACT,AAAU;MACV,AAAK;MACL,AAAM;MACN,AAAW;MACX,AAAa;EAIhB,AAAqB,AAA8B,AAAoB,AAAqB,AAA6B,AAAS,AAAO;IAEvI,AAAS;EAGX,AAAqB,AAA6B,AAAS;IACzD,AAAS;IACT,AAAU;IACV,AAAO;IACP,AAAQ;EAIV,AAAqB,AAA8B,AAAmB;IACnE,AAAW;IACX,AAAQ;IACR,AAAa;IACb,AAAO;IACP,AAAY;IACZ,AAAgB;EAEnB,AAAqB,AAA8B,AAAmB;IACnE,AAAO;IACP,AAAQ;IACR,AAAU;IACV,AAAkB;IAClB,AAAQ;IAEX,AAAqB,AAA8B,AAAmB,AAA4B;MAC9F,AAAkB;MAClB,AAAQ;MACR,AAAO;MACP,AAAQ;MACR,AAAS;MACT,AAAmB;MACnB,AAAW;EAKf,AAAqB,AAA8B;IACjD,AAAa;EAIf,AAAqB,AAA6B,AAAgB,AAAO;IACtE,AAAS;EAEZ,AAAqB,AAA6B,AAAgB,AAAO;IACtE,AAAS;;AAMZ,AAAqB;EACpB,AAAS;EAEV,AAAqB,AAA4B;IAC/C,AAAS;;mBAIQ;EACnB;IACE,AAAa;;EAEf;IACE,AAAa;;WAIJ;EACX;IACE,AAAa;;EAEf;IACE,AAAa",
10
- "names": []
11
- }
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"}
 
 
 
 
 
 
 
 
 
 
inc/class-shortcode-ui.php CHANGED
@@ -65,10 +65,10 @@ class Shortcode_UI {
65
  * Setup plugin actions.
66
  */
67
  private function setup_actions() {
68
- add_action( 'admin_enqueue_scripts', array( $this, 'action_admin_enqueue_scripts' ) );
69
- add_action( 'wp_enqueue_editor', array( $this, 'action_wp_enqueue_editor' ) );
70
- add_action( 'wp_ajax_do_shortcode', array( $this, 'handle_ajax_do_shortcode' ) );
71
- add_filter( 'wp_editor_settings', array( $this, 'filter_wp_editor_settings' ), 10, 2 );
72
  }
73
 
74
  /**
@@ -118,6 +118,9 @@ class Shortcode_UI {
118
  $args['shortcode_tag'] = $shortcode_tag;
119
  $this->shortcodes[ $shortcode_tag ] = $args;
120
 
 
 
 
121
  }
122
 
123
  /**
@@ -133,7 +136,27 @@ class Shortcode_UI {
133
  *
134
  * @param array $shortcodes
135
  */
136
- return apply_filters( 'shortcode_ui_shortcodes', $this->shortcodes );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  }
138
 
139
  /**
@@ -197,16 +220,15 @@ class Shortcode_UI {
197
  wp_localize_script( 'shortcode-ui', ' shortcodeUIData', array(
198
  'shortcodes' => $shortcodes,
199
  'strings' => array(
200
- 'media_frame_title' => esc_html__( 'Insert Post Element', 'shortcode-ui' ),
201
- 'media_frame_menu_insert_label' => esc_html__( 'Insert Post Element', 'shortcode-ui' ),
202
- 'media_frame_menu_update_label' => esc_html__( '%s Details', 'shortcode-ui' ), // Substituted in JS
203
- 'media_frame_toolbar_insert_label' => esc_html__( 'Insert Element', 'shortcode-ui' ),
204
- 'media_frame_toolbar_update_label' => esc_html__( 'Update', 'shortcode-ui' ),
205
- 'media_frame_no_attributes_message' => esc_html__( 'There are no attributes to configure for this Post Element.', 'shortcode-ui' ),
206
- 'edit_tab_label' => esc_html__( 'Edit', 'shortcode-ui' ),
207
- 'mce_view_error' => esc_html__( 'Failed to load preview', 'shortcode-ui' ),
208
- 'search_placeholder' => esc_html__( 'Search', 'shortcode-ui' ),
209
- 'insert_content_label' => esc_html__( 'Insert Content', 'shortcode-ui' ),
210
  ),
211
  'nonces' => array(
212
  'preview' => wp_create_nonce( 'shortcode-ui-preview' ),
@@ -292,25 +314,16 @@ class Shortcode_UI {
292
  }
293
 
294
  /**
295
- * Render a shortcode for preview in the TinyMCE editor.
296
  */
297
- public function handle_ajax_do_shortcode() {
298
 
299
- // Don't sanitize shortcodes — can contain HTML kses doesn't allow (e.g. sourcecode shortcode)
300
- if ( ! empty( $_POST['shortcode'] ) ) {
301
- $shortcode = stripslashes( $_POST['shortcode'] );
302
- } else {
303
- $shortcode = null;
304
- }
305
- if ( isset( $_POST['post_id'] ) ) {
306
- $post_id = intval( $_POST['post_id'] );
307
- } else {
308
- $post_id = null;
309
  }
310
 
311
- if ( ! current_user_can( 'edit_post', $post_id ) || ! wp_verify_nonce( $_POST['nonce'], 'shortcode-ui-preview' ) ) {
312
- echo esc_html__( "Something's rotten in the state of Denmark", 'shortcode-ui' );
313
- exit;
314
  }
315
 
316
  if ( ! empty( $post_id ) ) {
@@ -318,7 +331,7 @@ class Shortcode_UI {
318
  global $post;
319
  $post = get_post( $post_id );
320
  setup_postdata( $post );
321
- // @codingStandardsIgnoreStart
322
  }
323
 
324
  ob_start();
@@ -336,7 +349,76 @@ class Shortcode_UI {
336
  */
337
  do_action( 'shortcode_ui_after_do_shortcode', $shortcode );
338
 
339
- wp_send_json_success( ob_get_clean() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
 
341
  }
342
 
65
  * Setup plugin actions.
66
  */
67
  private function setup_actions() {
68
+ add_action( 'admin_enqueue_scripts', array( $this, 'action_admin_enqueue_scripts' ) );
69
+ add_action( 'wp_enqueue_editor', array( $this, 'action_wp_enqueue_editor' ) );
70
+ add_action( 'wp_ajax_bulk_do_shortcode', array( $this, 'handle_ajax_bulk_do_shortcode' ) );
71
+ add_filter( 'wp_editor_settings', array( $this, 'filter_wp_editor_settings' ), 10, 2 );
72
  }
73
 
74
  /**
118
  $args['shortcode_tag'] = $shortcode_tag;
119
  $this->shortcodes[ $shortcode_tag ] = $args;
120
 
121
+ // Setup filter to handle decoding encoded attributes.
122
+ add_filter( "shortcode_atts_{$shortcode_tag}", array( $this, 'filter_shortcode_atts_decode_encoded' ), 5, 3 );
123
+
124
  }
125
 
126
  /**
136
  *
137
  * @param array $shortcodes
138
  */
139
+ $shortcodes = apply_filters( 'shortcode_ui_shortcodes', $this->shortcodes );
140
+
141
+ foreach ( $shortcodes as $shortcode => $args ) {
142
+
143
+ foreach ( $args['attrs'] as $key => $value ) {
144
+ foreach ( array( 'label', 'description' ) as $field ) {
145
+ if ( ! empty( $value[ $field ] ) ) {
146
+ $shortcodes[ $shortcode ]['attrs'][ $key ][ $field ] = wp_kses_post( $value[ $field ] );
147
+ }
148
+ }
149
+ }
150
+
151
+ foreach ( array( 'label', 'description' ) as $field ) {
152
+ if ( ! empty( $args['inner_content'][ $field ] ) ) {
153
+ $shortcodes[ $shortcode ]['inner_content'][ $field ] = wp_kses_post( $args['inner_content'][ $field ] );
154
+ }
155
+ }
156
+
157
+ }
158
+
159
+ return $shortcodes;
160
  }
161
 
162
  /**
220
  wp_localize_script( 'shortcode-ui', ' shortcodeUIData', array(
221
  'shortcodes' => $shortcodes,
222
  'strings' => array(
223
+ 'media_frame_title' => __( 'Insert Post Element', 'shortcode-ui' ),
224
+ 'media_frame_menu_insert_label' => __( 'Insert Post Element', 'shortcode-ui' ),
225
+ 'media_frame_menu_update_label' => __( '%s Details', 'shortcode-ui' ), // Substituted in JS
226
+ 'media_frame_toolbar_insert_label' => __( 'Insert Element', 'shortcode-ui' ),
227
+ 'media_frame_toolbar_update_label' => __( 'Update', 'shortcode-ui' ),
228
+ 'media_frame_no_attributes_message' => __( 'There are no attributes to configure for this Post Element.', 'shortcode-ui' ),
229
+ 'mce_view_error' => __( 'Failed to load preview', 'shortcode-ui' ),
230
+ 'search_placeholder' => __( 'Search', 'shortcode-ui' ),
231
+ 'insert_content_label' => __( 'Insert Content', 'shortcode-ui' ),
 
232
  ),
233
  'nonces' => array(
234
  'preview' => wp_create_nonce( 'shortcode-ui-preview' ),
314
  }
315
 
316
  /**
317
+ * Render a shortcode body for preview.
318
  */
319
+ private function render_shortcode_for_preview( $shortcode, $post_id = null ) {
320
 
321
+ if ( ! defined( 'SHORTCODE_UI_DOING_PREVIEW' ) ) {
322
+ define( 'SHORTCODE_UI_DOING_PREVIEW', true );
 
 
 
 
 
 
 
 
323
  }
324
 
325
+ if ( ! current_user_can( 'edit_post', $post_id ) ) {
326
+ return esc_html__( "Something's rotten in the state of Denmark", 'shortcode-ui' );
 
327
  }
328
 
329
  if ( ! empty( $post_id ) ) {
331
  global $post;
332
  $post = get_post( $post_id );
333
  setup_postdata( $post );
334
+ // @codingStandardsIgnoreEnd
335
  }
336
 
337
  ob_start();
349
  */
350
  do_action( 'shortcode_ui_after_do_shortcode', $shortcode );
351
 
352
+ return ob_get_clean();
353
+ }
354
+
355
+ /**
356
+ * Get a bunch of shortcodes to render in MCE preview.
357
+ */
358
+ public function handle_ajax_bulk_do_shortcode() {
359
+
360
+ if ( is_array( $_POST['queries'] ) ) {
361
+
362
+ $responses = array();
363
+
364
+ foreach ( $_POST['queries'] as $posted_query ) {
365
+
366
+ // Don't sanitize shortcodes — can contain HTML kses doesn't allow (e.g. sourcecode shortcode)
367
+ if ( ! empty( $posted_query['shortcode'] ) ) {
368
+ $shortcode = stripslashes( $posted_query['shortcode'] );
369
+ } else {
370
+ $shortcode = null;
371
+ }
372
+ if ( isset( $posted_query['post_id'] ) ) {
373
+ $post_id = intval( $posted_query['post_id'] );
374
+ } else {
375
+ $post_id = null;
376
+ }
377
+
378
+ $responses[ $posted_query['counter'] ] = array(
379
+ 'query' => $posted_query,
380
+ 'response' => $this->render_shortcode_for_preview( $shortcode, $post_id ),
381
+ );
382
+ }
383
+
384
+ wp_send_json_success( $responses );
385
+ exit;
386
+ }
387
+
388
+ }
389
+
390
+ /**
391
+ * Decode any encoded attributes.
392
+ *
393
+ * @param array $out The output array of shortcode attributes.
394
+ * @param array $pairs The supported attributes and their defaults.
395
+ * @param array $atts The user defined shortcode attributes.
396
+ * @return array $out The output array of shortcode attributes.
397
+ */
398
+ public function filter_shortcode_atts_decode_encoded( $out, $pairs, $atts ) {
399
+
400
+ // Get current shortcode tag from the current filter
401
+ // by stripping `shortcode_atts_` from start of string.
402
+ $shortcode_tag = substr( current_filter(), 15 );
403
+
404
+ if ( ! isset( $this->shortcodes[ $shortcode_tag ] ) ) {
405
+ return $out;
406
+ }
407
+
408
+ $fields = Shortcode_UI_Fields::get_instance()->get_fields();
409
+ $args = $this->shortcodes[ $shortcode_tag ];
410
+
411
+ foreach ( $args['attrs'] as $attr ) {
412
+
413
+ $default = isset( $fields[ $attr['type'] ]['encode'] ) ? $fields[ $attr['type'] ]['encode'] : false;
414
+ $encoded = isset( $attr['encode'] ) ? $attr['encode'] : $default;
415
+
416
+ if ( $encoded && isset( $out[ $attr['attr'] ] ) ) {
417
+ $out[ $attr['attr'] ] = rawurldecode( $out[ $attr['attr'] ] );
418
+ }
419
+ }
420
+
421
+ return $out;
422
 
423
  }
424
 
inc/fields/class-field-attachment.php CHANGED
@@ -90,8 +90,8 @@ class Shortcake_Field_Attachment {
90
  ?>
91
 
92
  <script type="text/html" id="tmpl-fusion-shortcake-field-attachment">
93
- <div class="field-block">
94
- <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>
@@ -109,7 +109,7 @@ class Shortcake_Field_Attachment {
109
  <div class="edit-link"><a href="#"><?php esc_html_e( 'Edit Attachment', 'shortcode-ui' ); ?></a></div>
110
  </div>
111
  <# if ( typeof data.description == 'string' ) { #>
112
- <p class="description">{{ data.description }}</p>
113
  <# } #>
114
  </div>
115
  </script>
90
  ?>
91
 
92
  <script type="text/html" id="tmpl-fusion-shortcake-field-attachment">
93
+ <div class="field-block shortcode-ui-field-attachment shortcode-ui-attribute-{{ data.attr }}">
94
+ <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>
109
  <div class="edit-link"><a href="#"><?php esc_html_e( 'Edit Attachment', 'shortcode-ui' ); ?></a></div>
110
  </div>
111
  <# if ( typeof data.description == 'string' ) { #>
112
+ <p class="description">{{{ data.description }}}</p>
113
  <# } #>
114
  </div>
115
  </script>
inc/fields/class-field-color.php CHANGED
@@ -109,11 +109,11 @@ class Shortcake_Field_Color {
109
  ?>
110
 
111
  <script type="text/html" id="tmpl-fusion-shortcake-field-color">
112
- <div class="field-block">
113
- <label for="{{ data.attr }}">{{ data.label }}</label>
114
  <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' ) { #>
116
- <p class="description">{{ data.description }}</p>
117
  <# } #>
118
  </div>
119
  </script>
109
  ?>
110
 
111
  <script type="text/html" id="tmpl-fusion-shortcake-field-color">
112
+ <div class="field-block shortcode-ui-field-color shortcode-ui-attribute-{{ data.attr }}">
113
+ <label for="{{ data.attr }}">{{{ data.label }}}</label>
114
  <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' ) { #>
116
+ <p class="description">{{{ data.description }}}</p>
117
  <# } #>
118
  </div>
119
  </script>
inc/fields/class-field-post-select.php CHANGED
@@ -52,7 +52,6 @@ class Shortcode_UI_Field_Post_Select {
52
  /**
53
  * Output styles and templates used by post select field.
54
  */
55
- // public function action_print_media_templates() {
56
  public function action_shortcode_ui_loaded_editor() {
57
 
58
  ?>
@@ -75,9 +74,12 @@ class Shortcode_UI_Field_Post_Select {
75
  </style>
76
 
77
  <script type="text/html" id="tmpl-shortcode-ui-field-post-select">
78
- <div class="field-block">
79
- <label for="{{ data.id }}">{{ data.label }}</label>
80
  <input type="text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" class="shortcode-ui-post-select" />
 
 
 
81
  </div>
82
  </script>
83
 
52
  /**
53
  * Output styles and templates used by post select field.
54
  */
 
55
  public function action_shortcode_ui_loaded_editor() {
56
 
57
  ?>
74
  </style>
75
 
76
  <script type="text/html" id="tmpl-shortcode-ui-field-post-select">
77
+ <div class="field-block shortcode-ui-field-post-select shortcode-ui-attribute-{{ data.attr }}">
78
+ <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' ) { #>
81
+ <p class="description">{{{ data.description }}}</p>
82
+ <# } #>
83
  </div>
84
  </script>
85
 
inc/fields/class-shortcode-ui-fields.php CHANGED
@@ -22,6 +22,7 @@ class Shortcode_UI_Fields {
22
  private $field_defaults = array(
23
  'template' => 'shortcode-ui-field-text',
24
  'view' => 'editAttributeField',
 
25
  );
26
 
27
  /**
@@ -96,10 +97,11 @@ class Shortcode_UI_Fields {
96
  $this->fields = apply_filters( 'shortcode_ui_fields', $this->fields );
97
 
98
  // set default args for each field.
99
- $field_defaults = $this->field_defaults;
100
- $this->fields = array_map( function( $args ) use ( $field_defaults ) {
101
- return wp_parse_args( $args, $field_defaults );
102
- }, $this->fields );
 
103
 
104
  }
105
 
22
  private $field_defaults = array(
23
  'template' => 'shortcode-ui-field-text',
24
  'view' => 'editAttributeField',
25
+ 'encode' => false,
26
  );
27
 
28
  /**
97
  $this->fields = apply_filters( 'shortcode_ui_fields', $this->fields );
98
 
99
  // set default args for each field.
100
+ $array_map = array();
101
+ foreach ($this->fields as $field_name => $field) {
102
+ $array_map[ $field_name ] = wp_parse_args( $field, $this->field_defaults );
103
+ }
104
+ $this->fields = $array_map;
105
 
106
  }
107
 
inc/templates/edit-form.tpl.php CHANGED
@@ -2,7 +2,7 @@
2
  <form class="edit-shortcode-form">
3
  <p><a href="#" class="edit-shortcode-form-cancel">&#8592; <?php esc_html_e( 'Back to list', 'shortcode-ui' ); ?></a></p>
4
 
5
- <div class="edit-shortcode-form-fields"></div>
6
  </form>
7
  </script>
8
 
@@ -16,52 +16,52 @@
16
  </script>
17
 
18
  <script type="text/html" id="tmpl-shortcode-ui-field-text">
19
- <div class="field-block">
20
- <label for="{{ data.id }}">{{ data.label }}</label>
21
  <input type="text" class="regular-text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" {{{ data.meta }}}/>
22
  <# if ( typeof data.description == 'string' ) { #>
23
- <p class="description">{{ data.description }}</p>
24
  <# } #>
25
  </div>
26
  </script>
27
 
28
  <script type="text/html" id="tmpl-shortcode-ui-field-url">
29
- <div class="field-block">
30
- <label for="{{ data.id }}">{{ data.label }}</label>
31
  <input type="url" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" class="code" {{{ data.meta }}}/>
32
  <# if ( typeof data.description == 'string' ) { #>
33
- <p class="description">{{ data.description }}</p>
34
  <# } #>
35
  </div>
36
  </script>
37
 
38
  <script type="text/html" id="tmpl-shortcode-ui-field-textarea">
39
- <div class="field-block">
40
- <label for="{{ data.id }}">{{ data.label }}</label>
41
  <textarea name="{{ data.attr }}" id="{{ data.id }}" {{{ data.meta }}}>{{ data.value }}</textarea>
42
  <# if ( typeof data.description == 'string' ) { #>
43
- <p class="description">{{ data.description }}</p>
44
  <# } #>
45
  </div>
46
  </script>
47
 
48
  <script type="text/html" id="tmpl-shortcode-ui-field-select">
49
- <div class="field-block">
50
- <label for="{{ data.id }}">{{ data.label }}</label>
51
  <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>
54
  <# }); #>
55
  </select>
56
  <# if ( typeof data.description == 'string' ) { #>
57
- <p class="description">{{ data.description }}</p>
58
  <# } #>
59
  </div>
60
  </script>
61
 
62
  <script type="text/html" id="tmpl-shortcode-ui-field-radio">
63
- <div class="field-block">
64
- <label>{{ data.label }}</label>
65
  <# _.each( data.options, function( label, value ) { #>
66
  <label>
67
  <input type="radio" name="{{ data.attr }}" value="{{ value }}" <# if ( value == data.value ) { print('checked'); } #> />
@@ -69,82 +69,82 @@
69
  </label>
70
  <# }); #>
71
  <# if ( typeof data.description == 'string' ) { #>
72
- <p class="description">{{ data.description }}</p>
73
  <# } #>
74
  </div>
75
  </script>
76
 
77
  <script type="text/html" id="tmpl-shortcode-ui-field-checkbox">
78
- <div class="field-block">
79
  <label for="{{ data.id }}">
80
  <input type="checkbox" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" <# if ( 'true' == data.value ){ print('checked'); } #>>
81
- {{ data.label }}
82
  </label>
83
  <# if ( typeof data.description == 'string' ) { #>
84
- <p class="description">{{ data.description }}</p>
85
  <# } #>
86
  </div>
87
  </script>
88
 
89
  <script type="text/html" id="tmpl-shortcode-ui-field-email">
90
- <div class="field-block">
91
- <label for="{{ data.id }}">{{ data.label }}</label>
92
  <input type="email" class="regular-text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value}}" {{{ data.meta }}}/>
93
  <# if ( typeof data.description == 'string' ) { #>
94
- <p class="description">{{ data.description }}</p>
95
  <# } #>
96
  </div>
97
  </script>
98
 
99
  <script type="text/html" id="tmpl-shortcode-ui-field-number">
100
- <div class="field-block">
101
- <label for="{{ data.id }}">{{ data.label }}</label>
102
  <input type="number" class="regular-text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value}}" {{{ data.meta }}}/>
103
  <# if ( typeof data.description == 'string' ) { #>
104
- <p class="description">{{ data.description }}</p>
105
  <# } #>
106
  </div>
107
  </script>
108
 
109
  <script type="text/html" id="tmpl-shortcode-ui-field-hidden">
110
- <div class="field-block">
111
- <label for="{{ data.id }}">{{ data.label }}</label>
112
  <input type="hidden" name="{{ data.attr }}" id="{{ data.id }}" value="true" {{{ data.meta }}}/>
113
  <# if ( typeof data.description == 'string' ) { #>
114
- <p class="description">{{ data.description }}</p>
115
  <# } #>
116
  </div>
117
  </script>
118
 
119
  <script type="text/html" id="tmpl-shortcode-ui-field-date">
120
- <div class="field-block">
121
- <label for="{{ data.id }}">{{ data.label }}</label>
122
  <input type="date" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" {{{ data.meta }}}/>
123
  <# if ( typeof data.description == 'string' ) { #>
124
- <p class="description">{{ data.description }}</p>
125
  <# } #>
126
  </div>
127
  </script>
128
 
129
  <script type="text/html" id="tmpl-shortcode-ui-content">
130
- <div class="field-block">
131
- <label for="inner_content">{{ data.label }}</label>
132
  <textarea id="inner_content" name="inner_content" class="content-edit" {{{ data.meta }}}>{{ data.value }}</textarea>
133
  <# if ( typeof data.description == 'string' ) { #>
134
- <p class="description">{{ data.description }}</p>
135
  <# } #>
136
  </div>
137
  </script>
138
 
139
  <script type="text/html" id="tmpl-shortcode-ui-field-range">
140
- <div class="field-block">
141
- <label for="{{ data.id }}">{{ data.label }}</label>
142
  <div class="field-range-container">
143
  <input type="range" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value}}" {{{ data.meta }}} />
144
  <output class="range" for="{{ data.id }}" id="{{ data.id }}_indicator">{{ data.value }}</output>
145
  </div>
146
  <# if ( typeof data.description == 'string' ) { #>
147
- <p class="description">{{ data.description }}</p>
148
  <# } #>
149
  </div>
150
- </script>
2
  <form class="edit-shortcode-form">
3
  <p><a href="#" class="edit-shortcode-form-cancel">&#8592; <?php esc_html_e( 'Back to list', 'shortcode-ui' ); ?></a></p>
4
 
5
+ <div class="edit-shortcode-form-fields shortcode-ui-edit-{{ data.model.attributes.shortcode_tag }}"></div>
6
  </form>
7
  </script>
8
 
16
  </script>
17
 
18
  <script type="text/html" id="tmpl-shortcode-ui-field-text">
19
+ <div class="field-block shortcode-ui-field-text shortcode-ui-attribute-{{ data.attr }}">
20
+ <label for="{{ data.id }}">{{{ data.label }}}</label>
21
  <input type="text" class="regular-text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" {{{ data.meta }}}/>
22
  <# if ( typeof data.description == 'string' ) { #>
23
+ <p class="description">{{{ data.description }}}</p>
24
  <# } #>
25
  </div>
26
  </script>
27
 
28
  <script type="text/html" id="tmpl-shortcode-ui-field-url">
29
+ <div class="field-block shortcode-ui-field-url shortcode-ui-attribute-{{ data.attr }}">
30
+ <label for="{{ data.id }}">{{{ data.label }}}</label>
31
  <input type="url" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" class="code" {{{ data.meta }}}/>
32
  <# if ( typeof data.description == 'string' ) { #>
33
+ <p class="description">{{{ data.description }}}</p>
34
  <# } #>
35
  </div>
36
  </script>
37
 
38
  <script type="text/html" id="tmpl-shortcode-ui-field-textarea">
39
+ <div class="field-block shortcode-ui-field-textarea shortcode-ui-attribute-{{ data.attr }}">
40
+ <label for="{{ data.id }}">{{{ data.label }}}</label>
41
  <textarea name="{{ data.attr }}" id="{{ data.id }}" {{{ data.meta }}}>{{ data.value }}</textarea>
42
  <# if ( typeof data.description == 'string' ) { #>
43
+ <p class="description">{{{ data.description }}}</p>
44
  <# } #>
45
  </div>
46
  </script>
47
 
48
  <script type="text/html" id="tmpl-shortcode-ui-field-select">
49
+ <div class="field-block shortcode-ui-field-select shortcode-ui-attribute-{{ data.attr }}">
50
+ <label for="{{ data.id }}">{{{ data.label }}}</label>
51
  <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>
54
  <# }); #>
55
  </select>
56
  <# if ( typeof data.description == 'string' ) { #>
57
+ <p class="description">{{{ data.description }}}</p>
58
  <# } #>
59
  </div>
60
  </script>
61
 
62
  <script type="text/html" id="tmpl-shortcode-ui-field-radio">
63
+ <div class="field-block shortcode-ui-field-radio shortcode-ui-attribute-{{ data.attr }}">
64
+ <label>{{{ data.label }}}</label>
65
  <# _.each( data.options, function( label, value ) { #>
66
  <label>
67
  <input type="radio" name="{{ data.attr }}" value="{{ value }}" <# if ( value == data.value ) { print('checked'); } #> />
69
  </label>
70
  <# }); #>
71
  <# if ( typeof data.description == 'string' ) { #>
72
+ <p class="description">{{{ data.description }}}</p>
73
  <# } #>
74
  </div>
75
  </script>
76
 
77
  <script type="text/html" id="tmpl-shortcode-ui-field-checkbox">
78
+ <div class="field-block shortcode-ui-field-checkbox shortcode-ui-attribute-{{ data.attr }}">
79
  <label for="{{ data.id }}">
80
  <input type="checkbox" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" <# if ( 'true' == data.value ){ print('checked'); } #>>
81
+ {{{ data.label }}}
82
  </label>
83
  <# if ( typeof data.description == 'string' ) { #>
84
+ <p class="description">{{{ data.description }}}</p>
85
  <# } #>
86
  </div>
87
  </script>
88
 
89
  <script type="text/html" id="tmpl-shortcode-ui-field-email">
90
+ <div class="field-block shortcode-ui-field-email shortcode-ui-attribute-{{ data.attr }}">
91
+ <label for="{{ data.id }}">{{{ data.label }}}</label>
92
  <input type="email" class="regular-text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value}}" {{{ data.meta }}}/>
93
  <# if ( typeof data.description == 'string' ) { #>
94
+ <p class="description">{{{ data.description }}}</p>
95
  <# } #>
96
  </div>
97
  </script>
98
 
99
  <script type="text/html" id="tmpl-shortcode-ui-field-number">
100
+ <div class="field-block shortcode-ui-field-number shortcode-ui-attribute-{{ data.attr }}">
101
+ <label for="{{ data.id }}">{{{ data.label }}}</label>
102
  <input type="number" class="regular-text" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value}}" {{{ data.meta }}}/>
103
  <# if ( typeof data.description == 'string' ) { #>
104
+ <p class="description">{{{ data.description }}}</p>
105
  <# } #>
106
  </div>
107
  </script>
108
 
109
  <script type="text/html" id="tmpl-shortcode-ui-field-hidden">
110
+ <div class="field-block shortcode-ui-field-hidden shortcode-ui-attribute-{{ data.attr }}">
111
+ <label for="{{ data.id }}">{{{ data.label }}}</label>
112
  <input type="hidden" name="{{ data.attr }}" id="{{ data.id }}" value="true" {{{ data.meta }}}/>
113
  <# if ( typeof data.description == 'string' ) { #>
114
+ <p class="description">{{{ data.description }}}</p>
115
  <# } #>
116
  </div>
117
  </script>
118
 
119
  <script type="text/html" id="tmpl-shortcode-ui-field-date">
120
+ <div class="field-block shortcode-ui-field-date shortcode-ui-attribute-{{ data.attr }}">
121
+ <label for="{{ data.id }}">{{{ data.label }}}</label>
122
  <input type="date" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value }}" {{{ data.meta }}}/>
123
  <# if ( typeof data.description == 'string' ) { #>
124
+ <p class="description">{{{ data.description }}}</p>
125
  <# } #>
126
  </div>
127
  </script>
128
 
129
  <script type="text/html" id="tmpl-shortcode-ui-content">
130
+ <div class="field-block shortcode-ui-content shortcode-ui-attribute-{{ data.attr }}">
131
+ <label for="inner_content">{{{ data.label }}}</label>
132
  <textarea id="inner_content" name="inner_content" class="content-edit" {{{ data.meta }}}>{{ data.value }}</textarea>
133
  <# if ( typeof data.description == 'string' ) { #>
134
+ <p class="description">{{{ data.description }}}</p>
135
  <# } #>
136
  </div>
137
  </script>
138
 
139
  <script type="text/html" id="tmpl-shortcode-ui-field-range">
140
+ <div class="field-block shortcode-ui-field-range shortcode-ui-attribute-{{ data.attr }}">
141
+ <label for="{{ data.id }}">{{{ data.label }}}</label>
142
  <div class="field-range-container">
143
  <input type="range" name="{{ data.attr }}" id="{{ data.id }}" value="{{ data.value}}" {{{ data.meta }}} />
144
  <output class="range" for="{{ data.id }}" id="{{ data.id }}_indicator">{{ data.value }}</output>
145
  </div>
146
  <# if ( typeof data.description == 'string' ) { #>
147
+ <p class="description">{{{ data.description }}}</p>
148
  <# } #>
149
  </div>
150
+ </script>
js/build/shortcode-ui.js CHANGED
@@ -1,6 +1,6 @@
1
  (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
  (function (global){
3
- var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null);
4
  var ShortcodeAttribute = require('./../models/shortcode-attribute.js');
5
 
6
  /**
@@ -22,7 +22,7 @@ module.exports = ShortcodeAttributes;
22
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
23
  },{"./../models/shortcode-attribute.js":5}],2:[function(require,module,exports){
24
  (function (global){
25
- var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null);
26
  var Shortcode = require('./../models/shortcode.js');
27
 
28
  // Shortcode Collection
@@ -35,8 +35,8 @@ module.exports = Shortcodes;
35
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
36
  },{"./../models/shortcode.js":6}],3:[function(require,module,exports){
37
  (function (global){
38
- var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null),
39
- wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null),
40
  sui = require('./../utils/sui.js'),
41
  Shortcodes = require('./../collections/shortcodes.js');
42
 
@@ -89,9 +89,9 @@ sui.controllers.MediaController = MediaController;
89
  module.exports = MediaController;
90
 
91
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
92
- },{"./../collections/shortcodes.js":2,"./../utils/sui.js":9}],4:[function(require,module,exports){
93
  (function (global){
94
- var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null);
95
 
96
  /**
97
  * Shortcode Attribute Model.
@@ -110,19 +110,22 @@ module.exports = InnerContent;
110
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
111
  },{}],5:[function(require,module,exports){
112
  (function (global){
113
- var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null);
114
 
115
  var ShortcodeAttribute = Backbone.Model.extend({
 
116
  defaults: {
117
  attr: '',
118
  label: '',
119
  type: '',
120
  value: '',
121
  description: '',
 
122
  meta: {
123
  placeholder: '',
124
  },
125
  },
 
126
  });
127
 
128
  module.exports = ShortcodeAttribute;
@@ -130,9 +133,10 @@ module.exports = ShortcodeAttribute;
130
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
131
  },{}],6:[function(require,module,exports){
132
  (function (global){
133
- var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null);
134
  var ShortcodeAttributes = require('./../collections/shortcode-attributes.js');
135
  var InnerContent = require('./inner-content.js');
 
136
 
137
  Shortcode = Backbone.Model.extend({
138
 
@@ -140,6 +144,7 @@ Shortcode = Backbone.Model.extend({
140
  label: '',
141
  shortcode_tag: '',
142
  attrs: new ShortcodeAttributes(),
 
143
  },
144
 
145
  /**
@@ -203,10 +208,19 @@ Shortcode = Backbone.Model.extend({
203
  return;
204
  }
205
 
 
 
 
 
 
206
  attrs.push( attr.get( 'attr' ) + '="' + attr.get( 'value' ) + '"' );
207
 
208
  } );
209
 
 
 
 
 
210
  if ( this.get( 'inner_content' ) ) {
211
  content = this.get( 'inner_content' ).get( 'value' );
212
  } else if ( this.get( 'inner_content_backup' ) ) {
@@ -241,8 +255,8 @@ var sui = require('./utils/sui.js'),
241
  Shortcodes = require('./collections/shortcodes.js'),
242
  shortcodeViewConstructor = require('./utils/shortcode-view-constructor.js'),
243
  mediaFrame = require('./views/media-frame.js'),
244
- wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null),
245
- $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null);
246
 
247
  $(document).ready(function(){
248
 
@@ -266,29 +280,183 @@ $(document).ready(function(){
266
  });
267
 
268
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
269
- },{"./collections/shortcodes.js":2,"./utils/shortcode-view-constructor.js":8,"./utils/sui.js":9,"./views/media-frame.js":17}],8:[function(require,module,exports){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  (function (global){
271
  var sui = require('./sui.js'),
272
- wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null),
273
- $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null);
 
274
 
275
  /**
276
- * Generic shortcode mce view constructor.
 
 
 
277
  * This is cloned and used by each shortcode when registering a view.
 
278
  */
279
  var shortcodeViewConstructor = {
280
 
 
 
 
 
 
 
 
 
 
281
  initialize: function( options ) {
 
 
282
  this.shortcodeModel = this.getShortcodeModel( this.shortcode );
283
- this.fetch();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  },
285
 
286
  /**
287
  * Get the shortcode model given the view shortcode options.
288
- * Must be a registered shortcode (see sui.shortcodes)
 
 
 
 
 
 
289
  */
290
  getShortcodeModel: function( options ) {
291
-
292
  var shortcodeModel;
293
 
294
  shortcodeModel = sui.shortcodes.findWhere( { shortcode_tag: options.tag } );
@@ -297,42 +465,73 @@ var shortcodeViewConstructor = {
297
  return;
298
  }
299
 
300
- shortcodeModel = shortcodeModel.clone();
301
 
302
- shortcodeModel.get('attrs').each(
303
- function( attr ) {
304
- if ( attr.get('attr') in options.attrs.named ) {
305
- attr.set(
306
- 'value',
307
- options.attrs.named[ attr.get('attr') ]
308
- );
309
- }
310
  }
311
- );
312
 
313
- if ( 'content' in options ) {
314
- var innerContent = shortcodeModel.get('inner_content');
315
- if ( innerContent ) {
316
- innerContent.set('value', options.content);
 
 
 
 
 
 
 
 
 
 
317
  }
318
  }
319
 
320
- return shortcodeModel;
321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  },
323
 
324
  /**
325
- * Fetch preview.
 
326
  * Async. Sets this.content and calls this.render.
327
  *
328
  * @return undefined
329
  */
330
- fetch : function() {
331
-
332
  var self = this;
333
 
334
  if ( ! this.fetching ) {
335
-
336
  this.fetching = true;
337
 
338
  wp.ajax.post( 'do_shortcode', {
@@ -340,31 +539,26 @@ var shortcodeViewConstructor = {
340
  shortcode: this.shortcodeModel.formatShortcode(),
341
  nonce: shortcodeUIData.nonces.preview,
342
  }).done( function( response ) {
343
-
344
  if ( '' === response ) {
345
  self.content = '<span class="shortcake-notice shortcake-empty">' + self.shortcodeModel.formatShortcode() + '</span>';
346
  } else {
347
  self.content = response;
348
  }
349
-
350
  }).fail( function() {
351
  self.content = '<span class="shortcake-error">' + shortcodeUIData.strings.mce_view_error + '</span>';
352
  } ).always( function() {
353
  delete self.fetching;
354
  self.render( null, true );
355
  } );
356
-
357
  }
358
-
359
  },
360
 
361
  /**
362
- * Edit shortcode.
363
- * Get shortcode model and open edit modal.
364
  *
 
365
  */
366
- edit : function( shortcodeString ) {
367
-
368
  var currentShortcode;
369
 
370
  // Backwards compatability for WP pre-4.2
@@ -390,84 +584,45 @@ var shortcodeViewConstructor = {
390
 
391
  /**
392
  * Parse a shortcode string and return shortcode model.
393
- * Must be a registered shortcode - see window.Shortcode_UI.shortcodes.
 
394
  *
395
  * @todo - I think there must be a cleaner way to get the
396
  * shortcode & args here that doesn't use regex.
397
  *
398
- * @param string shortcodeString
399
  * @return Shortcode
400
  */
401
  parseShortcodeString: function( shortcodeString ) {
402
-
403
  var model, attr;
404
 
405
- var megaRegex = /\[([^\s\]]+)([^\]]+)?\]([^\[]*)?(\[\/(\S+?)\])?/;
406
- var matches = shortcodeString.match( megaRegex );
 
407
 
408
  if ( ! matches ) {
409
  return;
410
  }
411
 
412
  defaultShortcode = sui.shortcodes.findWhere({
413
- shortcode_tag : matches[1]
414
  });
415
 
416
  if ( ! defaultShortcode ) {
417
  return;
418
  }
419
 
420
- currentShortcode = defaultShortcode.clone();
421
-
422
- if ( matches[2] ) {
423
-
424
- var attributeRegex = /(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/gmi;
425
- attributeMatches = matches[2].match( attributeRegex ) || [];
426
-
427
- // Trim whitespace from matches.
428
- attributeMatches = attributeMatches.map( function( match ) {
429
- return match.replace( /^\s+|\s+$/g, '' );
430
- } );
431
-
432
- // convert attribute strings to object.
433
- for ( var i = 0; i < attributeMatches.length; i++ ) {
434
-
435
- var bitsRegEx = /(\S+?)=(.*)/g;
436
- var bits = bitsRegEx.exec( attributeMatches[i] );
437
-
438
- if ( bits && bits[1] ) {
439
-
440
- attr = currentShortcode.get( 'attrs' ).findWhere({
441
- attr : bits[1]
442
- });
443
-
444
- // If attribute found - set value.
445
- // Trim quotes from beginning and end.
446
- if ( attr ) {
447
- attr.set( 'value', bits[2].replace( /^"|^'|"$|'$/gmi, "" ) );
448
- }
449
-
450
- }
451
- }
452
-
453
- }
454
-
455
- if ( matches[3] ) {
456
- var inner_content = currentShortcode.get( 'inner_content' );
457
- if ( inner_content ) {
458
- inner_content.set( 'value', this.unAutoP( matches[3] ) );
459
- } else {
460
- currentShortcode.set( 'inner_content_backup', this.unAutoP( matches[3] ) );
461
- }
462
- }
463
-
464
- return currentShortcode;
465
-
466
  },
467
 
468
  /**
469
  * Strip 'p' and 'br' tags, replace with line breaks.
470
- * Reverse the effect of the WP editor autop functionality.
 
 
 
 
471
  */
472
  unAutoP: function( content ) {
473
  if ( switchEditors && switchEditors.pre_wpautop ) {
@@ -475,7 +630,24 @@ var shortcodeViewConstructor = {
475
  }
476
 
477
  return content;
 
478
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
479
  },
480
 
481
  // Backwards compatability for Pre WP 4.2.
@@ -590,24 +762,24 @@ var shortcodeViewConstructor = {
590
  },
591
 
592
  },
593
-
594
  };
595
 
596
- module.exports = shortcodeViewConstructor;
597
 
598
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
599
- },{"./sui.js":9}],9:[function(require,module,exports){
600
  var Shortcodes = require('./../collections/shortcodes.js');
601
 
602
  window.Shortcode_UI = window.Shortcode_UI || {
603
  shortcodes: new Shortcodes(),
604
  views: {},
605
  controllers: {},
 
606
  };
607
 
608
  module.exports = window.Shortcode_UI;
609
 
610
- },{"./../collections/shortcodes.js":2}],10:[function(require,module,exports){
611
  var sui = require('./../utils/sui.js');
612
 
613
  var editAttributeFieldAttachment = sui.views.editAttributeField.extend( {
@@ -746,6 +918,13 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( {
746
  _openMediaFrame: function(e) {
747
  e.preventDefault();
748
  this.frame.open();
 
 
 
 
 
 
 
749
 
750
  var self = this;
751
  this.frame.on( 'select', function() {
@@ -810,11 +989,11 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( {
810
  module.exports = sui.views.editAttributeFieldAttachment = editAttributeFieldAttachment;
811
 
812
 
813
- },{"./../utils/sui.js":9}],11:[function(require,module,exports){
814
  (function (global){
815
  var sui = require('./../utils/sui.js'),
816
  editAttributeField = require('./edit-attribute-field.js'),
817
- $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null);
818
 
819
  sui.views.editAttributeFieldColor = editAttributeField.extend({
820
 
@@ -868,7 +1047,7 @@ sui.views.editAttributeFieldColor = editAttributeField.extend({
868
 
869
 
870
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
871
- },{"./../utils/sui.js":9,"./edit-attribute-field.js":13}],12:[function(require,module,exports){
872
  ( function( $ ) {
873
 
874
  var sui = window.Shortcode_UI;
@@ -1064,27 +1243,20 @@ sui.views.editAttributeFieldColor = editAttributeField.extend({
1064
 
1065
  } )( jQuery );
1066
 
1067
- },{}],13:[function(require,module,exports){
1068
  (function (global){
1069
- var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null),
1070
  sui = require('./../utils/sui.js'),
1071
- $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null);
1072
 
1073
  var editAttributeField = Backbone.View.extend( {
1074
 
1075
  tagName: "div",
1076
 
1077
  events: {
1078
- 'keyup input[type="text"]': 'inputChanged',
1079
- 'keyup textarea': 'inputChanged',
1080
- 'change select': 'inputChanged',
1081
- 'change input[type=checkbox]': 'inputChanged',
1082
- 'change input[type=radio]': 'inputChanged',
1083
- 'change input[type=email]': 'inputChanged',
1084
- 'change input[type=number]': 'inputChanged',
1085
- 'change input[type=date]': 'inputChanged',
1086
- 'change input[type=url]': 'inputChanged',
1087
- 'input input[type=range]': 'inputChanged',
1088
  },
1089
 
1090
  render: function() {
@@ -1212,11 +1384,11 @@ sui.views.editAttributeField = editAttributeField;
1212
  module.exports = editAttributeField;
1213
 
1214
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1215
- },{"./../utils/sui.js":9}],14:[function(require,module,exports){
1216
  (function (global){
1217
- var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null),
1218
- sui = require('./../utils/sui.js'),
1219
- backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null),
1220
  editAttributeField = require('./edit-attribute-field.js'),
1221
 
1222
  // Additional attribute field types: these fields are all standalone in functionality,
@@ -1243,7 +1415,7 @@ var EditShortcodeForm = wp.Backbone.View.extend({
1243
  var view = new editAttributeField( { model: innerContent } );
1244
 
1245
  view.shortcode = t.model;
1246
- view.template = wp.media.template( 'shortcode-ui-content' );
1247
 
1248
  t.views.add( '.edit-shortcode-form-fields', view );
1249
 
@@ -1296,10 +1468,10 @@ var EditShortcodeForm = wp.Backbone.View.extend({
1296
  module.exports = EditShortcodeForm;
1297
 
1298
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1299
- },{"./../utils/sui.js":9,"./edit-attribute-field-attachment.js":10,"./edit-attribute-field-color.js":11,"./edit-attribute-field-post-select.js":12,"./edit-attribute-field.js":13}],15:[function(require,module,exports){
1300
  (function (global){
1301
- var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null),
1302
- $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null);
1303
 
1304
  /**
1305
  * Single shortcode list item view.
@@ -1330,10 +1502,10 @@ var insertShortcodeListItem = wp.Backbone.View.extend({
1330
  module.exports = insertShortcodeListItem;
1331
 
1332
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1333
- },{}],16:[function(require,module,exports){
1334
  (function (global){
1335
- var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null);
1336
- var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null);
1337
  var Shortcodes = require('./../collections/shortcodes.js');
1338
  var insertShortcodeListItem = require('./insert-shortcode-list-item.js');
1339
 
@@ -1377,10 +1549,10 @@ var insertShortcodeList = wp.Backbone.View.extend({
1377
  module.exports = insertShortcodeList;
1378
 
1379
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1380
- },{"./../collections/shortcodes.js":2,"./insert-shortcode-list-item.js":15}],17:[function(require,module,exports){
1381
  (function (global){
1382
- var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null),
1383
- $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null),
1384
  MediaController = require('./../controllers/media-controller.js'),
1385
  Shortcode_UI = require('./shortcode-ui'),
1386
  Toolbar = require('./media-toolbar');
@@ -1501,9 +1673,9 @@ var mediaFrame = postMediaFrame.extend( {
1501
  module.exports = mediaFrame;
1502
 
1503
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1504
- },{"./../controllers/media-controller.js":3,"./media-toolbar":18,"./shortcode-ui":21}],18:[function(require,module,exports){
1505
  (function (global){
1506
- var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null);
1507
 
1508
  /**
1509
  * Toolbar view that extends wp.media.view.Toolbar
@@ -1533,9 +1705,9 @@ var Toolbar = wp.media.view.Toolbar.extend({
1533
  module.exports = Toolbar;
1534
 
1535
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1536
- },{}],19:[function(require,module,exports){
1537
  (function (global){
1538
- var wp = (typeof window !== "undefined" ? window.wp : typeof global !== "undefined" ? global.wp : null);
1539
  sui = require('./../utils/sui.js');
1540
 
1541
  var SearchShortcode = wp.media.view.Search.extend({
@@ -1581,10 +1753,10 @@ sui.views.SearchShortcode = SearchShortcode;
1581
  module.exports = SearchShortcode;
1582
 
1583
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1584
- },{"./../utils/sui.js":9}],20:[function(require,module,exports){
1585
  (function (global){
1586
- var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null),
1587
- $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null);
1588
 
1589
  /**
1590
  * Preview of rendered shortcode.
@@ -1736,7 +1908,9 @@ var ShortcodePreview = Backbone.View.extend({
1736
  }).done( function( response ) {
1737
  callback( response );
1738
  }).fail( function() {
1739
- callback( '<span class="shortcake-error">' + shortcodeUIData.strings.mce_view_error + '</span>' );
 
 
1740
  } );
1741
 
1742
  },
@@ -1770,16 +1944,16 @@ var ShortcodePreview = Backbone.View.extend({
1770
  module.exports = ShortcodePreview;
1771
 
1772
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1773
- },{}],21:[function(require,module,exports){
1774
  (function (global){
1775
- var Backbone = (typeof window !== "undefined" ? window.Backbone : typeof global !== "undefined" ? global.Backbone : null),
1776
  insertShortcodeList = require('./insert-shortcode-list.js'),
1777
  ShortcodePreview = require('./shortcode-preview.js'),
1778
  EditShortcodeForm = require('./edit-shortcode-form.js'),
1779
  Toolbar = require('./media-toolbar.js'),
1780
  SearchShortcode = require('./search-shortcode.js'),
1781
  sui = require('./../utils/sui.js'),
1782
- $ = (typeof window !== "undefined" ? window.jQuery : typeof global !== "undefined" ? global.jQuery : null);
1783
 
1784
  var Shortcode_UI = Backbone.View.extend({
1785
 
@@ -1876,4 +2050,4 @@ var Shortcode_UI = Backbone.View.extend({
1876
  module.exports = Shortcode_UI;
1877
 
1878
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1879
- },{"./../utils/sui.js":9,"./edit-shortcode-form.js":14,"./insert-shortcode-list.js":16,"./media-toolbar.js":18,"./search-shortcode.js":19,"./shortcode-preview.js":20}]},{},[7]);
1
  (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
  (function (global){
3
+ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null);
4
  var ShortcodeAttribute = require('./../models/shortcode-attribute.js');
5
 
6
  /**
22
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
23
  },{"./../models/shortcode-attribute.js":5}],2:[function(require,module,exports){
24
  (function (global){
25
+ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null);
26
  var Shortcode = require('./../models/shortcode.js');
27
 
28
  // Shortcode Collection
35
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
36
  },{"./../models/shortcode.js":6}],3:[function(require,module,exports){
37
  (function (global){
38
+ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
39
+ wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null),
40
  sui = require('./../utils/sui.js'),
41
  Shortcodes = require('./../collections/shortcodes.js');
42
 
89
  module.exports = MediaController;
90
 
91
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
92
+ },{"./../collections/shortcodes.js":2,"./../utils/sui.js":10}],4:[function(require,module,exports){
93
  (function (global){
94
+ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null);
95
 
96
  /**
97
  * Shortcode Attribute Model.
110
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
111
  },{}],5:[function(require,module,exports){
112
  (function (global){
113
+ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null);
114
 
115
  var ShortcodeAttribute = Backbone.Model.extend({
116
+
117
  defaults: {
118
  attr: '',
119
  label: '',
120
  type: '',
121
  value: '',
122
  description: '',
123
+ encode: false,
124
  meta: {
125
  placeholder: '',
126
  },
127
  },
128
+
129
  });
130
 
131
  module.exports = ShortcodeAttribute;
133
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
134
  },{}],6:[function(require,module,exports){
135
  (function (global){
136
+ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null);
137
  var ShortcodeAttributes = require('./../collections/shortcode-attributes.js');
138
  var InnerContent = require('./inner-content.js');
139
+ var $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
140
 
141
  Shortcode = Backbone.Model.extend({
142
 
144
  label: '',
145
  shortcode_tag: '',
146
  attrs: new ShortcodeAttributes(),
147
+ attributes_backup: {},
148
  },
149
 
150
  /**
208
  return;
209
  }
210
 
211
+ // Encode textareas incase HTML
212
+ if ( attr.get( 'encode' ) ) {
213
+ attr.set( 'value', encodeURIComponent( decodeURIComponent( attr.get( 'value' ) ) ), { silent: true } );
214
+ }
215
+
216
  attrs.push( attr.get( 'attr' ) + '="' + attr.get( 'value' ) + '"' );
217
 
218
  } );
219
 
220
+ $.each( this.get( 'attributes_backup' ), function( key, value){
221
+ attrs.push( key + '="' + value + '"' );
222
+ });
223
+
224
  if ( this.get( 'inner_content' ) ) {
225
  content = this.get( 'inner_content' ).get( 'value' );
226
  } else if ( this.get( 'inner_content_backup' ) ) {
255
  Shortcodes = require('./collections/shortcodes.js'),
256
  shortcodeViewConstructor = require('./utils/shortcode-view-constructor.js'),
257
  mediaFrame = require('./views/media-frame.js'),
258
+ wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null),
259
+ $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
260
 
261
  $(document).ready(function(){
262
 
280
  });
281
 
282
  }).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){
284
+ (function (global){
285
+ var $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
286
+ var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
287
+
288
+ /**
289
+ * A Utility object for batching requests for shortcode previews.
290
+ *
291
+ * Returns a "singleton" object with two methods, `queueToFetch` and
292
+ * `fetchAll`. Calling `Fetcher.queueToFetch()` will add the requested query to
293
+ * the fetcher's array, and set a timeout to run all queries after the current
294
+ * call stack has finished.
295
+ *
296
+ * @this {Fetcher} aliased as `fetcher`
297
+ */
298
+ var Fetcher = (function() {
299
+ var fetcher = this;
300
+
301
+ /*
302
+ * Counter, used to match each request in a batch with its response.
303
+ * @private
304
+ */
305
+ this.counter = 0;
306
+
307
+ /*
308
+ * Array of queries to be executed in a batch.
309
+ * @private
310
+ */
311
+ this.queries = [];
312
+
313
+ /*
314
+ * The timeout for the current batch request.
315
+ * @private
316
+ */
317
+ this.timeout = null;
318
+
319
+ /**
320
+ * Add a query to the queue.
321
+ *
322
+ * Adds the requested query to the next batch. Either sets a timeout to
323
+ * fetch previews, or adds to the current one if one is already being
324
+ * built. Returns a jQuery Deferred promise that will be resolved when the
325
+ * query is successful or otherwise complete.
326
+ *
327
+ * @param {object} query Object containing fields required to render preview: {
328
+ * @var {integer} post_id Post ID
329
+ * @var {string} shortcode Shortcode string to render
330
+ * @var {string} nonce Preview nonce
331
+ * }
332
+ * @return {Deferred}
333
+ */
334
+ this.queueToFetch = function( query ) {
335
+ var fetchPromise = new $.Deferred();
336
+
337
+ query.counter = ++fetcher.counter;
338
+
339
+ fetcher.queries.push({
340
+ promise: fetchPromise,
341
+ query: query,
342
+ counter: query.counter
343
+ });
344
+
345
+ if ( ! fetcher.timeout ) {
346
+ fetcher.timeout = setTimeout( fetcher.fetchAll );
347
+ }
348
+
349
+ return fetchPromise;
350
+ };
351
+
352
+ /**
353
+ * Execute all queued queries.
354
+ *
355
+ * Posts to the `bulk_do_shortcode` ajax endpoint to retrieve any queued
356
+ * previews. When that request recieves a response, goes through the
357
+ * response and resolves each of the promises in it.
358
+ *
359
+ * @this {Fetcher}
360
+ */
361
+ this.fetchAll = function() {
362
+ delete fetcher.timeout;
363
+
364
+ if ( 0 === fetcher.queries.length ) {
365
+ return;
366
+ }
367
+
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 ) {
375
+ var matchedQuery = _.findWhere( fetcher.queries, {
376
+ counter: parseInt( index ),
377
+ });
378
+
379
+ if ( matchedQuery ) {
380
+ fetcher.queries = _.without( fetcher.queries, matchedQuery );
381
+ matchedQuery.promise.resolve( result );
382
+ }
383
+ } );
384
+ } );
385
+ };
386
+
387
+ // Public API methods available
388
+ return {
389
+ queueToFetch : this.queueToFetch,
390
+ fetchAll : this.fetchAll
391
+ };
392
+
393
+ })();
394
+
395
+ module.exports = Fetcher;
396
+
397
+ }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
398
+ },{}],9:[function(require,module,exports){
399
  (function (global){
400
  var sui = require('./sui.js'),
401
+ fetcher = require('./fetcher.js'),
402
+ wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null),
403
+ $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
404
 
405
  /**
406
+ * Generic shortcode MCE view constructor.
407
+ *
408
+ * A Backbone-like View constructor intended for use when rendering a TinyMCE View.
409
+ * The main difference is that the TinyMCE View is not tied to a particular DOM node.
410
  * This is cloned and used by each shortcode when registering a view.
411
+ *
412
  */
413
  var shortcodeViewConstructor = {
414
 
415
+ /**
416
+ * Initialize a shortcode preview View.
417
+ *
418
+ * Fetches the preview by making a delayed Ajax call, and renders if a preview can be fetched.
419
+ *
420
+ * @constructor
421
+ * @this {Shortcode} Model registered with sui.shortcodes
422
+ * @param {Object} options Options
423
+ */
424
  initialize: function( options ) {
425
+ var self = this;
426
+
427
  this.shortcodeModel = this.getShortcodeModel( this.shortcode );
428
+ this.fetching = this.delayedFetch();
429
+
430
+ this.fetching.done( function( queryResponse ) {
431
+ var response = queryResponse.response;
432
+ if ( '' === response ) {
433
+ var span = $('<span />').addClass('shortcake-notice shortcake-empty').text( self.shortcodeModel.formatShortcode() );
434
+ var wrapper = $('<div />').html( span );
435
+ self.content = wrapper.html();
436
+ } else {
437
+ self.content = response;
438
+ }
439
+ }).fail( function() {
440
+ var span = $('<span />').addClass('shortcake-error').text( shortcodeUIData.strings.mce_view_error );
441
+ var wrapper = $('<div />').html( span );
442
+ self.content = wrapper.html();
443
+ } ).always( function() {
444
+ delete self.fetching;
445
+ self.render( null, true );
446
+ } );
447
  },
448
 
449
  /**
450
  * Get the shortcode model given the view shortcode options.
451
+ *
452
+ * If the shortcode found in the view is registered with Shortcake, this
453
+ * will clone the shortcode's Model and assign appropriate attribute
454
+ * values.
455
+ *
456
+ * @this {Shortcode}
457
+ * @param {Object} options Options formatted as wp.shortcode.
458
  */
459
  getShortcodeModel: function( options ) {
 
460
  var shortcodeModel;
461
 
462
  shortcodeModel = sui.shortcodes.findWhere( { shortcode_tag: options.tag } );
465
  return;
466
  }
467
 
468
+ currentShortcode = shortcodeModel.clone();
469
 
470
+ var attributes_backup = {};
471
+ var attributes = options.attrs;
472
+ for ( var key in attributes.named ) {
473
+
474
+ if ( ! attributes.named.hasOwnProperty( key ) ) {
475
+ continue;
 
 
476
  }
 
477
 
478
+ value = attributes.named[ key ];
479
+ attr = currentShortcode.get( 'attrs' ).findWhere({ attr: key });
480
+
481
+ // Reverse the effects of wpautop: https://core.trac.wordpress.org/ticket/34329
482
+ value = this.unAutoP( value );
483
+
484
+ if ( attr && attr.get('encode') ) {
485
+ value = decodeURIComponent( value );
486
+ }
487
+
488
+ if ( attr ) {
489
+ attr.set( 'value', value );
490
+ } else {
491
+ attributes_backup[ key ] = value;
492
  }
493
  }
494
 
495
+ currentShortcode.set( 'attributes_backup', attributes_backup );
496
 
497
+ if ( options.content ) {
498
+ var inner_content = currentShortcode.get( 'inner_content' );
499
+ // Reverse the effects of wpautop: https://core.trac.wordpress.org/ticket/34329
500
+ options.content = this.unAutoP( options.content );
501
+ if ( inner_content ) {
502
+ inner_content.set( 'value', options.content );
503
+ } else {
504
+ currentShortcode.set( 'inner_content_backup', options.content );
505
+ }
506
+ }
507
+
508
+ return currentShortcode;
509
+ },
510
+
511
+ /**
512
+ * Queue a request with Fetcher class, and return a promise.
513
+ *
514
+ * @return {Promise}
515
+ */
516
+ delayedFetch: function() {
517
+ return fetcher.queueToFetch({
518
+ post_id: $( '#post_ID' ).val(),
519
+ shortcode: this.shortcodeModel.formatShortcode(),
520
+ nonce: shortcodeUIData.nonces.preview,
521
+ });
522
  },
523
 
524
  /**
525
+ * Fetch a preview of a single shortcode.
526
+ *
527
  * Async. Sets this.content and calls this.render.
528
  *
529
  * @return undefined
530
  */
531
+ fetch: function() {
 
532
  var self = this;
533
 
534
  if ( ! this.fetching ) {
 
535
  this.fetching = true;
536
 
537
  wp.ajax.post( 'do_shortcode', {
539
  shortcode: this.shortcodeModel.formatShortcode(),
540
  nonce: shortcodeUIData.nonces.preview,
541
  }).done( function( response ) {
 
542
  if ( '' === response ) {
543
  self.content = '<span class="shortcake-notice shortcake-empty">' + self.shortcodeModel.formatShortcode() + '</span>';
544
  } else {
545
  self.content = response;
546
  }
 
547
  }).fail( function() {
548
  self.content = '<span class="shortcake-error">' + shortcodeUIData.strings.mce_view_error + '</span>';
549
  } ).always( function() {
550
  delete self.fetching;
551
  self.render( null, true );
552
  } );
 
553
  }
 
554
  },
555
 
556
  /**
557
+ * Get the shortcode model and open modal UI for editing.
 
558
  *
559
+ * @param {string} shortcodeString String representation of the shortcode
560
  */
561
+ edit: function( shortcodeString ) {
 
562
  var currentShortcode;
563
 
564
  // Backwards compatability for WP pre-4.2
584
 
585
  /**
586
  * Parse a shortcode string and return shortcode model.
587
+ * Must be a shortcode which has UI registered with Shortcake - see
588
+ * `window.sui.shortcodes`.
589
  *
590
  * @todo - I think there must be a cleaner way to get the
591
  * shortcode & args here that doesn't use regex.
592
  *
593
+ * @param {string} shortcodeString
594
  * @return Shortcode
595
  */
596
  parseShortcodeString: function( shortcodeString ) {
 
597
  var model, attr;
598
 
599
+ var shortcode_tags = _.map( sui.shortcodes.pluck( 'shortcode_tag' ), this.pregQuote ).join( '|' );
600
+ var regexp = wp.shortcode.regexp( shortcode_tags );
601
+ var matches = regexp.exec( shortcodeString );
602
 
603
  if ( ! matches ) {
604
  return;
605
  }
606
 
607
  defaultShortcode = sui.shortcodes.findWhere({
608
+ shortcode_tag : matches[2]
609
  });
610
 
611
  if ( ! defaultShortcode ) {
612
  return;
613
  }
614
 
615
+ var shortcode = wp.shortcode.fromMatch( matches );
616
+ return this.getShortcodeModel( shortcode );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
617
  },
618
 
619
  /**
620
  * Strip 'p' and 'br' tags, replace with line breaks.
621
+ *
622
+ * Reverses the effect of the WP editor autop functionality.
623
+ *
624
+ * @param {string} content Content with `<p>` and `<br>` tags inserted
625
+ * @return {string}
626
  */
627
  unAutoP: function( content ) {
628
  if ( switchEditors && switchEditors.pre_wpautop ) {
630
  }
631
 
632
  return content;
633
+ },
634
 
635
+ /**
636
+ * Escape any special characters in a string to be used as a regular expression.
637
+ *
638
+ * JS version of PHP's preg_quote()
639
+ *
640
+ * @see http://phpjs.org/functions/preg_quote/
641
+ *
642
+ * @param {string} str String to parse
643
+ * @param {string} delimiter Delimiter character to be also escaped - not used here
644
+ * @return {string}
645
+ */
646
+ pregQuote: function( str, delimiter ) {
647
+ return String(str)
648
+ .replace(
649
+ new RegExp( '[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + ( delimiter || '' ) + '-]', 'g' ),
650
+ '\\$&' );
651
  },
652
 
653
  // Backwards compatability for Pre WP 4.2.
762
  },
763
 
764
  },
 
765
  };
766
 
767
+ module.exports = sui.utils.shortcodeViewConstructor = shortcodeViewConstructor;
768
 
769
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
770
+ },{"./fetcher.js":8,"./sui.js":10}],10:[function(require,module,exports){
771
  var Shortcodes = require('./../collections/shortcodes.js');
772
 
773
  window.Shortcode_UI = window.Shortcode_UI || {
774
  shortcodes: new Shortcodes(),
775
  views: {},
776
  controllers: {},
777
+ utils: {},
778
  };
779
 
780
  module.exports = window.Shortcode_UI;
781
 
782
+ },{"./../collections/shortcodes.js":2}],11:[function(require,module,exports){
783
  var sui = require('./../utils/sui.js');
784
 
785
  var editAttributeFieldAttachment = sui.views.editAttributeField.extend( {
918
  _openMediaFrame: function(e) {
919
  e.preventDefault();
920
  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() {
989
  module.exports = sui.views.editAttributeFieldAttachment = editAttributeFieldAttachment;
990
 
991
 
992
+ },{"./../utils/sui.js":10}],12:[function(require,module,exports){
993
  (function (global){
994
  var sui = require('./../utils/sui.js'),
995
  editAttributeField = require('./edit-attribute-field.js'),
996
+ $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
997
 
998
  sui.views.editAttributeFieldColor = editAttributeField.extend({
999
 
1047
 
1048
 
1049
  }).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;
1243
 
1244
  } )( jQuery );
1245
 
1246
+ },{}],14:[function(require,module,exports){
1247
  (function (global){
1248
+ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
1249
  sui = require('./../utils/sui.js'),
1250
+ $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
1251
 
1252
  var editAttributeField = Backbone.View.extend( {
1253
 
1254
  tagName: "div",
1255
 
1256
  events: {
1257
+ 'input input': 'inputChanged',
1258
+ 'input textarea': 'inputChanged',
1259
+ 'change select': 'inputChanged',
 
 
 
 
 
 
 
1260
  },
1261
 
1262
  render: function() {
1384
  module.exports = editAttributeField;
1385
 
1386
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1387
+ },{"./../utils/sui.js":10}],15:[function(require,module,exports){
1388
  (function (global){
1389
+ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null),
1390
+ sui = require('./../utils/sui.js'),
1391
+ backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
1392
  editAttributeField = require('./edit-attribute-field.js'),
1393
 
1394
  // Additional attribute field types: these fields are all standalone in functionality,
1415
  var view = new editAttributeField( { model: innerContent } );
1416
 
1417
  view.shortcode = t.model;
1418
+ view.template = wp.media.template( 'shortcode-ui-content' );
1419
 
1420
  t.views.add( '.edit-shortcode-form-fields', view );
1421
 
1468
  module.exports = EditShortcodeForm;
1469
 
1470
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1471
+ },{"./../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){
1472
  (function (global){
1473
+ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null),
1474
+ $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
1475
 
1476
  /**
1477
  * Single shortcode list item view.
1502
  module.exports = insertShortcodeListItem;
1503
 
1504
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1505
+ },{}],17:[function(require,module,exports){
1506
  (function (global){
1507
+ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null);
1508
+ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null);
1509
  var Shortcodes = require('./../collections/shortcodes.js');
1510
  var insertShortcodeListItem = require('./insert-shortcode-list-item.js');
1511
 
1549
  module.exports = insertShortcodeList;
1550
 
1551
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1552
+ },{"./../collections/shortcodes.js":2,"./insert-shortcode-list-item.js":16}],18:[function(require,module,exports){
1553
  (function (global){
1554
+ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null),
1555
+ $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null),
1556
  MediaController = require('./../controllers/media-controller.js'),
1557
  Shortcode_UI = require('./shortcode-ui'),
1558
  Toolbar = require('./media-toolbar');
1673
  module.exports = mediaFrame;
1674
 
1675
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1676
+ },{"./../controllers/media-controller.js":3,"./media-toolbar":19,"./shortcode-ui":22}],19:[function(require,module,exports){
1677
  (function (global){
1678
+ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null);
1679
 
1680
  /**
1681
  * Toolbar view that extends wp.media.view.Toolbar
1705
  module.exports = Toolbar;
1706
 
1707
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1708
+ },{}],20:[function(require,module,exports){
1709
  (function (global){
1710
+ var wp = (typeof window !== "undefined" ? window['wp'] : typeof global !== "undefined" ? global['wp'] : null);
1711
  sui = require('./../utils/sui.js');
1712
 
1713
  var SearchShortcode = wp.media.view.Search.extend({
1753
  module.exports = SearchShortcode;
1754
 
1755
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1756
+ },{"./../utils/sui.js":10}],21:[function(require,module,exports){
1757
  (function (global){
1758
+ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
1759
+ $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
1760
 
1761
  /**
1762
  * Preview of rendered shortcode.
1908
  }).done( function( response ) {
1909
  callback( response );
1910
  }).fail( function() {
1911
+ var span = $('<span />').addClass('shortcake-error').text( shortcodeUIData.strings.mce_view_error );
1912
+ var wrapper = $('<div />').html( span );
1913
+ callback( wrapper.html() );
1914
  } );
1915
 
1916
  },
1944
  module.exports = ShortcodePreview;
1945
 
1946
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1947
+ },{}],22:[function(require,module,exports){
1948
  (function (global){
1949
+ var Backbone = (typeof window !== "undefined" ? window['Backbone'] : typeof global !== "undefined" ? global['Backbone'] : null),
1950
  insertShortcodeList = require('./insert-shortcode-list.js'),
1951
  ShortcodePreview = require('./shortcode-preview.js'),
1952
  EditShortcodeForm = require('./edit-shortcode-form.js'),
1953
  Toolbar = require('./media-toolbar.js'),
1954
  SearchShortcode = require('./search-shortcode.js'),
1955
  sui = require('./../utils/sui.js'),
1956
+ $ = (typeof window !== "undefined" ? window['jQuery'] : typeof global !== "undefined" ? global['jQuery'] : null);
1957
 
1958
  var Shortcode_UI = Backbone.View.extend({
1959
 
2050
  module.exports = Shortcode_UI;
2051
 
2052
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
2053
+ },{"./../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]);
js/src/models/shortcode-attribute.js CHANGED
@@ -1,16 +1,19 @@
1
  var Backbone = require('backbone');
2
 
3
  var ShortcodeAttribute = Backbone.Model.extend({
 
4
  defaults: {
5
  attr: '',
6
  label: '',
7
  type: '',
8
  value: '',
9
  description: '',
 
10
  meta: {
11
  placeholder: '',
12
  },
13
  },
 
14
  });
15
 
16
  module.exports = ShortcodeAttribute;
1
  var Backbone = require('backbone');
2
 
3
  var ShortcodeAttribute = Backbone.Model.extend({
4
+
5
  defaults: {
6
  attr: '',
7
  label: '',
8
  type: '',
9
  value: '',
10
  description: '',
11
+ encode: false,
12
  meta: {
13
  placeholder: '',
14
  },
15
  },
16
+
17
  });
18
 
19
  module.exports = ShortcodeAttribute;
js/src/models/shortcode.js CHANGED
@@ -1,6 +1,7 @@
1
  var Backbone = require('backbone');
2
  var ShortcodeAttributes = require('sui-collections/shortcode-attributes');
3
  var InnerContent = require('sui-models/inner-content');
 
4
 
5
  Shortcode = Backbone.Model.extend({
6
 
@@ -8,6 +9,7 @@ Shortcode = Backbone.Model.extend({
8
  label: '',
9
  shortcode_tag: '',
10
  attrs: new ShortcodeAttributes(),
 
11
  },
12
 
13
  /**
@@ -71,10 +73,19 @@ Shortcode = Backbone.Model.extend({
71
  return;
72
  }
73
 
 
 
 
 
 
74
  attrs.push( attr.get( 'attr' ) + '="' + attr.get( 'value' ) + '"' );
75
 
76
  } );
77
 
 
 
 
 
78
  if ( this.get( 'inner_content' ) ) {
79
  content = this.get( 'inner_content' ).get( 'value' );
80
  } else if ( this.get( 'inner_content_backup' ) ) {
1
  var Backbone = require('backbone');
2
  var ShortcodeAttributes = require('sui-collections/shortcode-attributes');
3
  var InnerContent = require('sui-models/inner-content');
4
+ var $ = require('jquery');
5
 
6
  Shortcode = Backbone.Model.extend({
7
 
9
  label: '',
10
  shortcode_tag: '',
11
  attrs: new ShortcodeAttributes(),
12
+ attributes_backup: {},
13
  },
14
 
15
  /**
73
  return;
74
  }
75
 
76
+ // Encode textareas incase HTML
77
+ if ( attr.get( 'encode' ) ) {
78
+ attr.set( 'value', encodeURIComponent( decodeURIComponent( attr.get( 'value' ) ) ), { silent: true } );
79
+ }
80
+
81
  attrs.push( attr.get( 'attr' ) + '="' + attr.get( 'value' ) + '"' );
82
 
83
  } );
84
 
85
+ $.each( this.get( 'attributes_backup' ), function( key, value){
86
+ attrs.push( key + '="' + value + '"' );
87
+ });
88
+
89
  if ( this.get( 'inner_content' ) ) {
90
  content = this.get( 'inner_content' ).get( 'value' );
91
  } else if ( this.get( 'inner_content_backup' ) ) {
js/src/utils/fetcher.js ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var $ = require('jquery');
2
+ var _ = require('underscore');
3
+
4
+ /**
5
+ * A Utility object for batching requests for shortcode previews.
6
+ *
7
+ * Returns a "singleton" object with two methods, `queueToFetch` and
8
+ * `fetchAll`. Calling `Fetcher.queueToFetch()` will add the requested query to
9
+ * the fetcher's array, and set a timeout to run all queries after the current
10
+ * call stack has finished.
11
+ *
12
+ * @this {Fetcher} aliased as `fetcher`
13
+ */
14
+ var Fetcher = (function() {
15
+ var fetcher = this;
16
+
17
+ /*
18
+ * Counter, used to match each request in a batch with its response.
19
+ * @private
20
+ */
21
+ this.counter = 0;
22
+
23
+ /*
24
+ * Array of queries to be executed in a batch.
25
+ * @private
26
+ */
27
+ this.queries = [];
28
+
29
+ /*
30
+ * The timeout for the current batch request.
31
+ * @private
32
+ */
33
+ this.timeout = null;
34
+
35
+ /**
36
+ * Add a query to the queue.
37
+ *
38
+ * Adds the requested query to the next batch. Either sets a timeout to
39
+ * fetch previews, or adds to the current one if one is already being
40
+ * built. Returns a jQuery Deferred promise that will be resolved when the
41
+ * query is successful or otherwise complete.
42
+ *
43
+ * @param {object} query Object containing fields required to render preview: {
44
+ * @var {integer} post_id Post ID
45
+ * @var {string} shortcode Shortcode string to render
46
+ * @var {string} nonce Preview nonce
47
+ * }
48
+ * @return {Deferred}
49
+ */
50
+ this.queueToFetch = function( query ) {
51
+ var fetchPromise = new $.Deferred();
52
+
53
+ query.counter = ++fetcher.counter;
54
+
55
+ fetcher.queries.push({
56
+ promise: fetchPromise,
57
+ query: query,
58
+ counter: query.counter
59
+ });
60
+
61
+ if ( ! fetcher.timeout ) {
62
+ fetcher.timeout = setTimeout( fetcher.fetchAll );
63
+ }
64
+
65
+ return fetchPromise;
66
+ };
67
+
68
+ /**
69
+ * Execute all queued queries.
70
+ *
71
+ * Posts to the `bulk_do_shortcode` ajax endpoint to retrieve any queued
72
+ * previews. When that request recieves a response, goes through the
73
+ * response and resolves each of the promises in it.
74
+ *
75
+ * @this {Fetcher}
76
+ */
77
+ this.fetchAll = function() {
78
+ delete fetcher.timeout;
79
+
80
+ if ( 0 === fetcher.queries.length ) {
81
+ return;
82
+ }
83
+
84
+ var request = $.post( ajaxurl + '?action=bulk_do_shortcode', {
85
+ queries: _.pluck( fetcher.queries, 'query' )
86
+ }
87
+ );
88
+
89
+ request.done( function( response ) {
90
+ _.each( response.data, function( result, index ) {
91
+ var matchedQuery = _.findWhere( fetcher.queries, {
92
+ counter: parseInt( index ),
93
+ });
94
+
95
+ if ( matchedQuery ) {
96
+ fetcher.queries = _.without( fetcher.queries, matchedQuery );
97
+ matchedQuery.promise.resolve( result );
98
+ }
99
+ } );
100
+ } );
101
+ };
102
+
103
+ // Public API methods available
104
+ return {
105
+ queueToFetch : this.queueToFetch,
106
+ fetchAll : this.fetchAll
107
+ };
108
+
109
+ })();
110
+
111
+ module.exports = Fetcher;
js/src/utils/shortcode-view-constructor.js CHANGED
@@ -1,24 +1,63 @@
1
  var sui = require('sui-utils/sui'),
2
- wp = require('wp'),
3
- $ = require('jquery');
 
4
 
5
  /**
6
- * Generic shortcode mce view constructor.
 
 
 
7
  * This is cloned and used by each shortcode when registering a view.
 
8
  */
9
  var shortcodeViewConstructor = {
10
 
 
 
 
 
 
 
 
 
 
11
  initialize: function( options ) {
 
 
12
  this.shortcodeModel = this.getShortcodeModel( this.shortcode );
13
- this.fetch();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  },
15
 
16
  /**
17
  * Get the shortcode model given the view shortcode options.
18
- * Must be a registered shortcode (see sui.shortcodes)
 
 
 
 
 
 
19
  */
20
  getShortcodeModel: function( options ) {
21
-
22
  var shortcodeModel;
23
 
24
  shortcodeModel = sui.shortcodes.findWhere( { shortcode_tag: options.tag } );
@@ -27,42 +66,73 @@ var shortcodeViewConstructor = {
27
  return;
28
  }
29
 
30
- shortcodeModel = shortcodeModel.clone();
31
 
32
- shortcodeModel.get('attrs').each(
33
- function( attr ) {
34
- if ( attr.get('attr') in options.attrs.named ) {
35
- attr.set(
36
- 'value',
37
- options.attrs.named[ attr.get('attr') ]
38
- );
39
- }
40
  }
41
- );
42
 
43
- if ( 'content' in options ) {
44
- var innerContent = shortcodeModel.get('inner_content');
45
- if ( innerContent ) {
46
- innerContent.set('value', options.content);
 
 
 
 
 
 
 
 
 
 
47
  }
48
  }
49
 
50
- return shortcodeModel;
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  },
53
 
54
  /**
55
- * Fetch preview.
 
56
  * Async. Sets this.content and calls this.render.
57
  *
58
  * @return undefined
59
  */
60
- fetch : function() {
61
-
62
  var self = this;
63
 
64
  if ( ! this.fetching ) {
65
-
66
  this.fetching = true;
67
 
68
  wp.ajax.post( 'do_shortcode', {
@@ -70,31 +140,26 @@ var shortcodeViewConstructor = {
70
  shortcode: this.shortcodeModel.formatShortcode(),
71
  nonce: shortcodeUIData.nonces.preview,
72
  }).done( function( response ) {
73
-
74
  if ( '' === response ) {
75
  self.content = '<span class="shortcake-notice shortcake-empty">' + self.shortcodeModel.formatShortcode() + '</span>';
76
  } else {
77
  self.content = response;
78
  }
79
-
80
  }).fail( function() {
81
  self.content = '<span class="shortcake-error">' + shortcodeUIData.strings.mce_view_error + '</span>';
82
  } ).always( function() {
83
  delete self.fetching;
84
  self.render( null, true );
85
  } );
86
-
87
  }
88
-
89
  },
90
 
91
  /**
92
- * Edit shortcode.
93
- * Get shortcode model and open edit modal.
94
  *
 
95
  */
96
- edit : function( shortcodeString ) {
97
-
98
  var currentShortcode;
99
 
100
  // Backwards compatability for WP pre-4.2
@@ -120,84 +185,45 @@ var shortcodeViewConstructor = {
120
 
121
  /**
122
  * Parse a shortcode string and return shortcode model.
123
- * Must be a registered shortcode - see window.Shortcode_UI.shortcodes.
 
124
  *
125
  * @todo - I think there must be a cleaner way to get the
126
  * shortcode & args here that doesn't use regex.
127
  *
128
- * @param string shortcodeString
129
  * @return Shortcode
130
  */
131
  parseShortcodeString: function( shortcodeString ) {
132
-
133
  var model, attr;
134
 
135
- var megaRegex = /\[([^\s\]]+)([^\]]+)?\]([^\[]*)?(\[\/(\S+?)\])?/;
136
- var matches = shortcodeString.match( megaRegex );
 
137
 
138
  if ( ! matches ) {
139
  return;
140
  }
141
 
142
  defaultShortcode = sui.shortcodes.findWhere({
143
- shortcode_tag : matches[1]
144
  });
145
 
146
  if ( ! defaultShortcode ) {
147
  return;
148
  }
149
 
150
- currentShortcode = defaultShortcode.clone();
151
-
152
- if ( matches[2] ) {
153
-
154
- var attributeRegex = /(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/gmi;
155
- attributeMatches = matches[2].match( attributeRegex ) || [];
156
-
157
- // Trim whitespace from matches.
158
- attributeMatches = attributeMatches.map( function( match ) {
159
- return match.replace( /^\s+|\s+$/g, '' );
160
- } );
161
-
162
- // convert attribute strings to object.
163
- for ( var i = 0; i < attributeMatches.length; i++ ) {
164
-
165
- var bitsRegEx = /(\S+?)=(.*)/g;
166
- var bits = bitsRegEx.exec( attributeMatches[i] );
167
-
168
- if ( bits && bits[1] ) {
169
-
170
- attr = currentShortcode.get( 'attrs' ).findWhere({
171
- attr : bits[1]
172
- });
173
-
174
- // If attribute found - set value.
175
- // Trim quotes from beginning and end.
176
- if ( attr ) {
177
- attr.set( 'value', bits[2].replace( /^"|^'|"$|'$/gmi, "" ) );
178
- }
179
-
180
- }
181
- }
182
-
183
- }
184
-
185
- if ( matches[3] ) {
186
- var inner_content = currentShortcode.get( 'inner_content' );
187
- if ( inner_content ) {
188
- inner_content.set( 'value', this.unAutoP( matches[3] ) );
189
- } else {
190
- currentShortcode.set( 'inner_content_backup', this.unAutoP( matches[3] ) );
191
- }
192
- }
193
-
194
- return currentShortcode;
195
-
196
  },
197
 
198
  /**
199
  * Strip 'p' and 'br' tags, replace with line breaks.
200
- * Reverse the effect of the WP editor autop functionality.
 
 
 
 
201
  */
202
  unAutoP: function( content ) {
203
  if ( switchEditors && switchEditors.pre_wpautop ) {
@@ -205,7 +231,24 @@ var shortcodeViewConstructor = {
205
  }
206
 
207
  return content;
 
208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  },
210
 
211
  // Backwards compatability for Pre WP 4.2.
@@ -320,7 +363,6 @@ var shortcodeViewConstructor = {
320
  },
321
 
322
  },
323
-
324
  };
325
 
326
- module.exports = shortcodeViewConstructor;
1
  var sui = require('sui-utils/sui'),
2
+ fetcher = require('sui-utils/fetcher'),
3
+ wp = require('wp'),
4
+ $ = require('jquery');
5
 
6
  /**
7
+ * Generic shortcode MCE view constructor.
8
+ *
9
+ * A Backbone-like View constructor intended for use when rendering a TinyMCE View.
10
+ * The main difference is that the TinyMCE View is not tied to a particular DOM node.
11
  * This is cloned and used by each shortcode when registering a view.
12
+ *
13
  */
14
  var shortcodeViewConstructor = {
15
 
16
+ /**
17
+ * Initialize a shortcode preview View.
18
+ *
19
+ * Fetches the preview by making a delayed Ajax call, and renders if a preview can be fetched.
20
+ *
21
+ * @constructor
22
+ * @this {Shortcode} Model registered with sui.shortcodes
23
+ * @param {Object} options Options
24
+ */
25
  initialize: function( options ) {
26
+ var self = this;
27
+
28
  this.shortcodeModel = this.getShortcodeModel( this.shortcode );
29
+ this.fetching = this.delayedFetch();
30
+
31
+ this.fetching.done( function( queryResponse ) {
32
+ var response = queryResponse.response;
33
+ if ( '' === response ) {
34
+ var span = $('<span />').addClass('shortcake-notice shortcake-empty').text( self.shortcodeModel.formatShortcode() );
35
+ var wrapper = $('<div />').html( span );
36
+ self.content = wrapper.html();
37
+ } else {
38
+ self.content = response;
39
+ }
40
+ }).fail( function() {
41
+ var span = $('<span />').addClass('shortcake-error').text( shortcodeUIData.strings.mce_view_error );
42
+ var wrapper = $('<div />').html( span );
43
+ self.content = wrapper.html();
44
+ } ).always( function() {
45
+ delete self.fetching;
46
+ self.render( null, true );
47
+ } );
48
  },
49
 
50
  /**
51
  * Get the shortcode model given the view shortcode options.
52
+ *
53
+ * If the shortcode found in the view is registered with Shortcake, this
54
+ * will clone the shortcode's Model and assign appropriate attribute
55
+ * values.
56
+ *
57
+ * @this {Shortcode}
58
+ * @param {Object} options Options formatted as wp.shortcode.
59
  */
60
  getShortcodeModel: function( options ) {
 
61
  var shortcodeModel;
62
 
63
  shortcodeModel = sui.shortcodes.findWhere( { shortcode_tag: options.tag } );
66
  return;
67
  }
68
 
69
+ currentShortcode = shortcodeModel.clone();
70
 
71
+ var attributes_backup = {};
72
+ var attributes = options.attrs;
73
+ for ( var key in attributes.named ) {
74
+
75
+ if ( ! attributes.named.hasOwnProperty( key ) ) {
76
+ continue;
 
 
77
  }
 
78
 
79
+ value = attributes.named[ key ];
80
+ attr = currentShortcode.get( 'attrs' ).findWhere({ attr: key });
81
+
82
+ // Reverse the effects of wpautop: https://core.trac.wordpress.org/ticket/34329
83
+ value = this.unAutoP( value );
84
+
85
+ if ( attr && attr.get('encode') ) {
86
+ value = decodeURIComponent( value );
87
+ }
88
+
89
+ if ( attr ) {
90
+ attr.set( 'value', value );
91
+ } else {
92
+ attributes_backup[ key ] = value;
93
  }
94
  }
95
 
96
+ currentShortcode.set( 'attributes_backup', attributes_backup );
97
 
98
+ if ( options.content ) {
99
+ var inner_content = currentShortcode.get( 'inner_content' );
100
+ // Reverse the effects of wpautop: https://core.trac.wordpress.org/ticket/34329
101
+ options.content = this.unAutoP( options.content );
102
+ if ( inner_content ) {
103
+ inner_content.set( 'value', options.content );
104
+ } else {
105
+ currentShortcode.set( 'inner_content_backup', options.content );
106
+ }
107
+ }
108
+
109
+ return currentShortcode;
110
+ },
111
+
112
+ /**
113
+ * Queue a request with Fetcher class, and return a promise.
114
+ *
115
+ * @return {Promise}
116
+ */
117
+ delayedFetch: function() {
118
+ return fetcher.queueToFetch({
119
+ post_id: $( '#post_ID' ).val(),
120
+ shortcode: this.shortcodeModel.formatShortcode(),
121
+ nonce: shortcodeUIData.nonces.preview,
122
+ });
123
  },
124
 
125
  /**
126
+ * Fetch a preview of a single shortcode.
127
+ *
128
  * Async. Sets this.content and calls this.render.
129
  *
130
  * @return undefined
131
  */
132
+ fetch: function() {
 
133
  var self = this;
134
 
135
  if ( ! this.fetching ) {
 
136
  this.fetching = true;
137
 
138
  wp.ajax.post( 'do_shortcode', {
140
  shortcode: this.shortcodeModel.formatShortcode(),
141
  nonce: shortcodeUIData.nonces.preview,
142
  }).done( function( response ) {
 
143
  if ( '' === response ) {
144
  self.content = '<span class="shortcake-notice shortcake-empty">' + self.shortcodeModel.formatShortcode() + '</span>';
145
  } else {
146
  self.content = response;
147
  }
 
148
  }).fail( function() {
149
  self.content = '<span class="shortcake-error">' + shortcodeUIData.strings.mce_view_error + '</span>';
150
  } ).always( function() {
151
  delete self.fetching;
152
  self.render( null, true );
153
  } );
 
154
  }
 
155
  },
156
 
157
  /**
158
+ * Get the shortcode model and open modal UI for editing.
 
159
  *
160
+ * @param {string} shortcodeString String representation of the shortcode
161
  */
162
+ edit: function( shortcodeString ) {
 
163
  var currentShortcode;
164
 
165
  // Backwards compatability for WP pre-4.2
185
 
186
  /**
187
  * Parse a shortcode string and return shortcode model.
188
+ * Must be a shortcode which has UI registered with Shortcake - see
189
+ * `window.sui.shortcodes`.
190
  *
191
  * @todo - I think there must be a cleaner way to get the
192
  * shortcode & args here that doesn't use regex.
193
  *
194
+ * @param {string} shortcodeString
195
  * @return Shortcode
196
  */
197
  parseShortcodeString: function( shortcodeString ) {
 
198
  var model, attr;
199
 
200
+ var shortcode_tags = _.map( sui.shortcodes.pluck( 'shortcode_tag' ), this.pregQuote ).join( '|' );
201
+ var regexp = wp.shortcode.regexp( shortcode_tags );
202
+ var matches = regexp.exec( shortcodeString );
203
 
204
  if ( ! matches ) {
205
  return;
206
  }
207
 
208
  defaultShortcode = sui.shortcodes.findWhere({
209
+ shortcode_tag : matches[2]
210
  });
211
 
212
  if ( ! defaultShortcode ) {
213
  return;
214
  }
215
 
216
+ var shortcode = wp.shortcode.fromMatch( matches );
217
+ return this.getShortcodeModel( shortcode );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  },
219
 
220
  /**
221
  * Strip 'p' and 'br' tags, replace with line breaks.
222
+ *
223
+ * Reverses the effect of the WP editor autop functionality.
224
+ *
225
+ * @param {string} content Content with `<p>` and `<br>` tags inserted
226
+ * @return {string}
227
  */
228
  unAutoP: function( content ) {
229
  if ( switchEditors && switchEditors.pre_wpautop ) {
231
  }
232
 
233
  return content;
234
+ },
235
 
236
+ /**
237
+ * Escape any special characters in a string to be used as a regular expression.
238
+ *
239
+ * JS version of PHP's preg_quote()
240
+ *
241
+ * @see http://phpjs.org/functions/preg_quote/
242
+ *
243
+ * @param {string} str String to parse
244
+ * @param {string} delimiter Delimiter character to be also escaped - not used here
245
+ * @return {string}
246
+ */
247
+ pregQuote: function( str, delimiter ) {
248
+ return String(str)
249
+ .replace(
250
+ new RegExp( '[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + ( delimiter || '' ) + '-]', 'g' ),
251
+ '\\$&' );
252
  },
253
 
254
  // Backwards compatability for Pre WP 4.2.
363
  },
364
 
365
  },
 
366
  };
367
 
368
+ module.exports = sui.utils.shortcodeViewConstructor = shortcodeViewConstructor;
js/src/utils/sui.js CHANGED
@@ -4,6 +4,7 @@ window.Shortcode_UI = window.Shortcode_UI || {
4
  shortcodes: new Shortcodes(),
5
  views: {},
6
  controllers: {},
 
7
  };
8
 
9
  module.exports = window.Shortcode_UI;
4
  shortcodes: new Shortcodes(),
5
  views: {},
6
  controllers: {},
7
+ utils: {},
8
  };
9
 
10
  module.exports = window.Shortcode_UI;
js/src/views/edit-attribute-field-attachment.js CHANGED
@@ -136,6 +136,13 @@ var editAttributeFieldAttachment = sui.views.editAttributeField.extend( {
136
  _openMediaFrame: function(e) {
137
  e.preventDefault();
138
  this.frame.open();
 
 
 
 
 
 
 
139
 
140
  var self = this;
141
  this.frame.on( 'select', function() {
136
  _openMediaFrame: function(e) {
137
  e.preventDefault();
138
  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() {
js/src/views/edit-attribute-field.js CHANGED
@@ -7,16 +7,9 @@ var editAttributeField = Backbone.View.extend( {
7
  tagName: "div",
8
 
9
  events: {
10
- 'keyup input[type="text"]': 'inputChanged',
11
- 'keyup textarea': 'inputChanged',
12
- 'change select': 'inputChanged',
13
- 'change input[type=checkbox]': 'inputChanged',
14
- 'change input[type=radio]': 'inputChanged',
15
- 'change input[type=email]': 'inputChanged',
16
- 'change input[type=number]': 'inputChanged',
17
- 'change input[type=date]': 'inputChanged',
18
- 'change input[type=url]': 'inputChanged',
19
- 'input input[type=range]': 'inputChanged',
20
  },
21
 
22
  render: function() {
7
  tagName: "div",
8
 
9
  events: {
10
+ 'input input': 'inputChanged',
11
+ 'input textarea': 'inputChanged',
12
+ 'change select': 'inputChanged',
 
 
 
 
 
 
 
13
  },
14
 
15
  render: function() {
js/src/views/edit-shortcode-form.js CHANGED
@@ -1,6 +1,6 @@
1
  var wp = require('wp'),
2
- sui = require('sui-utils/sui'),
3
- backbone = require('backbone'),
4
  editAttributeField = require( 'sui-views/edit-attribute-field' ),
5
 
6
  // Additional attribute field types: these fields are all standalone in functionality,
@@ -27,7 +27,7 @@ var EditShortcodeForm = wp.Backbone.View.extend({
27
  var view = new editAttributeField( { model: innerContent } );
28
 
29
  view.shortcode = t.model;
30
- view.template = wp.media.template( 'shortcode-ui-content' );
31
 
32
  t.views.add( '.edit-shortcode-form-fields', view );
33
 
1
  var wp = require('wp'),
2
+ sui = require('sui-utils/sui'),
3
+ backbone = require('backbone'),
4
  editAttributeField = require( 'sui-views/edit-attribute-field' ),
5
 
6
  // Additional attribute field types: these fields are all standalone in functionality,
27
  var view = new editAttributeField( { model: innerContent } );
28
 
29
  view.shortcode = t.model;
30
+ view.template = wp.media.template( 'shortcode-ui-content' );
31
 
32
  t.views.add( '.edit-shortcode-form-fields', view );
33
 
js/src/views/shortcode-preview.js CHANGED
@@ -151,7 +151,9 @@ var ShortcodePreview = Backbone.View.extend({
151
  }).done( function( response ) {
152
  callback( response );
153
  }).fail( function() {
154
- callback( '<span class="shortcake-error">' + shortcodeUIData.strings.mce_view_error + '</span>' );
 
 
155
  } );
156
 
157
  },
151
  }).done( function( response ) {
152
  callback( response );
153
  }).fail( function() {
154
+ var span = $('<span />').addClass('shortcake-error').text( shortcodeUIData.strings.mce_view_error );
155
+ var wrapper = $('<div />').html( span );
156
+ callback( wrapper.html() );
157
  } );
158
 
159
  },
languages/shortcode-ui-da_DK.mo ADDED
Binary file
languages/shortcode-ui-da_DK.po ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2015 Fusion Engineering and community
2
+ # This file is distributed under the GPL v2 or later.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: Shortcake (Shortcode UI) 0.5.0-alpha\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/shortcode-ui\n"
7
+ "POT-Creation-Date: 2015-09-09 22:06+0200\n"
8
+ "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
+ "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2015-09-09 22:16+0200\n"
12
+ "Language-Team: \n"
13
+ "X-Generator: Poedit 1.8.4\n"
14
+ "X-Poedit-KeywordsList: __;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c\n"
15
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
16
+ "X-Poedit-SourceCharset: UTF-8\n"
17
+ "X-Poedit-Basepath: ..\n"
18
+ "X-Textdomain-Support: yes\n"
19
+ "Last-Translator: \n"
20
+ "Language: da_DK\n"
21
+ "X-Poedit-SearchPath-0: .\n"
22
+
23
+ #: inc/class-shortcode-ui.php:109
24
+ msgid "Inner Content"
25
+ msgstr "Indre indhold"
26
+
27
+ #: inc/class-shortcode-ui.php:200 inc/class-shortcode-ui.php:201
28
+ msgid "Insert Post Element"
29
+ msgstr "Indsæt opslags element"
30
+
31
+ #: inc/class-shortcode-ui.php:202
32
+ msgid "%s Details"
33
+ msgstr "%s detaljer"
34
+
35
+ #: inc/class-shortcode-ui.php:203
36
+ msgid "Insert Element"
37
+ msgstr "Indsæt element"
38
+
39
+ #: inc/class-shortcode-ui.php:204
40
+ msgid "Update"
41
+ msgstr "Opdater"
42
+
43
+ #: inc/class-shortcode-ui.php:205
44
+ msgid "There are no attributes to configure for this Post Element."
45
+ msgstr "Der er ikke nogen egenskaber at konfigurere for dette opslagselement"
46
+
47
+ #: inc/class-shortcode-ui.php:206
48
+ msgid "Edit"
49
+ msgstr "Ændre"
50
+
51
+ #: inc/class-shortcode-ui.php:207
52
+ msgid "Failed to load preview"
53
+ msgstr "Kunne ikke indlæse glimt"
54
+
55
+ #: inc/class-shortcode-ui.php:208
56
+ msgid "Search"
57
+ msgstr "Søg"
58
+
59
+ #: inc/class-shortcode-ui.php:209
60
+ msgid "Insert Content"
61
+ msgstr "Indsæt indhold"
62
+
63
+ #: inc/class-shortcode-ui.php:312
64
+ msgid "Something's rotten in the state of Denmark"
65
+ msgstr "Der er noget rådent i Danmark"
66
+
67
+ #: inc/fields/class-field-attachment.php:79
68
+ #: inc/fields/class-field-attachment.php:80
69
+ msgid "Select Attachment"
70
+ msgstr "Vælg vedhæftning"
71
+
72
+ #: inc/fields/class-field-attachment.php:104
73
+ msgid "Thumbnail Details"
74
+ msgstr "Miniatureportræt detaljer"
75
+
76
+ #: inc/fields/class-field-attachment.php:109
77
+ msgid "Edit Attachment"
78
+ msgstr "Ændre vedhæftning"
79
+
80
+ #: inc/templates/edit-form.tpl.php:3
81
+ msgid "Back to list"
82
+ msgstr "Tilbage til liste"
83
+
84
+ #. Plugin Name of the plugin/theme
85
+ msgid "Shortcake (Shortcode UI)"
86
+ msgstr "Shortcake (Shortcode UI)"
87
+
88
+ #. Description of the plugin/theme
89
+ msgid "User Interface for adding shortcodes."
90
+ msgstr "Brugergrænseflade for tilføjelse af genvejskoder"
91
+
92
+ #. Author of the plugin/theme
93
+ msgid "Fusion Engineering and community"
94
+ msgstr "Fusion Engineering and community"
95
+
96
+ #. Author URI of the plugin/theme
97
+ msgid "http://next.fusion.net/tag/shortcode-ui/"
98
+ msgstr "http://next.fusion.net/tag/shortcode-ui/"
languages/shortcode-ui-de_DE.mo ADDED
Binary file
languages/shortcode-ui-de_DE.po ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2015 Fusion Engineering and community
2
+ # This file is distributed under the GPL v2 or later.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: Shortcake (Shortcode UI) 0.6.0-alpha\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/shortcode-ui\n"
7
+ "POT-Creation-Date: 2015-09-21 18:43+0200\n"
8
+ "MIME-Version: 1.0\n"
9
+ "Content-Type: text/plain; charset=UTF-8\n"
10
+ "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2015-10-12 14:34+0200\n"
12
+ "Language-Team: Gérard Mathiuet <gerard@mathiuet.ch>\n"
13
+ "X-Generator: Poedit 1.8.5\n"
14
+ "X-Poedit-KeywordsList: __;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c\n"
15
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
16
+ "X-Poedit-SourceCharset: UTF-8\n"
17
+ "X-Poedit-Basepath: ..\n"
18
+ "X-Textdomain-Support: yes\n"
19
+ "Last-Translator: \n"
20
+ "Language: de_DE\n"
21
+ "X-Poedit-SearchPath-0: .\n"
22
+
23
+ #: inc/class-shortcode-ui.php:109
24
+ msgid "Inner Content"
25
+ msgstr "Inhalt"
26
+
27
+ #: inc/class-shortcode-ui.php:200 inc/class-shortcode-ui.php:201
28
+ msgid "Insert Post Element"
29
+ msgstr "Beitragselement einfügen"
30
+
31
+ #: inc/class-shortcode-ui.php:202
32
+ msgid "%s Details"
33
+ msgstr "%s-Details"
34
+
35
+ #: inc/class-shortcode-ui.php:203
36
+ msgid "Insert Element"
37
+ msgstr "Element einfügen"
38
+
39
+ #: inc/class-shortcode-ui.php:204
40
+ msgid "Update"
41
+ msgstr "Aktualisieren"
42
+
43
+ #: inc/class-shortcode-ui.php:205
44
+ msgid "There are no attributes to configure for this Post Element."
45
+ msgstr "Es sind keine zu konfigurierenden Attribute für dieses Beitrags-Element verfügbar."
46
+
47
+ #: inc/class-shortcode-ui.php:206
48
+ msgid "Edit"
49
+ msgstr "Bearbeiten"
50
+
51
+ #: inc/class-shortcode-ui.php:207
52
+ msgid "Failed to load preview"
53
+ msgstr "Fehler beim Laden der Vorschau"
54
+
55
+ #: inc/class-shortcode-ui.php:208
56
+ msgid "Search"
57
+ msgstr "Suchen"
58
+
59
+ #: inc/class-shortcode-ui.php:209
60
+ msgid "Insert Content"
61
+ msgstr "Inhalt einfügen"
62
+
63
+ #: inc/class-shortcode-ui.php:312
64
+ msgid "Something's rotten in the state of Denmark"
65
+ msgstr "Etwas ist faul im Staate Dänemark"
66
+
67
+ #: inc/fields/class-field-attachment.php:79
68
+ #: inc/fields/class-field-attachment.php:80
69
+ msgid "Select Attachment"
70
+ msgstr "Anhang auswählen"
71
+
72
+ #: inc/fields/class-field-attachment.php:104
73
+ msgid "Thumbnail Details"
74
+ msgstr "Vorschaubild-Details"
75
+
76
+ #: inc/fields/class-field-attachment.php:109
77
+ msgid "Edit Attachment"
78
+ msgstr "Anhang bearbeiten"
79
+
80
+ #: inc/templates/edit-form.tpl.php:3
81
+ msgid "Back to list"
82
+ msgstr "Zurück zur Liste"
83
+
84
+ #. Plugin Name of the plugin/theme
85
+ msgid "Shortcake (Shortcode UI)"
86
+ msgstr "Shortcake (Shortcode UI)"
87
+
88
+ #. Description of the plugin/theme
89
+ msgid "User Interface for adding shortcodes."
90
+ msgstr "Benutzeroberfläche für das Einfügen von Shortcodes."
91
+
92
+ #. Author of the plugin/theme
93
+ msgid "Fusion Engineering and community"
94
+ msgstr "Fusion Engineering and community"
95
+
96
+ #. Author URI of the plugin/theme
97
+ msgid "http://next.fusion.net/tag/shortcode-ui/"
98
+ msgstr "http://next.fusion.net/tag/shortcode-ui/"
languages/shortcode-ui-fr_FR.mo CHANGED
Binary file
languages/shortcode-ui-fr_FR.po CHANGED
@@ -2,91 +2,92 @@
2
  # This file is distributed under the GPL v2 or later.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Shortcode UI v0.3-alpha\n"
6
- "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/"
7
- "shortcode-ui\n"
8
- "POT-Creation-Date: 2015-04-22 16:48:40+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "PO-Revision-Date: 2015-04-28 23:36+0100\n"
13
- "X-Generator: Poedit 1.7.6\n"
14
- "X-Poedit-KeywordsList: __;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;"
15
- "_n_noop:1,2;_nx_noop:1,2,3c;esc_attr__;esc_html__;esc_attr_e;"
16
- "esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c\n"
17
- "Language: fr\n"
18
  "Plural-Forms: nplurals=2; plural=(n > 1);\n"
19
  "X-Poedit-SourceCharset: UTF-8\n"
20
- "X-Poedit-Basepath: ../\n"
21
  "X-Textdomain-Support: yes\n"
22
  "Last-Translator: \n"
23
- "Language-Team: Frédéric Serva <fred.serva@gmail.com>\n"
24
  "X-Poedit-SearchPath-0: .\n"
25
 
26
- #: inc/class-shortcode-ui.php:40
27
  msgid "Inner Content"
28
- msgstr "Contenu interieur"
29
 
30
- #: inc/class-shortcode-ui.php:101 inc/class-shortcode-ui.php:102
31
  msgid "Insert Post Element"
32
  msgstr "Insérer un élément d'article"
33
 
34
- #: inc/class-shortcode-ui.php:103
35
  msgid "%s Details"
36
  msgstr "%s Détails"
37
 
38
- #: inc/class-shortcode-ui.php:104
39
  msgid "Insert Element"
40
  msgstr "Insérer un élément"
41
 
42
- #: inc/class-shortcode-ui.php:105
43
  msgid "Update"
44
  msgstr "Mettre à jour"
45
 
46
- #: inc/class-shortcode-ui.php:106
47
  msgid "There are no attributes to configure for this Post Element."
48
- msgstr "Aucun attribut à configurer pour cet élément d'article."
49
 
50
- #: inc/class-shortcode-ui.php:107
51
  msgid "Edit"
52
  msgstr "Modifier"
53
 
54
- #: inc/class-shortcode-ui.php:108
55
- msgid "Preview"
56
- msgstr "Aperçu"
57
-
58
- #: inc/class-shortcode-ui.php:109
59
  msgid "Failed to load preview"
60
  msgstr "Impossible de charger l'aperçu"
61
 
62
- #: inc/class-shortcode-ui.php:110
63
  msgid "Search"
64
  msgstr "Recherche"
65
 
66
- #: inc/class-shortcode-ui.php:111
67
  msgid "Insert Content"
68
  msgstr "Insérer le contenu"
69
 
70
- #: inc/class-shortcode-ui.php:205
71
  msgid "Something's rotten in the state of Denmark"
72
  msgstr "Il y a quelque chose de pourri au royaume du Danemark"
73
 
74
- #: inc/fields/class-field-attachment.php:47
75
- #: inc/fields/class-field-attachment.php:48
76
  msgid "Select Attachment"
77
  msgstr "Sélectionnez le fichier à télécharger"
78
 
 
 
 
 
 
 
 
 
79
  #: inc/templates/edit-form.tpl.php:3
80
  msgid "Back to list"
81
  msgstr "Retour à la liste"
82
 
83
  #. Plugin Name of the plugin/theme
84
- msgid "Shortcode UI"
85
- msgstr "Shortcode UI"
86
 
87
  #. Description of the plugin/theme
88
  msgid "User Interface for adding shortcodes."
89
- msgstr "Interface utilisateur facilitant l'ajout de shortcodes."
90
 
91
  #. Author of the plugin/theme
92
  msgid "Fusion Engineering and community"
2
  # This file is distributed under the GPL v2 or later.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Shortcake (Shortcode UI) 0.5.0-alpha\n"
6
+ "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/shortcode-ui\n"
7
+ "POT-Creation-Date: 2015-09-08 18:39+0200\n"
 
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2015-09-08 18:47+0200\n"
12
+ "Language-Team: Frédéric Serva <fred.serva@gmail.com>\n"
13
+ "X-Generator: Poedit 1.8.4\n"
14
+ "X-Poedit-KeywordsList: __;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c\n"
 
 
15
  "Plural-Forms: nplurals=2; plural=(n > 1);\n"
16
  "X-Poedit-SourceCharset: UTF-8\n"
17
+ "X-Poedit-Basepath: ..\n"
18
  "X-Textdomain-Support: yes\n"
19
  "Last-Translator: \n"
20
+ "Language: fr\n"
21
  "X-Poedit-SearchPath-0: .\n"
22
 
23
+ #: inc/class-shortcode-ui.php:109
24
  msgid "Inner Content"
25
+ msgstr "Contenu intérieur"
26
 
27
+ #: inc/class-shortcode-ui.php:200 inc/class-shortcode-ui.php:201
28
  msgid "Insert Post Element"
29
  msgstr "Insérer un élément d'article"
30
 
31
+ #: inc/class-shortcode-ui.php:202
32
  msgid "%s Details"
33
  msgstr "%s Détails"
34
 
35
+ #: inc/class-shortcode-ui.php:203
36
  msgid "Insert Element"
37
  msgstr "Insérer un élément"
38
 
39
+ #: inc/class-shortcode-ui.php:204
40
  msgid "Update"
41
  msgstr "Mettre à jour"
42
 
43
+ #: inc/class-shortcode-ui.php:205
44
  msgid "There are no attributes to configure for this Post Element."
45
+ msgstr "Aucun attribut à configurer pour cet élément d'article."
46
 
47
+ #: inc/class-shortcode-ui.php:206
48
  msgid "Edit"
49
  msgstr "Modifier"
50
 
51
+ #: inc/class-shortcode-ui.php:207
 
 
 
 
52
  msgid "Failed to load preview"
53
  msgstr "Impossible de charger l'aperçu"
54
 
55
+ #: inc/class-shortcode-ui.php:208
56
  msgid "Search"
57
  msgstr "Recherche"
58
 
59
+ #: inc/class-shortcode-ui.php:209
60
  msgid "Insert Content"
61
  msgstr "Insérer le contenu"
62
 
63
+ #: inc/class-shortcode-ui.php:312
64
  msgid "Something's rotten in the state of Denmark"
65
  msgstr "Il y a quelque chose de pourri au royaume du Danemark"
66
 
67
+ #: inc/fields/class-field-attachment.php:79
68
+ #: inc/fields/class-field-attachment.php:80
69
  msgid "Select Attachment"
70
  msgstr "Sélectionnez le fichier à télécharger"
71
 
72
+ #: inc/fields/class-field-attachment.php:104
73
+ msgid "Thumbnail Details"
74
+ msgstr "Détails de la vignette"
75
+
76
+ #: inc/fields/class-field-attachment.php:109
77
+ msgid "Edit Attachment"
78
+ msgstr "Modifier la pièce jointe"
79
+
80
  #: inc/templates/edit-form.tpl.php:3
81
  msgid "Back to list"
82
  msgstr "Retour à la liste"
83
 
84
  #. Plugin Name of the plugin/theme
85
+ msgid "Shortcake (Shortcode UI)"
86
+ msgstr "Shortcake (Shortcode UI)"
87
 
88
  #. Description of the plugin/theme
89
  msgid "User Interface for adding shortcodes."
90
+ msgstr "Interface utilisateur pour l’insertion de Codes courts."
91
 
92
  #. Author of the plugin/theme
93
  msgid "Fusion Engineering and community"
languages/shortcode-ui-it_IT.mo ADDED
Binary file
languages/shortcode-ui-it_IT.po ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2015 Fusion Engineering and community
2
+ # This file is distributed under the GPL v2 or later.
3
+ # Mte90 <mte90net@gmail.com>, 2015.
4
+ msgid ""
5
+ msgstr ""
6
+ "Project-Id-Version: Shortcake (Shortcode UI) 0.5.0-alpha\n"
7
+ "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/shortcode-ui\n"
8
+ "POT-Creation-Date: 2015-08-26 22:28:38+00:00\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=UTF-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "PO-Revision-Date: 2015-09-24 15:47+0200\n"
13
+ "Last-Translator: Mte90 <mte90net@gmail.com>\n"
14
+ "Language-Team: Italian <mte90net@gmail.com>\n"
15
+ "X-Generator: Poedit 1.8.4\n"
16
+ "X-Poedit-KeywordsList: __;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;"
17
+ "_nx_noop:1,2,3c;esc_attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;"
18
+ "esc_html_x:1,2c\n"
19
+ "Language: it\n"
20
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
21
+ "X-Poedit-SourceCharset: UTF-8\n"
22
+ "X-Poedit-Basepath: ..\n"
23
+ "X-Textdomain-Support: yes\n"
24
+ "X-Poedit-SearchPath-0: .\n"
25
+
26
+ #: inc/class-shortcode-ui.php:109
27
+ msgid "Inner Content"
28
+ msgstr "Contenuto interno"
29
+
30
+ #: inc/class-shortcode-ui.php:200 inc/class-shortcode-ui.php:201
31
+ msgid "Insert Post Element"
32
+ msgstr "Inserisci Elemento nel Post"
33
+
34
+ #: inc/class-shortcode-ui.php:202
35
+ msgid "%s Details"
36
+ msgstr "%s Dettagli"
37
+
38
+ #: inc/class-shortcode-ui.php:203
39
+ msgid "Insert Element"
40
+ msgstr "Inserisci Elemento"
41
+
42
+ #: inc/class-shortcode-ui.php:204
43
+ msgid "Update"
44
+ msgstr "Aggiorna"
45
+
46
+ #: inc/class-shortcode-ui.php:205
47
+ msgid "There are no attributes to configure for this Post Element."
48
+ msgstr "Non ci sono attributi per configurare questo Elemento Post."
49
+
50
+ #: inc/class-shortcode-ui.php:206
51
+ msgid "Edit"
52
+ msgstr "Modifica"
53
+
54
+ #: inc/class-shortcode-ui.php:207
55
+ msgid "Failed to load preview"
56
+ msgstr "Caricamento dell'anteprima fallita"
57
+
58
+ #: inc/class-shortcode-ui.php:208
59
+ msgid "Search"
60
+ msgstr "Cerca"
61
+
62
+ #: inc/class-shortcode-ui.php:209
63
+ msgid "Insert Content"
64
+ msgstr "Inserisci Contenuto"
65
+
66
+ #: inc/class-shortcode-ui.php:312
67
+ msgid "Something's rotten in the state of Denmark"
68
+ msgstr "Qualcosa è marcio in Danimarca"
69
+
70
+ #: inc/fields/class-field-attachment.php:79
71
+ #: inc/fields/class-field-attachment.php:80
72
+ msgid "Select Attachment"
73
+ msgstr "Seleziona Allegato"
74
+
75
+ #: inc/fields/class-field-attachment.php:104
76
+ msgid "Thumbnail Details"
77
+ msgstr "Dettagli Anteprima"
78
+
79
+ #: inc/fields/class-field-attachment.php:109
80
+ msgid "Edit Attachment"
81
+ msgstr "Modifica Allegato"
82
+
83
+ #: inc/templates/edit-form.tpl.php:3
84
+ msgid "Back to list"
85
+ msgstr "Torna alla lista"
86
+
87
+ #. Plugin Name of the plugin/theme
88
+ msgid "Shortcake (Shortcode UI)"
89
+ msgstr "Shortcake (Shortcode UI)"
90
+
91
+ #. Description of the plugin/theme
92
+ msgid "User Interface for adding shortcodes."
93
+ msgstr "Interfaccia Utente per aggiungere shortcode."
94
+
95
+ #. Author of the plugin/theme
96
+ msgid "Fusion Engineering and community"
97
+ msgstr "Fusion Engineering e community"
98
+
99
+ #. Author URI of the plugin/theme
100
+ msgid "http://next.fusion.net/tag/shortcode-ui/"
101
+ msgstr "http://next.fusion.net/tag/shortcode-ui/"
languages/shortcode-ui.pot CHANGED
@@ -2,16 +2,16 @@
2
  # This file is distributed under the GPL v2 or later.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Shortcake (Shortcode UI) 0.5.0-alpha\n"
6
- "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/shortcode-ui\n"
7
- "POT-Creation-Date: 2015-08-26 22:28:38+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
  "PO-Revision-Date: 2015-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
- "X-Generator: grunt-wp-i18n 0.5.2\n"
15
  "X-Poedit-KeywordsList: "
16
  "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
17
  "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
@@ -24,47 +24,55 @@ msgstr ""
24
  "X-Poedit-Bookmarks: \n"
25
  "X-Textdomain-Support: yes\n"
26
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  #: inc/class-shortcode-ui.php:109
28
  msgid "Inner Content"
29
  msgstr ""
30
 
31
- #: inc/class-shortcode-ui.php:200 inc/class-shortcode-ui.php:201
32
  msgid "Insert Post Element"
33
  msgstr ""
34
 
35
- #: inc/class-shortcode-ui.php:202
36
  msgid "%s Details"
37
  msgstr ""
38
 
39
- #: inc/class-shortcode-ui.php:203
40
  msgid "Insert Element"
41
  msgstr ""
42
 
43
- #: inc/class-shortcode-ui.php:204
44
  msgid "Update"
45
  msgstr ""
46
 
47
- #: inc/class-shortcode-ui.php:205
48
  msgid "There are no attributes to configure for this Post Element."
49
  msgstr ""
50
 
51
- #: inc/class-shortcode-ui.php:206
52
- msgid "Edit"
53
- msgstr ""
54
-
55
- #: inc/class-shortcode-ui.php:207
56
  msgid "Failed to load preview"
57
  msgstr ""
58
 
59
- #: inc/class-shortcode-ui.php:208
60
  msgid "Search"
61
  msgstr ""
62
 
63
- #: inc/class-shortcode-ui.php:209
64
  msgid "Insert Content"
65
  msgstr ""
66
 
67
- #: inc/class-shortcode-ui.php:312
68
  msgid "Something's rotten in the state of Denmark"
69
  msgstr ""
70
 
2
  # This file is distributed under the GPL v2 or later.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Shortcake (Shortcode UI) 0.6.0-alpha\n"
6
+ "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"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
  "PO-Revision-Date: 2015-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
+ "X-Generator: grunt-wp-i18n 0.5.3\n"
15
  "X-Poedit-KeywordsList: "
16
  "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
17
  "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
24
  "X-Poedit-Bookmarks: \n"
25
  "X-Textdomain-Support: yes\n"
26
 
27
+ #: dev.php:75
28
+ msgid "Attachment"
29
+ msgstr ""
30
+
31
+ #: dev.php:79 dev.php:80
32
+ msgid "Select Image"
33
+ msgstr ""
34
+
35
+ #: dev.php:83
36
+ msgid "Citation Source"
37
+ msgstr ""
38
+
39
  #: inc/class-shortcode-ui.php:109
40
  msgid "Inner Content"
41
  msgstr ""
42
 
43
+ #: inc/class-shortcode-ui.php:220 inc/class-shortcode-ui.php:221
44
  msgid "Insert Post Element"
45
  msgstr ""
46
 
47
+ #: inc/class-shortcode-ui.php:222
48
  msgid "%s Details"
49
  msgstr ""
50
 
51
+ #: inc/class-shortcode-ui.php:223
52
  msgid "Insert Element"
53
  msgstr ""
54
 
55
+ #: inc/class-shortcode-ui.php:224
56
  msgid "Update"
57
  msgstr ""
58
 
59
+ #: inc/class-shortcode-ui.php:225
60
  msgid "There are no attributes to configure for this Post Element."
61
  msgstr ""
62
 
63
+ #: inc/class-shortcode-ui.php:226
 
 
 
 
64
  msgid "Failed to load preview"
65
  msgstr ""
66
 
67
+ #: inc/class-shortcode-ui.php:227
68
  msgid "Search"
69
  msgstr ""
70
 
71
+ #: inc/class-shortcode-ui.php:228
72
  msgid "Insert Content"
73
  msgstr ""
74
 
75
+ #: inc/class-shortcode-ui.php:323
76
  msgid "Something's rotten in the state of Denmark"
77
  msgstr ""
78
 
package.json CHANGED
@@ -5,6 +5,7 @@
5
  "author": "Human Made Limited",
6
  "license": "GPL V2",
7
  "devDependencies": {
 
8
  "browserify": "^8.1.3",
9
  "browserify-shim": "^3.8.3",
10
  "grunt": "^0.4.5",
@@ -13,9 +14,10 @@
13
  "grunt-contrib-jshint": "^0.11.2",
14
  "grunt-contrib-watch": "^0.6.1",
15
  "grunt-phpcs": "^0.4.0",
 
16
  "grunt-sass": "^0.18.0",
17
  "grunt-wp-i18n": "^0.5.0",
18
- "grunt-wp-readme-to-markdown": "~0.9.0",
19
  "remapify": "1.4.3"
20
  },
21
  "browserify": {
5
  "author": "Human Made Limited",
6
  "license": "GPL V2",
7
  "devDependencies": {
8
+ "autoprefixer": "^6.0.3",
9
  "browserify": "^8.1.3",
10
  "browserify-shim": "^3.8.3",
11
  "grunt": "^0.4.5",
14
  "grunt-contrib-jshint": "^0.11.2",
15
  "grunt-contrib-watch": "^0.6.1",
16
  "grunt-phpcs": "^0.4.0",
17
+ "grunt-postcss": "^0.6.0",
18
  "grunt-sass": "^0.18.0",
19
  "grunt-wp-i18n": "^0.5.0",
20
+ "grunt-wp-readme-to-markdown": "~1.0.0",
21
  "remapify": "1.4.3"
22
  },
23
  "browserify": {
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === Shortcake (Shortcode UI) ===
2
- Contributors: fusionengineering, mattheu, danielbachhuber, zebulonj, goldenapples, jitendraharpalani, sanchothefat, bfintal, davisshaver
3
  Tags: shortcodes
4
  Requires at least: 4.1
5
- Tested up to: 4.3
6
- Stable tag: 0.5.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -13,17 +13,24 @@ Shortcake makes using WordPress shortcodes a piece of cake.
13
 
14
  Used alongside `add_shortcode`, Shortcake supplies a user-friendly interface for adding a shortcode to a post, and viewing and editing it from within the content editor.
15
 
16
- Once you've installed the plugin, you'll need to [register UI for your shortcodes](https://github.com/fusioneng/Shortcake/wiki/Registering-Shortcode-UI). For inspiration, check out [examples of Shortcake in the wild](https://github.com/fusioneng/Shortcake/wiki/Shortcode-UI-Examples).
17
 
18
- To report bugs or feature requests, [please use Github issues](https://github.com/fusioneng/Shortcake/issues).
19
 
20
  == Installation ==
21
 
22
  Shortcake can be installed like any other WordPress plugin.
23
 
24
- Once you've done so, you'll need to [register the UI for your code](https://github.com/fusioneng/Shortcake/wiki/Registering-Shortcode-UI).
 
 
 
 
 
 
 
 
25
 
26
- New in 0.4.0 is the ability to [attach javascript functions to event attribute updates](https://github.com/fusioneng/Shortcake/wiki/Event-Attribute-Callbacks). Action hooks can be used to dynamically show or hide a field based on the value of another, or to implement custom validation rules.
27
 
28
  == Screenshots ==
29
 
@@ -44,6 +51,25 @@ We've removed the compatibility shim for the magical `content` attribute. If you
44
 
45
  == Changelog ==
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  = 0.5.0 (August 26, 2015) =
48
  * Attachment field: Made it easier to change the attachment by clicking on the thumbnail; added attachment metadata in the field view.
49
  * Attachment field: Refactored JavaScript to trigger events.
1
  === Shortcake (Shortcode UI) ===
2
+ Contributors: fusionengineering, mattheu, danielbachhuber, zebulonj, goldenapples, jitendraharpalani, sanchothefat, bfintal, davisshaver, garyj, mte90, fredserva, khromov
3
  Tags: shortcodes
4
  Requires at least: 4.1
5
+ Tested up to: 4.4
6
+ Stable tag: 0.6.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
13
 
14
  Used alongside `add_shortcode`, Shortcake supplies a user-friendly interface for adding a shortcode to a post, and viewing and editing it from within the content editor.
15
 
16
+ Once you've installed the plugin, you'll need to [register UI for your shortcodes](https://github.com/wp-shortcake/shortcake/wiki/Registering-Shortcode-UI). For inspiration, check out [examples of Shortcake in the wild](https://github.com/wp-shortcode/shortcake/wiki/Shortcode-UI-Examples).
17
 
18
+ To report bugs or feature requests, [please use Github issues](https://github.com/wp-shortcode/shortcake/issues).
19
 
20
  == Installation ==
21
 
22
  Shortcake can be installed like any other WordPress plugin.
23
 
24
+ Once you've done so, you'll need to [register the UI for your code](https://github.com/wp-shortcode/shortcake/wiki/Registering-Shortcode-UI).
25
+
26
+ New in 0.4.0 is the ability to [attach javascript functions to event attribute updates](https://github.com/wp-shortcode/shortcake/wiki/Event-Attribute-Callbacks). Action hooks can be used to dynamically show or hide a field based on the value of another, or to implement custom validation rules.
27
+
28
+ == Frequently Asked Questions ==
29
+
30
+ = How do I register UI for arbitrary key=>value pairs as shortcode attributes? =
31
+
32
+ Shortcake doesn't support custom key=>value pairs as shortcode attributes because it isn't a great user experience.
33
 
 
34
 
35
  == Screenshots ==
36
 
51
 
52
  == Changelog ==
53
 
54
+ = 0.6.0 (November 2, 2015) =
55
+ * Supports an optional `encode=true` argument for attributes, to allow limited HTML support. Attributes need to be run through `shortcode_atts()` in order to be properly decoded.
56
+ * Defines a `SHORTCODE_UI_DOING_PREVIEW` constant when rendering a shortcode preview, which enables callbacks to serve a different representation of the shortcode in TinyMCE.
57
+ * When an attachment is already selected for a shortcode attribute, opening media library will include it selected.
58
+ * Cleaned up icon vertical alignment in the Insert Post Element UI.
59
+ * Added CSS utility classes to all field HTML. For instance, the attachment field is now wrapped with `shortcode-ui-field-attachment`.
60
+ * Added filters to modify shortcode UI arguments on registration.
61
+ * Cleaned up the example plugin, so it's a much more useful developer reference.
62
+ * Uses core's JavaScript regex for parsing shortcodes, instead of maintaining separate regex.
63
+ * Permits HTML in field labels and descriptions.
64
+ * Added Danish translation.
65
+ * Added Italian translation.
66
+ * Added German translation.
67
+ * Core integration: Fully supports PHP 5.2.
68
+ * Bug fix: Persists shortcode attributes and inner content when there isn't UI registered for them. Previously, they would be discarded.
69
+ * Bug fix: Display the description on the post select field.
70
+ * Bug fix: Attribute field change event binds to `input` event rather than `keyup`.
71
+ * [Full release notes](http://fusion.net/story/225765/introducing-shortcake-v0-6-0-cream/)
72
+
73
  = 0.5.0 (August 26, 2015) =
74
  * Attachment field: Made it easier to change the attachment by clicking on the thumbnail; added attachment metadata in the field view.
75
  * Attachment field: Refactored JavaScript to trigger events.
shortcode-ui.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /**
3
  * Plugin Name: Shortcake (Shortcode UI)
4
- * Version: 0.5.0
5
  * Description: User Interface for adding shortcodes.
6
  * Author: Fusion Engineering and community
7
  * Author URI: http://next.fusion.net/tag/shortcode-ui/
@@ -19,7 +19,7 @@
19
  * GNU General Public License for more details.
20
  */
21
 
22
- define( 'SHORTCODE_UI_VERSION', '0.5.0' );
23
 
24
  require_once dirname( __FILE__ ) . '/inc/class-shortcode-ui.php';
25
  require_once dirname( __FILE__ ) . '/inc/fields/class-shortcode-ui-fields.php';
@@ -29,15 +29,20 @@ require_once dirname( __FILE__ ) . '/inc/fields/class-field-post-select.php';
29
 
30
  add_action( 'init', 'shortcode_ui_load_textdomain' );
31
 
32
- add_action( 'init', function() {
33
 
 
 
 
 
 
 
34
  $shortcode_ui = Shortcode_UI::get_instance();
35
  $fields = Shortcode_UI_Fields::get_instance();
36
  $attachment_field = Shortcake_Field_Attachment::get_instance();
37
  $color_field = Shortcake_Field_Color::get_instance();
38
  $post_field = Shortcode_UI_Field_Post_Select::get_instance();
39
-
40
- }, 5 );
41
 
42
  /**
43
  * Load translations
@@ -45,7 +50,21 @@ add_action( 'init', function() {
45
  * @return null
46
  */
47
  function shortcode_ui_load_textdomain() {
48
- load_plugin_textdomain( 'shortcode-ui', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  }
50
 
51
  /**
@@ -56,6 +75,28 @@ function shortcode_ui_load_textdomain() {
56
  * @return null
57
  */
58
  function shortcode_ui_register_for_shortcode( $shortcode_tag, $args = array() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  Shortcode_UI::get_instance()->register_shortcode_ui( $shortcode_tag, $args );
60
  }
61
 
1
  <?php
2
  /**
3
  * Plugin Name: Shortcake (Shortcode UI)
4
+ * Version: 0.6.0
5
  * Description: User Interface for adding shortcodes.
6
  * Author: Fusion Engineering and community
7
  * Author URI: http://next.fusion.net/tag/shortcode-ui/
19
  * GNU General Public License for more details.
20
  */
21
 
22
+ define( 'SHORTCODE_UI_VERSION', '0.6.0' );
23
 
24
  require_once dirname( __FILE__ ) . '/inc/class-shortcode-ui.php';
25
  require_once dirname( __FILE__ ) . '/inc/fields/class-shortcode-ui-fields.php';
29
 
30
  add_action( 'init', 'shortcode_ui_load_textdomain' );
31
 
32
+ add_action( 'init', 'shortcode_ui_init', 5 );
33
 
34
+ /**
35
+ * Init Shortcake
36
+ *
37
+ * @return null
38
+ */
39
+ function shortcode_ui_init() {
40
  $shortcode_ui = Shortcode_UI::get_instance();
41
  $fields = Shortcode_UI_Fields::get_instance();
42
  $attachment_field = Shortcake_Field_Attachment::get_instance();
43
  $color_field = Shortcake_Field_Color::get_instance();
44
  $post_field = Shortcode_UI_Field_Post_Select::get_instance();
45
+ }
 
46
 
47
  /**
48
  * Load translations
50
  * @return null
51
  */
52
  function shortcode_ui_load_textdomain() {
53
+ // Don't use load_plugin_textdomain because it doesn't support non-standard directories
54
+ // See https://core.trac.wordpress.org/ticket/23794
55
+ $locale = get_locale();
56
+ $domain = 'shortcode-ui';
57
+ $locale = apply_filters( 'plugin_locale', $locale, $domain );
58
+ $path = dirname( __FILE__ ) . '/languages';
59
+ // Load the textdomain according to the plugin first
60
+ $mofile = $domain . '-' . $locale . '.mo';
61
+ if ( $loaded = load_textdomain( $domain, $path . '/'. $mofile ) ) {
62
+ return;
63
+ }
64
+
65
+ // Otherwise, load from the languages directory
66
+ $mofile = WP_LANG_DIR . '/plugins/' . $mofile;
67
+ load_textdomain( $domain, $mofile );
68
  }
69
 
70
  /**
75
  * @return null
76
  */
77
  function shortcode_ui_register_for_shortcode( $shortcode_tag, $args = array() ) {
78
+
79
+ /**
80
+ * Filter the Shortcode UI options for all registered shortcodes.
81
+ *
82
+ * @since 0.6.0
83
+ *
84
+ * @param array $args The configuration argument array specified in shortcode_ui_register_for_shortcode()
85
+ * @param string $shortcode_tag The shortcode base.
86
+ */
87
+ $args = apply_filters( 'shortcode_ui_shortcode_args', $args, $shortcode_tag );
88
+
89
+ /**
90
+ * Filter the Shortcode UI options for a specific registered shortcode.
91
+ *
92
+ * This dynamic filter uses the shortcode base and thus lets you hook on the options on a specific shortcode.
93
+ *
94
+ * @since 0.6.0
95
+ *
96
+ * @param array $args The configuration argument array specified in shortcode_ui_register_for_shortcode()
97
+ */
98
+ $args = apply_filters( "shortcode_ui_shortcode_args_{$shortcode_tag}", $args );
99
+
100
  Shortcode_UI::get_instance()->register_shortcode_ui( $shortcode_tag, $args );
101
  }
102