Meta Box - Version 4.8.0

Version Description

  • Improvement: rewrite the way the plugin loads file, which allows developers to include the plugin into themes/plugins simply by include the main file. The new loading mechanism also uses autoloading feature which prevents loading files twice and saves memory.
  • Improvement: rewrite user, post, taxonomy fields using the same codebase as they're native WordPress objects and sharing similar options. Also changes the syntax of query parameters for these fields (old syntax still works). Please see docs for details.
  • Improvement: add srcset in the returned value of helper function for image fields
  • Improvement: better sanitize value for url field
  • Improvement: prevent issues with dashes in field types
  • Improvement: remove redundant value in checkbox
  • Improvement: update CSS for date, time fields
  • Improvement: select2 now updated to 4.0.1
  • Improvement: optimize code for file_advanced and image_advanced fields which now submit array of values when saving instead of single CSV value
  • Improvement: add collapse option to checkbox_list and checkbox_tree in user, taxonomy, post fields which prevents plugin save parent values.
  • Improvement: secure password field so it is no longer saved in plain text. To check if a password matches the hash, please use wp_check_password.
  • Improvement: change the output of color field in the helper function. Now it shows the color instead of hex value.
  • Improvement: add color:change and color:clear JavaScript event for detecting changes in color field.
  • Improvement: refactor code for better structure and security
  • Fix: rewrite the JavaScript for cloning which causes bugs for date field.
  • Fix: fix missing attributes if value is '0' or 0.
  • Fix: add missing class attribute for fields
  • Fix: do not auto populate color field with '#'
  • Fix: wrong callback for fix page template
Download this release

Release Info

Developer rilwis
Plugin Icon 128x128 Meta Box
Version 4.8.0
Comparing to
See all releases

Code changes from version 4.7.3 to 4.8.0

Files changed (83) hide show
  1. css/datepicker.css +9 -1
  2. css/object-choice.css +15 -0
  3. css/select-advanced.css +1 -1
  4. css/select2/select2-spinner.gif +0 -0
  5. css/select2/select2.css +452 -673
  6. css/select2/select2.png +0 -0
  7. css/select2/select2x2.png +0 -0
  8. css/taxonomy.css +0 -14
  9. inc/common.php +0 -55
  10. inc/core.php +132 -0
  11. inc/field-multiple-values.php +0 -78
  12. inc/field.php +420 -447
  13. inc/fields/autocomplete.php +91 -101
  14. inc/fields/button.php +43 -33
  15. inc/fields/checkbox-list.php +55 -29
  16. inc/fields/checkbox.php +77 -88
  17. inc/fields/color.php +73 -57
  18. inc/fields/custom-html.php +17 -20
  19. inc/fields/date.php +86 -59
  20. inc/fields/datetime.php +177 -150
  21. inc/fields/divider.php +36 -39
  22. inc/fields/email.php +42 -45
  23. inc/fields/fieldset-text.php +68 -74
  24. inc/fields/file-advanced.php +39 -6
  25. inc/fields/file-input.php +56 -55
  26. inc/fields/file.php +313 -328
  27. inc/fields/heading.php +37 -40
  28. inc/fields/hidden.php +16 -25
  29. inc/fields/image-advanced.php +49 -44
  30. inc/fields/image-select.php +89 -96
  31. inc/fields/image.php +203 -211
  32. inc/fields/input.php +69 -73
  33. inc/fields/key-value.php +131 -140
  34. inc/fields/map.php +136 -138
  35. inc/fields/media.php +187 -231
  36. inc/fields/multiple-values.php +73 -0
  37. inc/fields/number.php +38 -31
  38. inc/fields/object-choice.php +238 -0
  39. inc/fields/oembed.php +86 -101
  40. inc/fields/password.php +28 -22
  41. inc/fields/plupload-image.php +148 -182
  42. inc/fields/post.php +108 -142
  43. inc/fields/radio.php +58 -66
  44. inc/fields/range.php +65 -59
  45. inc/fields/select-advanced.php +68 -66
  46. inc/fields/select.php +158 -182
  47. inc/fields/slider.php +57 -59
  48. inc/fields/taxonomy-advanced.php +77 -81
  49. inc/fields/taxonomy.php +147 -289
  50. inc/fields/text-list.php +68 -71
  51. inc/fields/text.php +39 -33
  52. inc/fields/textarea.php +71 -63
  53. inc/fields/thickbox-image.php +47 -49
  54. inc/fields/time.php +82 -61
  55. inc/fields/url.php +30 -36
  56. inc/fields/user.php +77 -86
  57. inc/fields/wysiwyg.php +95 -97
  58. inc/functions.php +110 -0
  59. inc/helper.php +53 -0
  60. inc/helpers.php +0 -271
  61. inc/init.php +0 -48
  62. inc/loader.php +133 -0
  63. inc/meta-box.php +343 -389
  64. inc/validation.php +12 -15
  65. inc/walkers/choice-list-walker.php +70 -0
  66. inc/walkers/select-tree-walker.php +75 -0
  67. inc/walkers/select-walker.php +32 -0
  68. inc/walkers/walker.php +34 -0
  69. js/autocomplete.js +7 -14
  70. js/clone.js +46 -46
  71. js/color.js +19 -13
  72. js/date.js +1 -1
  73. js/datetime.js +1 -1
  74. js/media.js +33 -84
  75. js/object-choice.js +45 -0
  76. js/plupload-image.js +2 -4
  77. js/select-advanced.js +2 -2
  78. js/select2/select2.min.js +2 -23
  79. js/taxonomy.js +0 -31
  80. js/time.js +1 -1
  81. meta-box-loader.php +0 -18
  82. meta-box.php +4 -39
  83. readme.txt +26 -3
css/datepicker.css CHANGED
@@ -17,7 +17,8 @@
17
  font-size: 13px;
18
  margin: 0;
19
  }
20
- .ui-datepicker .ui-datepicker-header {
 
21
  border: none;
22
  background: #23282d;
23
  color: #fff;
@@ -100,6 +101,7 @@
100
  /* Other Datepicker Color Schemes */
101
  /* Blue */
102
  .admin-color-blue .ui-datepicker .ui-datepicker-header,
 
103
  .admin-color-blue .ui-datepicker .ui-datepicker-header .ui-state-hover,
104
  .admin-color-blue .ui-datepicker thead {
105
  background: #4796b3;
@@ -113,6 +115,7 @@
113
  }
114
  /* Coffee */
115
  .admin-color-coffee .ui-datepicker .ui-datepicker-header,
 
116
  .admin-color-coffee .ui-datepicker .ui-datepicker-header .ui-state-hover,
117
  .admin-color-coffee .ui-datepicker thead {
118
  background: #46403c;
@@ -126,6 +129,7 @@
126
  }
127
  /* Ectoplasm */
128
  .admin-color-ectoplasm .ui-datepicker .ui-datepicker-header,
 
129
  .admin-color-ectoplasm .ui-datepicker .ui-datepicker-header .ui-state-hover,
130
  .admin-color-ectoplasm .ui-datepicker thead {
131
  background: #413256;
@@ -139,6 +143,7 @@
139
  }
140
  /* Midnight */
141
  .admin-color-midnight .ui-datepicker .ui-datepicker-header,
 
142
  .admin-color-midnight .ui-datepicker .ui-datepicker-header .ui-state-hover,
143
  .admin-color-midnight .ui-datepicker thead {
144
  background: #26292c;
@@ -152,6 +157,7 @@
152
  }
153
  /* Ocean */
154
  .admin-color-ocean .ui-datepicker .ui-datepicker-header,
 
155
  .admin-color-ocean .ui-datepicker .ui-datepicker-header .ui-state-hover,
156
  .admin-color-ocean .ui-datepicker thead {
157
  background: #627c83;
@@ -165,6 +171,7 @@
165
  }
166
  /* Sunrise */
167
  .admin-color-sunrise .ui-datepicker .ui-datepicker-header,
 
168
  .admin-color-sunrise .ui-datepicker .ui-datepicker-header .ui-state-hover,
169
  .admin-color-sunrise .ui-datepicker thead {
170
  background: #be3631;
@@ -178,6 +185,7 @@
178
  }
179
  /* Light */
180
  .admin-color-light .ui-datepicker .ui-datepicker-header,
 
181
  .admin-color-light .ui-datepicker .ui-datepicker-header .ui-state-hover,
182
  .admin-color-light .ui-datepicker thead {
183
  background: #e5e5e5;
17
  font-size: 13px;
18
  margin: 0;
19
  }
20
+ .ui-datepicker .ui-datepicker-header,
21
+ .ui-timepicker-div .ui-widget-header{
22
  border: none;
23
  background: #23282d;
24
  color: #fff;
101
  /* Other Datepicker Color Schemes */
102
  /* Blue */
103
  .admin-color-blue .ui-datepicker .ui-datepicker-header,
104
+ .admin-color-blue .ui-timepicker-div .ui-widget-header,
105
  .admin-color-blue .ui-datepicker .ui-datepicker-header .ui-state-hover,
106
  .admin-color-blue .ui-datepicker thead {
107
  background: #4796b3;
115
  }
116
  /* Coffee */
117
  .admin-color-coffee .ui-datepicker .ui-datepicker-header,
118
+ .admin-color-cofee .ui-timepicker-div .ui-widget-header,
119
  .admin-color-coffee .ui-datepicker .ui-datepicker-header .ui-state-hover,
120
  .admin-color-coffee .ui-datepicker thead {
121
  background: #46403c;
129
  }
130
  /* Ectoplasm */
131
  .admin-color-ectoplasm .ui-datepicker .ui-datepicker-header,
132
+ .admin-color-ectoplasm .ui-timepicker-div .ui-widget-header,
133
  .admin-color-ectoplasm .ui-datepicker .ui-datepicker-header .ui-state-hover,
134
  .admin-color-ectoplasm .ui-datepicker thead {
135
  background: #413256;
143
  }
144
  /* Midnight */
145
  .admin-color-midnight .ui-datepicker .ui-datepicker-header,
146
+ .admin-color-midnight .ui-timepicker-div .ui-widget-header,
147
  .admin-color-midnight .ui-datepicker .ui-datepicker-header .ui-state-hover,
148
  .admin-color-midnight .ui-datepicker thead {
149
  background: #26292c;
157
  }
158
  /* Ocean */
159
  .admin-color-ocean .ui-datepicker .ui-datepicker-header,
160
+ .admin-color-ocean .ui-timepicker-div .ui-widget-header,
161
  .admin-color-ocean .ui-datepicker .ui-datepicker-header .ui-state-hover,
162
  .admin-color-ocean .ui-datepicker thead {
163
  background: #627c83;
171
  }
172
  /* Sunrise */
173
  .admin-color-sunrise .ui-datepicker .ui-datepicker-header,
174
+ .admin-color-sunrise .ui-timepicker-div .ui-widget-header,
175
  .admin-color-sunrise .ui-datepicker .ui-datepicker-header .ui-state-hover,
176
  .admin-color-sunrise .ui-datepicker thead {
177
  background: #be3631;
185
  }
186
  /* Light */
187
  .admin-color-light .ui-datepicker .ui-datepicker-header,
188
+ .admin-color-light .ui-timepicker-div .ui-widget-header,
189
  .admin-color-light .ui-datepicker .ui-datepicker-header .ui-state-hover,
190
  .admin-color-light .ui-datepicker thead {
191
  background: #e5e5e5;
css/object-choice.css ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .rwmb-choice-list li{
2
+ line-height: 22px;
3
+ }
4
+
5
+ li .rwmb-choice-list {
6
+ margin-left: 15px;
7
+ }
8
+
9
+ .rwmb-select-tree {
10
+ display: inline-block;
11
+ }
12
+
13
+ .rwmb-select-tree.hidden {
14
+ display: none;
15
+ }
css/select-advanced.css CHANGED
@@ -1,4 +1,4 @@
1
- #post-body .rwmb-select-advanced {
2
  height: auto;
3
  min-width: 200px;
4
  }
1
+ .rwmb-field .select2-container {
2
  height: auto;
3
  min-width: 200px;
4
  }
css/select2/select2-spinner.gif DELETED
Binary file
css/select2/select2.css CHANGED
@@ -1,704 +1,483 @@
1
- /*
2
- Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014
3
- */
4
  .select2-container {
5
- margin: 0;
6
- position: relative;
7
- display: inline-block;
8
- /* inline-block for ie7 */
9
- zoom: 1;
10
- *display: inline;
11
- vertical-align: middle;
12
- }
13
-
14
- .select2-container,
15
- .select2-drop,
16
- .select2-search,
17
- .select2-search input {
18
- /*
19
- Force border-box so that % widths fit the parent
20
- container without overlap because of margin/padding.
21
- More Info : http://www.quirksmode.org/css/box.html
22
- */
23
- -webkit-box-sizing: border-box; /* webkit */
24
- -moz-box-sizing: border-box; /* firefox */
25
- box-sizing: border-box; /* css3 */
26
- }
27
-
28
- .select2-container .select2-choice {
29
- display: block;
30
- height: 26px;
31
- padding: 0 0 0 8px;
32
- overflow: hidden;
33
- position: relative;
34
-
35
- border: 1px solid #aaa;
36
- white-space: nowrap;
37
- line-height: 26px;
38
- color: #444;
39
- text-decoration: none;
40
-
41
- border-radius: 4px;
42
-
43
- background-clip: padding-box;
44
-
45
- -webkit-touch-callout: none;
46
- -webkit-user-select: none;
47
- -moz-user-select: none;
48
- -ms-user-select: none;
49
- user-select: none;
50
-
51
- background-color: #fff;
52
- background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff));
53
- background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%);
54
- background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%);
55
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0);
56
- background-image: linear-gradient(to top, #eee 0%, #fff 50%);
57
- }
58
-
59
- html[dir="rtl"] .select2-container .select2-choice {
60
- padding: 0 8px 0 0;
61
- }
62
-
63
- .select2-container.select2-drop-above .select2-choice {
64
- border-bottom-color: #aaa;
65
-
66
- border-radius: 0 0 4px 4px;
67
-
68
- background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff));
69
- background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%);
70
- background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%);
71
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
72
- background-image: linear-gradient(to bottom, #eee 0%, #fff 90%);
73
- }
74
-
75
- .select2-container.select2-allowclear .select2-choice .select2-chosen {
76
- margin-right: 42px;
77
- }
78
-
79
- .select2-container .select2-choice > .select2-chosen {
80
- margin-right: 26px;
81
- display: block;
82
- overflow: hidden;
83
-
84
- white-space: nowrap;
85
-
86
- text-overflow: ellipsis;
87
- float: none;
88
- width: auto;
89
- }
90
-
91
- html[dir="rtl"] .select2-container .select2-choice > .select2-chosen {
92
- margin-left: 26px;
93
- margin-right: 0;
94
- }
95
-
96
- .select2-container .select2-choice abbr {
97
- display: none;
98
- width: 12px;
99
- height: 12px;
100
- position: absolute;
101
- right: 24px;
102
- top: 8px;
103
-
104
- font-size: 1px;
105
- text-decoration: none;
106
-
107
- border: 0;
108
- background: url('select2.png') right top no-repeat;
109
  cursor: pointer;
110
- outline: 0;
111
- }
112
-
113
- .select2-container.select2-allowclear .select2-choice abbr {
114
- display: inline-block;
115
- }
116
-
117
- .select2-container .select2-choice abbr:hover {
118
- background-position: right -11px;
 
 
 
 
 
 
 
 
 
119
  cursor: pointer;
120
- }
121
-
122
- .select2-drop-mask {
123
- border: 0;
124
- margin: 0;
125
- padding: 0;
126
- position: fixed;
127
- left: 0;
128
- top: 0;
129
- min-height: 100%;
130
- min-width: 100%;
131
- height: auto;
132
- width: auto;
133
- opacity: 0;
134
- z-index: 9998;
135
- /* styles required for IE to work */
136
- background-color: #fff;
137
- filter: alpha(opacity=0);
138
- }
139
-
140
- .select2-drop {
141
- width: 100%;
142
- margin-top: -1px;
143
- position: absolute;
144
- z-index: 9999;
145
- top: 100%;
146
-
147
- background: #fff;
148
- color: #000;
149
- border: 1px solid #aaa;
150
- border-top: 0;
151
-
152
- border-radius: 0 0 4px 4px;
153
-
154
- -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
155
- box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
156
- }
157
-
158
- .select2-drop.select2-drop-above {
159
- margin-top: 1px;
160
- border-top: 1px solid #aaa;
161
- border-bottom: 0;
162
-
163
- border-radius: 4px 4px 0 0;
164
-
165
- -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
166
- box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
167
- }
168
-
169
- .select2-drop-active {
170
- border: 1px solid #5897fb;
171
- border-top: none;
172
- }
173
-
174
- .select2-drop.select2-drop-above.select2-drop-active {
175
- border-top: 1px solid #5897fb;
176
- }
177
-
178
- .select2-drop-auto-width {
179
- border-top: 1px solid #aaa;
180
- width: auto;
181
- }
182
-
183
- .select2-drop-auto-width .select2-search {
184
- padding-top: 4px;
185
- }
186
-
187
- .select2-container .select2-choice .select2-arrow {
188
- display: inline-block;
189
- width: 18px;
190
- height: 100%;
191
- position: absolute;
192
- right: 0;
193
- top: 0;
194
-
195
- border-left: 1px solid #aaa;
196
- border-radius: 0 4px 4px 0;
197
-
198
- background-clip: padding-box;
199
-
200
- background: #ccc;
201
- background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee));
202
- background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%);
203
- background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%);
204
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0);
205
- background-image: linear-gradient(to top, #ccc 0%, #eee 60%);
206
- }
207
-
208
- html[dir="rtl"] .select2-container .select2-choice .select2-arrow {
209
- left: 0;
210
- right: auto;
211
-
212
- border-left: none;
213
- border-right: 1px solid #aaa;
214
- border-radius: 4px 0 0 4px;
215
- }
216
-
217
- .select2-container .select2-choice .select2-arrow b {
218
  display: block;
219
- width: 100%;
220
- height: 100%;
221
- background: url('select2.png') no-repeat 0 1px;
222
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
- html[dir="rtl"] .select2-container .select2-choice .select2-arrow b {
225
- background-position: 2px 1px;
226
- }
227
-
228
- .select2-search {
229
- display: inline-block;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  width: 100%;
231
- min-height: 26px;
232
- margin: 0;
233
- padding-left: 4px;
234
- padding-right: 4px;
235
-
236
- position: relative;
237
- z-index: 10000;
238
-
239
- white-space: nowrap;
240
- }
241
-
242
- .select2-search input {
243
- width: 100%;
244
- height: auto !important;
245
- min-height: 26px;
246
- padding: 4px 20px 4px 5px;
247
- margin: 0;
248
-
249
- outline: 0;
250
- font-family: sans-serif;
251
- font-size: 1em;
252
-
253
- border: 1px solid #aaa;
254
- border-radius: 0;
255
-
256
- -webkit-box-shadow: none;
257
- box-shadow: none;
258
-
259
- background: #fff url('select2.png') no-repeat 100% -22px;
260
- background: url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
261
- background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
262
- background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
263
- background: url('select2.png') no-repeat 100% -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
264
- }
265
-
266
- html[dir="rtl"] .select2-search input {
267
- padding: 4px 5px 4px 20px;
268
-
269
- background: #fff url('select2.png') no-repeat -37px -22px;
270
- background: url('select2.png') no-repeat -37px -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
271
- background: url('select2.png') no-repeat -37px -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
272
- background: url('select2.png') no-repeat -37px -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
273
- background: url('select2.png') no-repeat -37px -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
274
- }
275
-
276
- .select2-drop.select2-drop-above .select2-search input {
277
- margin-top: 4px;
278
- }
279
-
280
- .select2-search input.select2-active {
281
- background: #fff url('select2-spinner.gif') no-repeat 100%;
282
- background: url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
283
- background: url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
284
- background: url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
285
- background: url('select2-spinner.gif') no-repeat 100%, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0;
286
- }
287
-
288
- .select2-container-active .select2-choice,
289
- .select2-container-active .select2-choices {
290
- border: 1px solid #5897fb;
291
- outline: none;
292
-
293
- -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
294
- box-shadow: 0 0 5px rgba(0, 0, 0, .3);
295
- }
296
-
297
- .select2-dropdown-open .select2-choice {
298
- border-bottom-color: transparent;
299
- -webkit-box-shadow: 0 1px 0 #fff inset;
300
- box-shadow: 0 1px 0 #fff inset;
301
-
302
- border-bottom-left-radius: 0;
303
- border-bottom-right-radius: 0;
304
-
305
- background-color: #eee;
306
- background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee));
307
- background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%);
308
- background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%);
309
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
310
- background-image: linear-gradient(to top, #fff 0%, #eee 50%);
311
- }
312
-
313
- .select2-dropdown-open.select2-drop-above .select2-choice,
314
- .select2-dropdown-open.select2-drop-above .select2-choices {
315
- border: 1px solid #5897fb;
316
- border-top-color: transparent;
317
-
318
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee));
319
- background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%);
320
- background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%);
321
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
322
- background-image: linear-gradient(to bottom, #fff 0%, #eee 50%);
323
- }
324
-
325
- .select2-dropdown-open .select2-choice .select2-arrow {
326
- background: transparent;
327
- border-left: none;
328
- filter: none;
329
- }
330
- html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow {
331
- border-right: none;
332
- }
333
-
334
- .select2-dropdown-open .select2-choice .select2-arrow b {
335
- background-position: -18px 1px;
336
- }
337
-
338
- html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow b {
339
- background-position: -16px 1px;
340
- }
341
 
342
  .select2-hidden-accessible {
343
- border: 0;
344
- clip: rect(0 0 0 0);
345
- height: 1px;
346
- margin: -1px;
347
- overflow: hidden;
348
- padding: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
  position: absolute;
350
- width: 1px;
351
- }
352
-
353
- /* results */
354
- .select2-results {
355
- max-height: 200px;
356
- padding: 0 0 0 4px;
357
- margin: 4px 4px 4px 0;
358
- position: relative;
359
- overflow-x: hidden;
360
- overflow-y: auto;
361
- -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
362
- }
363
-
364
- html[dir="rtl"] .select2-results {
365
- padding: 0 4px 0 0;
366
- margin: 4px 0 4px 4px;
367
- }
368
-
369
- .select2-results ul.select2-result-sub {
370
- margin: 0;
371
- padding-left: 0;
372
- }
373
-
374
- .select2-results li {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
  list-style: none;
376
- display: list-item;
377
- background-image: none;
378
- }
379
-
380
- .select2-results li.select2-result-with-children > .select2-result-label {
381
- font-weight: bold;
382
- }
383
-
384
- .select2-results .select2-result-label {
385
- padding: 3px 7px 4px;
386
  margin: 0;
 
 
 
 
 
 
 
387
  cursor: pointer;
388
-
389
- min-height: 1em;
390
-
391
- -webkit-touch-callout: none;
392
- -webkit-user-select: none;
393
- -moz-user-select: none;
394
- -ms-user-select: none;
395
- user-select: none;
396
- }
397
-
398
- .select2-results-dept-1 .select2-result-label { padding-left: 20px }
399
- .select2-results-dept-2 .select2-result-label { padding-left: 40px }
400
- .select2-results-dept-3 .select2-result-label { padding-left: 60px }
401
- .select2-results-dept-4 .select2-result-label { padding-left: 80px }
402
- .select2-results-dept-5 .select2-result-label { padding-left: 100px }
403
- .select2-results-dept-6 .select2-result-label { padding-left: 110px }
404
- .select2-results-dept-7 .select2-result-label { padding-left: 120px }
405
-
406
- .select2-results .select2-highlighted {
407
- background: #3875d7;
408
- color: #fff;
409
- }
410
-
411
- .select2-results li em {
412
- background: #feffde;
413
- font-style: normal;
414
- }
415
-
416
- .select2-results .select2-highlighted em {
417
- background: transparent;
418
- }
419
-
420
- .select2-results .select2-highlighted ul {
421
- background: #fff;
422
- color: #000;
423
- }
424
-
425
- .select2-results .select2-no-results,
426
- .select2-results .select2-searching,
427
- .select2-results .select2-ajax-error,
428
- .select2-results .select2-selection-limit {
429
- background: #f4f4f4;
430
- display: list-item;
431
- padding-left: 5px;
432
- }
433
-
434
- /*
435
- disabled look for disabled choices in the results dropdown
436
- */
437
- .select2-results .select2-disabled.select2-highlighted {
438
- color: #666;
439
- background: #f4f4f4;
440
- display: list-item;
441
  cursor: default;
442
- }
443
- .select2-results .select2-disabled {
444
- background: #f4f4f4;
445
- display: list-item;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
  cursor: default;
447
- }
448
-
449
- .select2-results .select2-selected {
450
- display: none;
451
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
452
 
453
- .select2-more-results.select2-active {
454
- background: #f4f4f4 url('select2-spinner.gif') no-repeat 100%;
455
- }
456
 
457
- .select2-results .select2-ajax-error {
458
- background: rgba(255, 50, 50, .2);
459
- }
460
 
461
- .select2-more-results {
462
- background: #f4f4f4;
463
- display: list-item;
464
- }
465
 
466
- /* disabled styles */
 
467
 
468
- .select2-container.select2-container-disabled .select2-choice {
469
- background-color: #f4f4f4;
470
- background-image: none;
471
- border: 1px solid #ddd;
472
- cursor: default;
473
- }
474
 
475
- .select2-container.select2-container-disabled .select2-choice .select2-arrow {
476
- background-color: #f4f4f4;
477
- background-image: none;
478
- border-left: 0;
479
- }
480
 
481
- .select2-container.select2-container-disabled .select2-choice abbr {
482
- display: none;
483
- }
484
 
 
 
 
485
 
486
- /* multiselect */
 
 
487
 
488
- .select2-container-multi .select2-choices {
489
- height: auto !important;
490
- height: 1%;
491
- margin: 0;
492
- padding: 0 5px 0 0;
493
- position: relative;
494
 
495
- border: 1px solid #aaa;
496
- cursor: text;
497
- overflow: hidden;
498
-
499
- background-color: #fff;
500
- background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff));
501
- background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%);
502
- background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%);
503
- background-image: linear-gradient(to bottom, #eee 1%, #fff 15%);
504
- }
505
-
506
- html[dir="rtl"] .select2-container-multi .select2-choices {
507
- padding: 0 0 0 5px;
508
- }
509
-
510
- .select2-locked {
511
- padding: 3px 5px 3px 5px !important;
512
- }
513
-
514
- .select2-container-multi .select2-choices {
515
- min-height: 26px;
516
- }
517
-
518
- .select2-container-multi.select2-container-active .select2-choices {
519
- border: 1px solid #5897fb;
520
- outline: none;
521
-
522
- -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
523
- box-shadow: 0 0 5px rgba(0, 0, 0, .3);
524
- }
525
- .select2-container-multi .select2-choices li {
526
- float: left;
527
- list-style: none;
528
- }
529
- html[dir="rtl"] .select2-container-multi .select2-choices li
530
- {
531
- float: right;
532
- }
533
- .select2-container-multi .select2-choices .select2-search-field {
534
- margin: 0;
535
- padding: 0;
536
- white-space: nowrap;
537
- }
538
-
539
- .select2-container-multi .select2-choices .select2-search-field input {
540
- padding: 5px;
541
- margin: 1px 0;
542
-
543
- font-family: sans-serif;
544
- font-size: 100%;
545
- color: #666;
546
- outline: 0;
547
- border: 0;
548
- -webkit-box-shadow: none;
549
- box-shadow: none;
550
- background: transparent !important;
551
- }
552
-
553
- .select2-container-multi .select2-choices .select2-search-field input.select2-active {
554
- background: #fff url('select2-spinner.gif') no-repeat 100% !important;
555
- }
556
-
557
- .select2-default {
558
- color: #999 !important;
559
- }
560
-
561
- .select2-container-multi .select2-choices .select2-search-choice {
562
- padding: 3px 5px 3px 18px;
563
- margin: 3px 0 3px 5px;
564
- position: relative;
565
-
566
- line-height: 13px;
567
- color: #333;
568
- cursor: default;
569
- border: 1px solid #aaaaaa;
570
 
571
- border-radius: 3px;
 
 
572
 
573
- -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
574
- box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
575
 
576
- background-clip: padding-box;
 
577
 
578
- -webkit-touch-callout: none;
579
- -webkit-user-select: none;
580
- -moz-user-select: none;
581
- -ms-user-select: none;
582
- user-select: none;
583
 
584
- background-color: #e4e4e4;
585
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0);
586
- background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee));
587
- background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
588
- background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
589
- background-image: linear-gradient(to bottom, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
590
- }
591
- html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice
592
- {
593
- margin: 3px 5px 3px 0;
594
- padding: 3px 18px 3px 5px;
595
- }
596
- .select2-container-multi .select2-choices .select2-search-choice .select2-chosen {
597
- cursor: default;
598
- }
599
- .select2-container-multi .select2-choices .select2-search-choice-focus {
600
- background: #d4d4d4;
601
- }
602
 
603
- .select2-search-choice-close {
604
- display: block;
605
- width: 12px;
606
- height: 13px;
607
- position: absolute;
608
- right: 3px;
609
- top: 4px;
610
-
611
- font-size: 1px;
612
- outline: none;
613
- background: url('select2.png') right top no-repeat;
614
- }
615
- html[dir="rtl"] .select2-search-choice-close {
616
- right: auto;
617
- left: 3px;
618
- }
619
-
620
- .select2-container-multi .select2-search-choice-close {
621
- left: 3px;
622
- }
623
-
624
- html[dir="rtl"] .select2-container-multi .select2-search-choice-close {
625
- left: auto;
626
- right: 2px;
627
- }
628
-
629
- .select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover {
630
- background-position: right -11px;
631
- }
632
- .select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close {
633
- background-position: right -11px;
634
- }
635
-
636
- /* disabled styles */
637
- .select2-container-multi.select2-container-disabled .select2-choices {
638
- background-color: #f4f4f4;
639
- background-image: none;
640
- border: 1px solid #ddd;
641
- cursor: default;
642
- }
643
-
644
- .select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice {
645
- padding: 3px 5px 3px 5px;
646
- border: 1px solid #ddd;
647
- background-image: none;
648
- background-color: #f4f4f4;
649
- }
650
-
651
- .select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none;
652
- background: none;
653
- }
654
- /* end multiselect */
655
-
656
-
657
- .select2-result-selectable .select2-match,
658
- .select2-result-unselectable .select2-match {
659
- text-decoration: underline;
660
- }
661
-
662
- .select2-offscreen, .select2-offscreen:focus {
663
- clip: rect(0 0 0 0) !important;
664
- width: 1px !important;
665
- height: 1px !important;
666
- border: 0 !important;
667
- margin: 0 !important;
668
- padding: 0 !important;
669
- overflow: hidden !important;
670
- position: absolute !important;
671
- outline: 0 !important;
672
- left: 0px !important;
673
- top: 0px !important;
674
- }
675
-
676
- .select2-display-none {
677
- display: none;
678
- }
679
-
680
- .select2-measure-scrollbar {
681
- position: absolute;
682
- top: -10000px;
683
- left: -10000px;
684
- width: 100px;
685
- height: 100px;
686
- overflow: scroll;
687
- }
688
-
689
- /* Retina-ize icons */
690
-
691
- @media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 2dppx) {
692
- .select2-search input,
693
- .select2-search-choice-close,
694
- .select2-container .select2-choice abbr,
695
- .select2-container .select2-choice .select2-arrow b {
696
- background-image: url('select2x2.png') !important;
697
- background-repeat: no-repeat !important;
698
- background-size: 60px 40px !important;
699
- }
700
-
701
- .select2-search input {
702
- background-position: 100% -21px !important;
703
- }
704
- }
 
 
 
1
  .select2-container {
2
+ box-sizing: border-box;
3
+ display: inline-block;
4
+ margin: 0;
5
+ position: relative;
6
+ vertical-align: middle;
7
+ }
8
+ .select2-container .select2-selection--single {
9
+ box-sizing: border-box;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  cursor: pointer;
11
+ display: block;
12
+ height: 28px;
13
+ user-select: none;
14
+ -webkit-user-select: none; }
15
+ .select2-container .select2-selection--single .select2-selection__rendered {
16
+ display: block;
17
+ padding-left: 8px;
18
+ padding-right: 20px;
19
+ overflow: hidden;
20
+ text-overflow: ellipsis;
21
+ white-space: nowrap; }
22
+ .select2-container .select2-selection--single .select2-selection__clear {
23
+ position: relative; }
24
+ .select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
25
+ padding-right: 8px;
26
+ padding-left: 20px; }
27
+ .select2-container .select2-selection--multiple {
28
+ box-sizing: border-box;
29
  cursor: pointer;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  display: block;
31
+ min-height: 32px;
32
+ user-select: none;
33
+ -webkit-user-select: none; }
34
+ .select2-container .select2-selection--multiple .select2-selection__rendered {
35
+ /*display: inline-block;*/
36
+ overflow: hidden;
37
+ padding-left: 8px;
38
+ text-overflow: ellipsis;
39
+ white-space: nowrap; }
40
+ .select2-container .select2-search--inline {
41
+ float: left; }
42
+ .select2-container .select2-search--inline .select2-search__field {
43
+ box-sizing: border-box;
44
+ border: none;
45
+ font-size: 100%;
46
+ margin-top: 5px;
47
+ padding: 0; }
48
+ .select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
49
+ -webkit-appearance: none; }
50
+
51
+ .select2-dropdown {
52
+ background-color: white;
53
+ border: 1px solid #aaa;
54
+ border-radius: 4px;
55
+ box-sizing: border-box;
56
+ display: block;
57
+ position: absolute;
58
+ left: -100000px;
59
+ width: 100%;
60
+ z-index: 1051; }
61
 
62
+ .select2-results {
63
+ display: block; }
64
+
65
+ .select2-results__options {
66
+ list-style: none;
67
+ margin: 0;
68
+ padding: 0; }
69
+
70
+ .select2-results__option {
71
+ padding: 6px;
72
+ user-select: none;
73
+ -webkit-user-select: none; }
74
+ .select2-results__option[aria-selected] {
75
+ cursor: pointer; }
76
+
77
+ .select2-container--open .select2-dropdown {
78
+ left: 0; }
79
+
80
+ .select2-container--open .select2-dropdown--above {
81
+ border-bottom: none;
82
+ border-bottom-left-radius: 0;
83
+ border-bottom-right-radius: 0; }
84
+
85
+ .select2-container--open .select2-dropdown--below {
86
+ border-top: none;
87
+ border-top-left-radius: 0;
88
+ border-top-right-radius: 0; }
89
+
90
+ .select2-search--dropdown {
91
+ display: block;
92
+ padding: 4px; }
93
+ .select2-search--dropdown .select2-search__field {
94
+ padding: 4px;
95
  width: 100%;
96
+ box-sizing: border-box; }
97
+ .select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
98
+ -webkit-appearance: none; }
99
+ .select2-search--dropdown.select2-search--hide {
100
+ display: none; }
101
+
102
+ .select2-close-mask {
103
+ border: 0;
104
+ margin: 0;
105
+ padding: 0;
106
+ display: block;
107
+ position: fixed;
108
+ left: 0;
109
+ top: 0;
110
+ min-height: 100%;
111
+ min-width: 100%;
112
+ height: auto;
113
+ width: auto;
114
+ opacity: 0;
115
+ z-index: 99;
116
+ background-color: #fff;
117
+ filter: alpha(opacity=0); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
  .select2-hidden-accessible {
120
+ border: 0 !important;
121
+ clip: rect(0 0 0 0) !important;
122
+ height: 1px !important;
123
+ margin: -1px !important;
124
+ overflow: hidden !important;
125
+ padding: 0 !important;
126
+ position: absolute !important;
127
+ width: 1px !important; }
128
+
129
+ .select2-container--default .select2-selection--single {
130
+ background-color: #fff;
131
+ border: 1px solid #aaa;
132
+ border-radius: 4px; }
133
+ .select2-container--default .select2-selection--single .select2-selection__rendered {
134
+ color: #444;
135
+ line-height: 28px; }
136
+ .select2-container--default .select2-selection--single .select2-selection__clear {
137
+ cursor: pointer;
138
+ float: right;
139
+ font-weight: bold; }
140
+ .select2-container--default .select2-selection--single .select2-selection__placeholder {
141
+ color: #999; }
142
+ .select2-container--default .select2-selection--single .select2-selection__arrow {
143
+ height: 26px;
144
  position: absolute;
145
+ top: 1px;
146
+ right: 1px;
147
+ width: 20px; }
148
+ .select2-container--default .select2-selection--single .select2-selection__arrow b {
149
+ border-color: #888 transparent transparent transparent;
150
+ border-style: solid;
151
+ border-width: 5px 4px 0 4px;
152
+ height: 0;
153
+ left: 50%;
154
+ margin-left: -4px;
155
+ margin-top: -2px;
156
+ position: absolute;
157
+ top: 50%;
158
+ width: 0; }
159
+
160
+ .select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
161
+ float: left; }
162
+
163
+ .select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
164
+ left: 1px;
165
+ right: auto; }
166
+
167
+ .select2-container--default.select2-container--disabled .select2-selection--single {
168
+ background-color: #eee;
169
+ cursor: default; }
170
+ .select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
171
+ display: none; }
172
+
173
+ .select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
174
+ border-color: transparent transparent #888 transparent;
175
+ border-width: 0 4px 5px 4px; }
176
+
177
+ .select2-container--default .select2-selection--multiple {
178
+ background-color: white;
179
+ border: 1px solid #aaa;
180
+ border-radius: 4px;
181
+ cursor: text; }
182
+ .select2-container--default .select2-selection--multiple .select2-selection__rendered {
183
+ box-sizing: border-box;
184
  list-style: none;
 
 
 
 
 
 
 
 
 
 
185
  margin: 0;
186
+ padding: 0 5px;
187
+ width: 100%; }
188
+ .select2-container--default .select2-selection--multiple .select2-selection__placeholder {
189
+ color: #999;
190
+ margin-top: 5px;
191
+ float: left; }
192
+ .select2-container--default .select2-selection--multiple .select2-selection__clear {
193
  cursor: pointer;
194
+ float: right;
195
+ font-weight: bold;
196
+ margin-top: 5px;
197
+ margin-right: 10px; }
198
+ .select2-container--default .select2-selection--multiple .select2-selection__choice {
199
+ background-color: #e4e4e4;
200
+ border: 1px solid #aaa;
201
+ border-radius: 4px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  cursor: default;
203
+ float: left;
204
+ margin-right: 5px;
205
+ margin-top: 5px;
206
+ padding: 0 5px; }
207
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
208
+ color: #999;
209
+ cursor: pointer;
210
+ display: inline-block;
211
+ font-weight: bold;
212
+ margin-right: 2px; }
213
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
214
+ color: #333; }
215
+
216
+ .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
217
+ float: right; }
218
+
219
+ .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
220
+ margin-left: 5px;
221
+ margin-right: auto; }
222
+
223
+ .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
224
+ margin-left: 2px;
225
+ margin-right: auto; }
226
+
227
+ .select2-container--default.select2-container--focus .select2-selection--multiple {
228
+ border: solid black 1px;
229
+ outline: 0; }
230
+
231
+ .select2-container--default.select2-container--disabled .select2-selection--multiple {
232
+ background-color: #eee;
233
+ cursor: default; }
234
+
235
+ .select2-container--default.select2-container--disabled .select2-selection__choice__remove {
236
+ display: none; }
237
+
238
+ .select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
239
+ border-top-left-radius: 0;
240
+ border-top-right-radius: 0; }
241
+
242
+ .select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
243
+ border-bottom-left-radius: 0;
244
+ border-bottom-right-radius: 0; }
245
+
246
+ .select2-container--default .select2-search--dropdown .select2-search__field {
247
+ border: 1px solid #aaa; }
248
+
249
+ .select2-container--default .select2-search--inline .select2-search__field {
250
+ background: transparent;
251
+ border: none;
252
+ outline: 0;
253
+ box-shadow: none;
254
+ -webkit-appearance: textfield; }
255
+
256
+ .select2-container--default .select2-results > .select2-results__options {
257
+ max-height: 200px;
258
+ overflow-y: auto; }
259
+
260
+ .select2-container--default .select2-results__option[role=group] {
261
+ padding: 0; }
262
+
263
+ .select2-container--default .select2-results__option[aria-disabled=true] {
264
+ color: #999; }
265
+
266
+ .select2-container--default .select2-results__option[aria-selected=true] {
267
+ background-color: #ddd; }
268
+
269
+ .select2-container--default .select2-results__option .select2-results__option {
270
+ padding-left: 1em; }
271
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__group {
272
+ padding-left: 0; }
273
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option {
274
+ margin-left: -1em;
275
+ padding-left: 2em; }
276
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
277
+ margin-left: -2em;
278
+ padding-left: 3em; }
279
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
280
+ margin-left: -3em;
281
+ padding-left: 4em; }
282
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
283
+ margin-left: -4em;
284
+ padding-left: 5em; }
285
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
286
+ margin-left: -5em;
287
+ padding-left: 6em; }
288
+
289
+ .select2-container--default .select2-results__option--highlighted[aria-selected] {
290
+ background-color: #5897fb;
291
+ color: white; }
292
+
293
+ .select2-container--default .select2-results__group {
294
  cursor: default;
295
+ display: block;
296
+ padding: 6px; }
297
+
298
+ .select2-container--classic .select2-selection--single {
299
+ background-color: #f7f7f7;
300
+ border: 1px solid #aaa;
301
+ border-radius: 4px;
302
+ outline: 0;
303
+ background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
304
+ background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
305
+ background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
306
+ background-repeat: repeat-x;
307
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
308
+ .select2-container--classic .select2-selection--single:focus {
309
+ border: 1px solid #5897fb; }
310
+ .select2-container--classic .select2-selection--single .select2-selection__rendered {
311
+ color: #444;
312
+ line-height: 28px; }
313
+ .select2-container--classic .select2-selection--single .select2-selection__clear {
314
+ cursor: pointer;
315
+ float: right;
316
+ font-weight: bold;
317
+ margin-right: 10px; }
318
+ .select2-container--classic .select2-selection--single .select2-selection__placeholder {
319
+ color: #999; }
320
+ .select2-container--classic .select2-selection--single .select2-selection__arrow {
321
+ background-color: #ddd;
322
+ border: none;
323
+ border-left: 1px solid #aaa;
324
+ border-top-right-radius: 4px;
325
+ border-bottom-right-radius: 4px;
326
+ height: 26px;
327
+ position: absolute;
328
+ top: 1px;
329
+ right: 1px;
330
+ width: 20px;
331
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
332
+ background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
333
+ background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
334
+ background-repeat: repeat-x;
335
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }
336
+ .select2-container--classic .select2-selection--single .select2-selection__arrow b {
337
+ border-color: #888 transparent transparent transparent;
338
+ border-style: solid;
339
+ border-width: 5px 4px 0 4px;
340
+ height: 0;
341
+ left: 50%;
342
+ margin-left: -4px;
343
+ margin-top: -2px;
344
+ position: absolute;
345
+ top: 50%;
346
+ width: 0; }
347
+
348
+ .select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
349
+ float: left; }
350
+
351
+ .select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
352
+ border: none;
353
+ border-right: 1px solid #aaa;
354
+ border-radius: 0;
355
+ border-top-left-radius: 4px;
356
+ border-bottom-left-radius: 4px;
357
+ left: 1px;
358
+ right: auto; }
359
+
360
+ .select2-container--classic.select2-container--open .select2-selection--single {
361
+ border: 1px solid #5897fb; }
362
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
363
+ background: transparent;
364
+ border: none; }
365
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
366
+ border-color: transparent transparent #888 transparent;
367
+ border-width: 0 4px 5px 4px; }
368
+
369
+ .select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
370
+ border-top: none;
371
+ border-top-left-radius: 0;
372
+ border-top-right-radius: 0;
373
+ background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
374
+ background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
375
+ background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
376
+ background-repeat: repeat-x;
377
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
378
+
379
+ .select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
380
+ border-bottom: none;
381
+ border-bottom-left-radius: 0;
382
+ border-bottom-right-radius: 0;
383
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
384
+ background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
385
+ background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
386
+ background-repeat: repeat-x;
387
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }
388
+
389
+ .select2-container--classic .select2-selection--multiple {
390
+ background-color: white;
391
+ border: 1px solid #aaa;
392
+ border-radius: 4px;
393
+ cursor: text;
394
+ outline: 0; }
395
+ .select2-container--classic .select2-selection--multiple:focus {
396
+ border: 1px solid #5897fb; }
397
+ .select2-container--classic .select2-selection--multiple .select2-selection__rendered {
398
+ list-style: none;
399
+ margin: 0;
400
+ padding: 0 5px; }
401
+ .select2-container--classic .select2-selection--multiple .select2-selection__clear {
402
+ display: none; }
403
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice {
404
+ background-color: #e4e4e4;
405
+ border: 1px solid #aaa;
406
+ border-radius: 4px;
407
+ cursor: default;
408
+ float: left;
409
+ margin-right: 5px;
410
+ margin-top: 5px;
411
+ padding: 0 5px; }
412
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
413
+ color: #888;
414
+ cursor: pointer;
415
+ display: inline-block;
416
+ font-weight: bold;
417
+ margin-right: 2px; }
418
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
419
+ color: #555; }
420
 
421
+ .select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
422
+ float: right; }
 
423
 
424
+ .select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
425
+ margin-left: 5px;
426
+ margin-right: auto; }
427
 
428
+ .select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
429
+ margin-left: 2px;
430
+ margin-right: auto; }
 
431
 
432
+ .select2-container--classic.select2-container--open .select2-selection--multiple {
433
+ border: 1px solid #5897fb; }
434
 
435
+ .select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
436
+ border-top: none;
437
+ border-top-left-radius: 0;
438
+ border-top-right-radius: 0; }
 
 
439
 
440
+ .select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
441
+ border-bottom: none;
442
+ border-bottom-left-radius: 0;
443
+ border-bottom-right-radius: 0; }
 
444
 
445
+ .select2-container--classic .select2-search--dropdown .select2-search__field {
446
+ border: 1px solid #aaa;
447
+ outline: 0; }
448
 
449
+ .select2-container--classic .select2-search--inline .select2-search__field {
450
+ outline: 0;
451
+ box-shadow: none; }
452
 
453
+ .select2-container--classic .select2-dropdown {
454
+ background-color: white;
455
+ border: 1px solid transparent; }
456
 
457
+ .select2-container--classic .select2-dropdown--above {
458
+ border-bottom: none; }
 
 
 
 
459
 
460
+ .select2-container--classic .select2-dropdown--below {
461
+ border-top: none; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
 
463
+ .select2-container--classic .select2-results > .select2-results__options {
464
+ max-height: 200px;
465
+ overflow-y: auto; }
466
 
467
+ .select2-container--classic .select2-results__option[role=group] {
468
+ padding: 0; }
469
 
470
+ .select2-container--classic .select2-results__option[aria-disabled=true] {
471
+ color: grey; }
472
 
473
+ .select2-container--classic .select2-results__option--highlighted[aria-selected] {
474
+ background-color: #3875d7;
475
+ color: white; }
 
 
476
 
477
+ .select2-container--classic .select2-results__group {
478
+ cursor: default;
479
+ display: block;
480
+ padding: 6px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
 
482
+ .select2-container--classic.select2-container--open .select2-dropdown {
483
+ border-color: #5897fb; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/select2/select2.png DELETED
Binary file
css/select2/select2x2.png DELETED
Binary file
css/taxonomy.css DELETED
@@ -1,14 +0,0 @@
1
- .rw-taxonomy-tree {
2
- margin-left: 15px;
3
- margin-top: 5px;
4
- }
5
- .rwmb-input > .rw-taxonomy-tree {
6
- margin-left: 0;
7
- margin-top: 0;
8
- }
9
- .rw-taxonomy-tree.active {
10
- display: inline-block;
11
- }
12
- .rw-taxonomy-tree.disabled {
13
- display: none;
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/common.php DELETED
@@ -1,55 +0,0 @@
1
- <?php
2
- /**
3
- * Handle common actions for the plugin: load text domain, add plugin links.
4
- *
5
- * @package Meta Box
6
- */
7
-
8
- // Prevent loading this file directly
9
- defined( 'ABSPATH' ) || exit;
10
-
11
- if ( ! class_exists( 'RWMB_Common' ) )
12
- {
13
- /**
14
- * Class that handle actions for the plugin.
15
- */
16
- class RWMB_Common
17
- {
18
- /**
19
- * Add actions when class is loaded.
20
- * @return void
21
- */
22
- public static function load()
23
- {
24
- add_action( 'plugins_loaded', array( __CLASS__, 'load_textdomain' ) );
25
-
26
- $plugin = 'meta-box/meta-box.php';
27
- add_filter( "plugin_action_links_$plugin", array( __CLASS__, 'plugin_links' ) );
28
- }
29
-
30
- /**
31
- * Load plugin translation.
32
- * @return void
33
- */
34
- public static function load_textdomain()
35
- {
36
- load_plugin_textdomain( 'meta-box', false, plugin_basename( RWMB_DIR ) . '/lang/' );
37
- }
38
-
39
- /**
40
- * Add links to Documentation and Extensions in plugin's list of action links.
41
- *
42
- * @since 4.3.11
43
- * @param array $links Array of action links
44
- * @return array
45
- */
46
- public static function plugin_links( $links )
47
- {
48
- $links[] = '<a href="http://metabox.io/docs/">' . __( 'Documentation', 'meta-box' ) . '</a>';
49
- $links[] = '<a href="http://metabox.io/plugins/">' . __( 'Extensions', 'meta-box' ) . '</a>';
50
- return $links;
51
- }
52
- }
53
-
54
- RWMB_Common::load();
55
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/core.php ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The plugin core class which initialize plugin's code.
4
+ * @package Meta Box
5
+ */
6
+
7
+ /**
8
+ * The Meta Box core class.
9
+ * @package Meta Box
10
+ */
11
+ class RWMB_Core
12
+ {
13
+ /**
14
+ * Register hooks.
15
+ */
16
+ public function __construct()
17
+ {
18
+ $plugin = 'meta-box/meta-box.php';
19
+ add_filter( "plugin_action_links_$plugin", array( $this, 'plugin_links' ) );
20
+ add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
21
+ add_action( 'admin_init', array( $this, 'register_meta_boxes' ) );
22
+ add_action( 'edit_page_form', array( $this, 'fix_page_template' ) );
23
+ }
24
+
25
+ /**
26
+ * Add links to Documentation and Extensions in plugin's list of action links.
27
+ *
28
+ * @since 4.3.11
29
+ * @param array $links Array of action links
30
+ * @return array
31
+ */
32
+ public function plugin_links( $links )
33
+ {
34
+ $links[] = '<a href="https://metabox.io/docs/">' . __( 'Documentation', 'meta-box' ) . '</a>';
35
+ $links[] = '<a href="https://metabox.io/plugins/">' . __( 'Extensions', 'meta-box' ) . '</a>';
36
+ return $links;
37
+ }
38
+
39
+ /**
40
+ * Load plugin translation.
41
+ */
42
+ public function load_textdomain()
43
+ {
44
+ load_plugin_textdomain( 'meta-box', false, plugin_basename( RWMB_DIR ) . '/lang/' );
45
+ }
46
+
47
+ /**
48
+ * Register meta boxes.
49
+ * Advantages:
50
+ * - prevents incorrect hook.
51
+ * - no need to check for class existences.
52
+ */
53
+ public function register_meta_boxes()
54
+ {
55
+ $meta_boxes = self::get_meta_boxes();
56
+ foreach ( $meta_boxes as $meta_box )
57
+ {
58
+ new RW_Meta_Box( $meta_box );
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Get registered meta boxes via a filter.
64
+ * Advantages:
65
+ * - prevents duplicated global variables.
66
+ * - allows users to remove/hide registered meta boxes.
67
+ */
68
+ static public function get_meta_boxes()
69
+ {
70
+ $meta_boxes = apply_filters( 'rwmb_meta_boxes', array() );
71
+ return empty( $meta_boxes ) || ! is_array( $meta_boxes ) ? array() : $meta_boxes;
72
+ }
73
+
74
+ /**
75
+ * WordPress will prevent post data saving if a page template has been selected that does not exist
76
+ * This is especially a problem when switching to our theme, and old page templates are in the post data
77
+ * Unset the page template if the page does not exist to allow the post to save
78
+ *
79
+ * @param WP_Post $post
80
+ * @since 4.3.10
81
+ */
82
+ public function fix_page_template( WP_Post $post )
83
+ {
84
+ $template = get_post_meta( $post->ID, '_wp_page_template', true );
85
+ $page_templates = wp_get_theme()->get_page_templates();
86
+
87
+ // If the template doesn't exists, remove the data to allow WordPress to save
88
+ if ( ! isset( $page_templates[$template] ) )
89
+ {
90
+ delete_post_meta( $post->ID, '_wp_page_template' );
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Apply various filters based on field type, id.
96
+ * Filters:
97
+ * - rwmb_{$name}
98
+ * - rwmb_{$field['type']}_{$name}
99
+ * - rwmb_{$field['id']}_{$name}
100
+ * @return mixed
101
+ */
102
+ public static function filter()
103
+ {
104
+ $args = func_get_args();
105
+
106
+ // 3 first params must be: filter name, value, field. Other params will be used for filters.
107
+ $name = array_shift( $args );
108
+ $value = array_shift( $args );
109
+ $field = array_shift( $args );
110
+
111
+ // List of filters
112
+ $filters = array(
113
+ 'rwmb_' . $name,
114
+ 'rwmb_' . $field['type'] . '_' . $name,
115
+ );
116
+ if ( isset( $field['id'] ) )
117
+ {
118
+ $filters[] = 'rwmb_' . $field['id'] . '_' . $name;
119
+ }
120
+
121
+ // Filter params: value, field, other params. Note: value is changed after each run.
122
+ array_unshift( $args, $field );
123
+ foreach ( $filters as $filter )
124
+ {
125
+ $filter_args = $args;
126
+ array_unshift( $filter_args, $value );
127
+ $value = apply_filters_ref_array( $filter, $filter_args );
128
+ }
129
+
130
+ return $value;
131
+ }
132
+ }
inc/field-multiple-values.php DELETED
@@ -1,78 +0,0 @@
1
- <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Field_Multiple_Values' ) )
6
- {
7
- /**
8
- * This class implements common methods used in fields which have multiple values
9
- * like checkbox list, autocomplete, etc.
10
- *
11
- * The difference when handling actions for these fields are the way they get/set
12
- * meta value. Briefly:
13
- * - If field is cloneable, value is saved as a single entry in the database
14
- * - Otherwise value is saved as multiple entries
15
- */
16
- class RWMB_Field_Multiple_Values extends RWMB_Field
17
- {
18
- /**
19
- * Normalize parameters for field
20
- *
21
- * @param array $field
22
- *
23
- * @return array
24
- */
25
- static function normalize_field( $field )
26
- {
27
- $field['multiple'] = true;
28
- $field['field_name'] = $field['id'];
29
- if ( ! $field['clone'] )
30
- $field['field_name'] .= '[]';
31
-
32
- return $field;
33
- }
34
-
35
- /**
36
- * Output the field value
37
- * Display option name instead of option value
38
- *
39
- * @param array $field Field parameters
40
- * @param array $args Additional arguments. Not used for these fields.
41
- * @param int|null $post_id Post ID. null for current post. Optional.
42
- *
43
- * @return mixed Field value
44
- */
45
- static function the_value( $field, $args = array(), $post_id = null )
46
- {
47
- $value = self::get_value( $field, $args, $post_id );
48
- if ( ! $value )
49
- return '';
50
-
51
- $output = '<ul>';
52
- if ( $field['clone'] )
53
- {
54
- foreach ( $value as $subvalue )
55
- {
56
- $output .= '<li>';
57
- $output .= '<ul>';
58
- foreach ( $subvalue as $option )
59
- {
60
- $output .= '<li>' . $field['options'][$option] . '</li>';
61
- }
62
- $output .= '</ul>';
63
- $output .= '</li>';
64
- }
65
- }
66
- else
67
- {
68
- foreach ( $value as $option )
69
- {
70
- $output .= '<li>' . $field['options'][$option] . '</li>';
71
- }
72
- }
73
- $output .= '</ul>';
74
-
75
- return $output;
76
- }
77
- }
78
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/field.php CHANGED
@@ -1,525 +1,498 @@
1
  <?php
2
- if ( ! class_exists( 'RWMB_Field ' ) )
 
 
 
 
3
  {
4
- class RWMB_Field
 
 
 
 
 
5
  {
6
- /**
7
- * Add actions
8
- *
9
- * @return void
10
- */
11
- static function add_actions()
12
- {
13
- }
14
-
15
- /**
16
- * Enqueue scripts and styles
17
- *
18
- * @return void
19
- */
20
- static function admin_enqueue_scripts()
21
- {
22
- }
23
-
24
- /**
25
- * Show field HTML
26
- * Filters are put inside this method, not inside methods such as "meta", "html", "begin_html", etc.
27
- * That ensures the returned value are always been applied filters
28
- * This method is not meant to be overwritten in specific fields
29
- *
30
- * @param array $field
31
- * @param bool $saved
32
- *
33
- * @return string
34
- */
35
- static function show( $field, $saved )
36
- {
37
- $post = get_post();
38
- $post_id = isset( $post->ID ) ? $post->ID : 0;
39
 
40
- $field_class = RW_Meta_Box::get_class_name( $field );
41
- $meta = call_user_func( array( $field_class, 'meta' ), $post_id, $saved, $field );
 
 
 
 
 
 
42
 
43
- // Apply filter to field meta value
44
- // 1st filter applies to all fields
45
- // 2nd filter applies to all fields with the same type
46
- // 3rd filter applies to current field only
47
- $meta = apply_filters( 'rwmb_field_meta', $meta, $field, $saved );
48
- $meta = apply_filters( "rwmb_{$field['type']}_meta", $meta, $field, $saved );
49
- $meta = apply_filters( "rwmb_{$field['id']}_meta", $meta, $field, $saved );
 
 
 
 
 
 
 
 
50
 
51
- $type = $field['type'];
52
- $id = $field['id'];
 
53
 
54
- $begin = call_user_func( array( $field_class, 'begin_html' ), $meta, $field );
 
55
 
56
- // Apply filter to field begin HTML
57
- // 1st filter applies to all fields
58
- // 2nd filter applies to all fields with the same type
59
- // 3rd filter applies to current field only
60
- $begin = apply_filters( 'rwmb_begin_html', $begin, $field, $meta );
61
- $begin = apply_filters( "rwmb_{$type}_begin_html", $begin, $field, $meta );
62
- $begin = apply_filters( "rwmb_{$id}_begin_html", $begin, $field, $meta );
63
 
64
- // Separate code for cloneable and non-cloneable fields to make easy to maintain
 
 
 
65
 
66
- // Cloneable fields
67
- if ( $field['clone'] )
 
 
 
68
  {
69
- $field_html = '';
 
 
 
 
 
 
 
 
 
70
 
71
- /**
72
- * Note: $meta must contain value so that the foreach loop runs!
73
- * @see meta()
74
- */
75
- foreach ( $meta as $index => $sub_meta )
76
  {
77
- $sub_field = $field;
78
- $sub_field['field_name'] = $field['field_name'] . "[{$index}]";
79
- if ( $index > 0 )
80
- {
81
- if ( isset( $sub_field['address_field'] ) )
82
- $sub_field['address_field'] = $field['address_field'] . "_{$index}";
83
- $sub_field['id'] = $field['id'] . "_{$index}";
84
- }
85
- if ( $field['multiple'] )
86
- $sub_field['field_name'] .= '[]';
87
-
88
- // Wrap field HTML in a div with class="rwmb-clone" if needed
89
- $class = "rwmb-clone rwmb-{$field['type']}-clone";
90
- if ( $field['sort_clone'] )
91
- {
92
- $class .= ' rwmb-sort-clone';
93
- }
94
- $input_html = "<div class='$class'>";
95
-
96
- // Drag clone icon
97
- if ( $field['sort_clone'] )
98
- $input_html .= "<a href='javascript:;' class='rwmb-clone-icon'></a>";
99
-
100
- // Call separated methods for displaying each type of field
101
- $input_html .= call_user_func( array( $field_class, 'html' ), $sub_meta, $sub_field );
102
-
103
- // Apply filter to field HTML
104
- // 1st filter applies to all fields with the same type
105
- // 2nd filter applies to current field only
106
- $input_html = apply_filters( "rwmb_{$type}_html", $input_html, $field, $sub_meta );
107
- $input_html = apply_filters( "rwmb_{$id}_html", $input_html, $field, $sub_meta );
108
-
109
- // Remove clone button
110
- $input_html .= call_user_func( array( $field_class, 'remove_clone_button' ), $sub_field );
111
-
112
- $input_html .= '</div>';
113
-
114
- $field_html .= $input_html;
115
  }
116
- }
117
- // Non-cloneable fields
118
- else
119
- {
120
- // Call separated methods for displaying each type of field
121
- $field_html = call_user_func( array( $field_class, 'html' ), $meta, $field );
122
 
123
- // Apply filter to field HTML
124
- // 1st filter applies to all fields with the same type
125
- // 2nd filter applies to current field only
126
- $field_html = apply_filters( "rwmb_{$type}_html", $field_html, $field, $meta );
127
- $field_html = apply_filters( "rwmb_{$id}_html", $field_html, $field, $meta );
128
- }
129
 
130
- $end = call_user_func( array( $field_class, 'end_html' ), $meta, $field );
131
-
132
- // Apply filter to field end HTML
133
- // 1st filter applies to all fields
134
- // 2nd filter applies to all fields with the same type
135
- // 3rd filter applies to current field only
136
- $end = apply_filters( 'rwmb_end_html', $end, $field, $meta );
137
- $end = apply_filters( "rwmb_{$type}_end_html", $end, $field, $meta );
138
- $end = apply_filters( "rwmb_{$id}_end_html", $end, $field, $meta );
139
-
140
- // Apply filter to field wrapper
141
- // This allow users to change whole HTML markup of the field wrapper (i.e. table row)
142
- // 1st filter applies to all fields
143
- // 1st filter applies to all fields with the same type
144
- // 2nd filter applies to current field only
145
- $html = apply_filters( 'rwmb_wrapper_html', "{$begin}{$field_html}{$end}", $field, $meta );
146
- $html = apply_filters( "rwmb_{$type}_wrapper_html", $html, $field, $meta );
147
- $html = apply_filters( "rwmb_{$id}_wrapper_html", $html, $field, $meta );
148
-
149
- // Display label and input in DIV and allow user-defined classes to be appended
150
- $classes = array( 'rwmb-field', "rwmb-{$type}-wrapper" );
151
- if ( 'hidden' === $field['type'] )
152
- $classes[] = 'hidden';
153
- if ( ! empty( $field['required'] ) )
154
- $classes[] = 'required';
155
- if ( ! empty( $field['class'] ) )
156
- $classes[] = $field['class'];
157
-
158
- $outer_html = sprintf(
159
- $field['before'] . '<div class="%s">%s</div>' . $field['after'],
160
- implode( ' ', $classes ),
161
- $html
162
- );
163
 
164
- // Allow to change output of outer div
165
- // 1st filter applies to all fields
166
- // 1st filter applies to all fields with the same type
167
- // 2nd filter applies to current field only
168
- $outer_html = apply_filters( 'rwmb_outer_html', $outer_html, $field, $meta );
169
- $outer_html = apply_filters( "rwmb_{$type}_outer_html", $outer_html, $field, $meta );
170
- $outer_html = apply_filters( "rwmb_{$id}_outer_html", $outer_html, $field, $meta );
171
 
172
- echo $outer_html;
 
173
  }
174
-
175
- /**
176
- * Get field HTML
177
- *
178
- * @param mixed $meta
179
- * @param array $field
180
- *
181
- * @return string
182
- */
183
- static function html( $meta, $field )
184
  {
185
- return '';
 
 
186
  }
187
 
188
- /**
189
- * Show begin HTML markup for fields
190
- *
191
- * @param mixed $meta
192
- * @param array $field
193
- *
194
- * @return string
195
- */
196
- static function begin_html( $meta, $field )
197
- {
198
- $field_label = '';
199
- if ( $field['name'] )
200
- {
201
- $field_label = sprintf(
202
- '<div class="rwmb-label"><label for="%s">%s</label></div>',
203
- $field['id'],
204
- $field['name']
205
- );
206
- }
207
-
208
- $data_max_clone = '';
209
- if ( is_numeric( $field['max_clone'] ) && $field['max_clone'] > 1 )
210
- {
211
- $data_max_clone .= ' data-max-clone=' . $field['max_clone'];
212
- }
213
 
214
- $input_open = sprintf(
215
- '<div class="rwmb-input"%s>',
216
- $data_max_clone
217
- );
218
 
219
- return $field_label . $input_open;
220
- }
 
 
 
 
221
 
222
- /**
223
- * Show end HTML markup for fields
224
- *
225
- * @param mixed $meta
226
- * @param array $field
227
- *
228
- * @return string
229
- */
230
- static function end_html( $meta, $field )
231
- {
232
- $button = $field['clone'] ? call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'add_clone_button' ), $field ) : '';
233
- $desc = $field['desc'] ? "<p id='{$field['id']}_description' class='description'>{$field['desc']}</p>" : '';
234
 
235
- // Closes the container
236
- $html = "{$button}{$desc}</div>";
237
 
238
- return $html;
239
- }
 
 
 
 
 
 
 
 
 
 
240
 
241
- /**
242
- * Add clone button
243
- *
244
- * @param array $field Field parameter
245
- *
246
- * @return string $html
247
- */
248
- static function add_clone_button( $field )
 
 
 
 
249
  {
250
- $text = apply_filters( 'rwmb_add_clone_button_text', __( '+ Add more', 'meta-box' ), $field );
251
- return "<a href='#' class='rwmb-button button-primary add-clone'>$text</a>";
 
 
 
252
  }
253
 
254
- /**
255
- * Remove clone button
256
- *
257
- * @param array $field Field parameter
258
- *
259
- * @return string $html
260
- */
261
- static function remove_clone_button( $field )
262
- {
263
- $icon = '<i class="dashicons dashicons-minus"></i>';
264
- $text = apply_filters( 'rwmb_remove_clone_button_text', $icon, $field );
265
- return "<a href='#' class='rwmb-button remove-clone'>$text</a>";
266
- }
267
 
268
- /**
269
- * Get meta value
270
- *
271
- * @param int $post_id
272
- * @param bool $saved
273
- * @param array $field
274
- *
275
- * @return mixed
276
- */
277
- static function meta( $post_id, $saved, $field )
278
- {
279
- /**
280
- * For special fields like 'divider', 'heading' which don't have ID, just return empty string
281
- * to prevent notice error when displaying fields
282
- */
283
- if ( empty( $field['id'] ) )
284
- return '';
285
 
286
- $single = $field['clone'] || ! $field['multiple'];
287
- $meta = get_post_meta( $post_id, $field['id'], $single );
288
 
289
- // Use $field['std'] only when the meta box hasn't been saved (i.e. the first time we run)
290
- $meta = ( ! $saved && '' === $meta || array() === $meta ) ? $field['std'] : $meta;
 
 
 
 
 
 
 
 
 
 
291
 
292
- // Escape attributes
293
- $meta = call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'esc_meta' ), $meta );
294
 
295
- // Make sure meta value is an array for clonable and multiple fields
296
- if ( $field['clone'] || $field['multiple'] )
297
- {
298
- if ( empty( $meta ) || ! is_array( $meta ) )
299
- {
300
- /**
301
- * Note: if field is clonable, $meta must be an array with values
302
- * so that the foreach loop in self::show() runs properly
303
- * @see self::show()
304
- */
305
- $meta = $field['clone'] ? array( '' ) : array();
306
- }
307
- }
308
 
309
- return $meta;
310
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
 
 
 
 
 
 
 
 
 
 
 
 
312
  /**
313
- * Escape meta for field output
314
- *
315
- * @param mixed $meta
316
- *
317
- * @return mixed
318
  */
319
- static function esc_meta( $meta )
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  {
321
- return is_array( $meta ) ? array_map( __METHOD__, $meta ) : esc_attr( $meta );
 
 
 
 
 
 
 
 
322
  }
323
 
324
- /**
325
- * Set value of meta before saving into database
326
- *
327
- * @param mixed $new
328
- * @param mixed $old
329
- * @param int $post_id
330
- * @param array $field
331
- *
332
- * @return int
333
- */
334
- static function value( $new, $old, $post_id, $field )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
  {
336
- return $new;
 
337
  }
338
 
339
- /**
340
- * Save meta value
341
- *
342
- * @param $new
343
- * @param $old
344
- * @param $post_id
345
- * @param $field
346
- */
347
- static function save( $new, $old, $post_id, $field )
348
  {
349
- $name = $field['id'];
350
-
351
- // Remove post meta if it's empty
352
- if ( '' === $new || array() === $new )
353
  {
354
- delete_post_meta( $post_id, $name );
355
-
356
- return;
357
  }
 
 
 
358
 
359
- // If field is cloneable, value is saved as a single entry in the database
360
- if ( $field['clone'] )
 
 
 
361
  {
362
- $new = (array) $new;
363
- foreach ( $new as $k => $v )
364
- {
365
- if ( '' === $v )
366
- unset( $new[$k] );
367
- }
368
- update_post_meta( $post_id, $name, $new );
369
- return;
370
  }
371
-
372
- // If field is multiple, value is saved as multiple entries in the database (WordPress behaviour)
373
- if ( $field['multiple'] )
374
  {
375
- foreach ( $new as $new_value )
376
- {
377
- if ( ! in_array( $new_value, $old ) )
378
- add_post_meta( $post_id, $name, $new_value, false );
379
- }
380
- foreach ( $old as $old_value )
381
- {
382
- if ( ! in_array( $old_value, $new ) )
383
- delete_post_meta( $post_id, $name, $old_value );
384
- }
385
- return;
386
  }
387
-
388
- // Default: just update post meta
389
- update_post_meta( $post_id, $name, $new );
390
  }
391
 
392
- /**
393
- * Normalize parameters for field
394
- *
395
- * @param array $field
396
- *
397
- * @return array
398
- */
399
- static function normalize_field( $field )
400
- {
401
- $field = wp_parse_args( $field, array(
402
- 'disabled' => false,
403
- 'required' => false,
404
- 'attributes' => array()
405
- ) );
406
-
407
- $field['attributes'] = wp_parse_args( $field['attributes'], array(
408
- 'disabled' => $field['disabled'],
409
- 'required' => $field['required'],
410
- 'class' => "rwmb-{$field['type']}",
411
- 'id' => $field['clone'] ? false : $field['id'],
412
- 'name' => $field['field_name'],
413
- ) );
414
-
415
- return $field;
416
- }
417
 
418
- /**
419
- * Renders an attribute array into an html attributes string
420
- *
421
- * @param array $attributes
422
- *
423
- * @return string
424
- */
425
- static function render_attributes( $attributes )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
426
  {
427
- $attr_string = '';
428
- foreach ( $attributes as $key => $value )
429
  {
430
- if ( $value )
431
- {
432
- $value = ( true === $value ) ? $key : $value;
433
- $attr_string .= sprintf(
434
- ' %s="%s"',
435
- $key,
436
- esc_attr( $value )
437
- );
438
- }
439
  }
440
- return $attr_string;
441
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442
 
443
  /**
444
- * Get the field value
445
- * The difference between this function and 'meta' function is 'meta' function always returns the escaped value
446
- * of the field saved in the database, while this function returns more meaningful value of the field, for ex.:
447
- * for file/image: return array of file/image information instead of file/image IDs
448
- *
449
- * Each field can extend this function and add more data to the returned value.
450
- * See specific field classes for details.
451
- *
452
- * @param array $field Field parameters
453
- * @param array $args Additional arguments. Rarely used. See specific fields for details
454
- * @param int|null $post_id Post ID. null for current post. Optional.
455
- *
456
- * @return mixed Field value
457
  */
458
- static function get_value( $field, $args = array(), $post_id = null )
459
- {
460
- if ( ! $post_id )
461
- $post_id = get_the_ID();
462
 
463
- /**
464
- * Get raw meta value in the database, no escape
465
- * Very similar to self::meta() function
466
- */
 
 
 
 
 
467
 
468
- /**
469
- * For special fields like 'divider', 'heading' which don't have ID, just return empty string
470
- * to prevent notice error when display in fields
471
- */
472
- $value = '';
473
- if ( ! empty( $field['id'] ) )
474
  {
475
- $single = $field['clone'] || ! $field['multiple'];
476
- $value = get_post_meta( $post_id, $field['id'], $single );
477
-
478
- // Make sure meta value is an array for clonable and multiple fields
479
- if ( $field['clone'] || $field['multiple'] )
480
- {
481
- $value = is_array( $value ) && $value ? $value : array();
482
- }
483
  }
484
-
485
- /**
486
- * Return the meta value by default.
487
- * For specific fields, the returned value might be different. See each field class for details
488
- */
489
- return $value;
490
  }
491
 
492
  /**
493
- * Output the field value
494
- * Depends on field value and field types, each field can extend this method to output its value in its own way
495
- * See specific field classes for details.
496
- *
497
- * Note: we don't echo the field value directly. We return the output HTML of field, which will be used in
498
- * rwmb_the_field function later.
499
- *
500
- * @use self::get_value()
501
- * @see rwmb_the_field()
502
- *
503
- * @param array $field Field parameters
504
- * @param array $args Additional arguments. Rarely used. See specific fields for details
505
- * @param int|null $post_id Post ID. null for current post. Optional.
506
- *
507
- * @return string HTML output of the field
508
  */
509
- static function the_value( $field, $args = array(), $post_id = null )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
510
  {
511
- $value = call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'get_value' ), $field, $args, $post_id );
512
- $output = $value;
513
- if ( is_array( $value ) )
514
  {
515
- $output = '<ul>';
516
- foreach ( $value as $subvalue )
517
- {
518
- $output .= '<li>' . $subvalue . '</li>';
519
- }
520
- $output .= '</ul>';
521
  }
522
- return $output;
523
  }
 
524
  }
525
  }
1
  <?php
2
+ /**
3
+ * Base field class which defines all necessary methods.
4
+ * Fields must inherit this class and overwrite methods with its own.
5
+ */
6
+ abstract class RWMB_Field
7
  {
8
+ /**
9
+ * Add actions
10
+ *
11
+ * @return void
12
+ */
13
+ static function add_actions()
14
  {
15
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
+ /**
18
+ * Enqueue scripts and styles
19
+ *
20
+ * @return void
21
+ */
22
+ static function admin_enqueue_scripts()
23
+ {
24
+ }
25
 
26
+ /**
27
+ * Show field HTML
28
+ * Filters are put inside this method, not inside methods such as "meta", "html", "begin_html", etc.
29
+ * That ensures the returned value are always been applied filters
30
+ * This method is not meant to be overwritten in specific fields
31
+ *
32
+ * @param array $field
33
+ * @param bool $saved
34
+ *
35
+ * @return string
36
+ */
37
+ static function show( $field, $saved )
38
+ {
39
+ $post = get_post();
40
+ $post_id = isset( $post->ID ) ? $post->ID : 0;
41
 
42
+ $field_class = RW_Meta_Box::get_class_name( $field );
43
+ $meta = call_user_func( array( $field_class, 'meta' ), $post_id, $saved, $field );
44
+ $meta = RWMB_Core::filter( 'field_meta', $meta, $field, $saved );
45
 
46
+ $begin = call_user_func( array( $field_class, 'begin_html' ), $meta, $field );
47
+ $begin = RWMB_Core::filter( 'begin_html', $begin, $field, $meta );
48
 
49
+ // Separate code for cloneable and non-cloneable fields to make easy to maintain
 
 
 
 
 
 
50
 
51
+ // Cloneable fields
52
+ if ( $field['clone'] )
53
+ {
54
+ $field_html = '';
55
 
56
+ /**
57
+ * Note: $meta must contain value so that the foreach loop runs!
58
+ * @see meta()
59
+ */
60
+ foreach ( $meta as $index => $sub_meta )
61
  {
62
+ $sub_field = $field;
63
+ $sub_field['field_name'] = $field['field_name'] . "[{$index}]";
64
+ if ( $index > 0 )
65
+ {
66
+ if ( isset( $sub_field['address_field'] ) )
67
+ $sub_field['address_field'] = $field['address_field'] . "_{$index}";
68
+ $sub_field['id'] = $field['id'] . "_{$index}";
69
+ }
70
+ if ( $field['multiple'] )
71
+ $sub_field['field_name'] .= '[]';
72
 
73
+ // Wrap field HTML in a div with class="rwmb-clone" if needed
74
+ $class = "rwmb-clone rwmb-{$field['type']}-clone";
75
+ $sort_icon = '';
76
+ if ( $field['sort_clone'] )
 
77
  {
78
+ $class .= ' rwmb-sort-clone';
79
+ $sort_icon = "<a href='javascript:;' class='rwmb-clone-icon'></a>";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  }
81
+ $input_html = "<div class='$class'>" . $sort_icon;
 
 
 
 
 
82
 
83
+ // Call separated methods for displaying each type of field
84
+ $input_html .= call_user_func( array( $field_class, 'html' ), $sub_meta, $sub_field );
85
+ $input_html = RWMB_Core::filter( 'html', $input_html, $sub_field, $sub_meta );
 
 
 
86
 
87
+ // Remove clone button
88
+ $input_html .= call_user_func( array( $field_class, 'remove_clone_button' ), $sub_field );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
+ $input_html .= '</div>';
 
 
 
 
 
 
91
 
92
+ $field_html .= $input_html;
93
+ }
94
  }
95
+ // Non-cloneable fields
96
+ else
 
 
 
 
 
 
 
 
97
  {
98
+ // Call separated methods for displaying each type of field
99
+ $field_html = call_user_func( array( $field_class, 'html' ), $meta, $field );
100
+ $field_html = RWMB_Core::filter( 'html', $field_html, $field, $meta );
101
  }
102
 
103
+ $end = call_user_func( array( $field_class, 'end_html' ), $meta, $field );
104
+ $end = RWMB_Core::filter( 'end_html', $end, $field, $meta );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
+ $html = RWMB_Core::filter( 'wrapper_html', "$begin$field_html$end", $field, $meta );
 
 
 
107
 
108
+ // Display label and input in DIV and allow user-defined classes to be appended
109
+ $classes = "rwmb-field rwmb-{$field['type']}-wrapper " . $field['class'] ;
110
+ if ( 'hidden' === $field['type'] )
111
+ $classes .= ' hidden';
112
+ if ( ! empty( $field['required'] ) )
113
+ $classes .= ' required';
114
 
115
+ $outer_html = sprintf(
116
+ $field['before'] . '<div class="%s">%s</div>' . $field['after'],
117
+ trim( $classes ),
118
+ $html
119
+ );
120
+ $outer_html = RWMB_Core::filter( 'outer_html', $outer_html, $field, $meta );
 
 
 
 
 
 
121
 
122
+ echo $outer_html;
123
+ }
124
 
125
+ /**
126
+ * Get field HTML
127
+ *
128
+ * @param mixed $meta
129
+ * @param array $field
130
+ *
131
+ * @return string
132
+ */
133
+ static function html( $meta, $field )
134
+ {
135
+ return '';
136
+ }
137
 
138
+ /**
139
+ * Show begin HTML markup for fields
140
+ *
141
+ * @param mixed $meta
142
+ * @param array $field
143
+ *
144
+ * @return string
145
+ */
146
+ static function begin_html( $meta, $field )
147
+ {
148
+ $field_label = '';
149
+ if ( $field['name'] )
150
  {
151
+ $field_label = sprintf(
152
+ '<div class="rwmb-label"><label for="%s">%s</label></div>',
153
+ $field['id'],
154
+ $field['name']
155
+ );
156
  }
157
 
158
+ $data_max_clone = is_numeric( $field['max_clone'] ) && $field['max_clone'] > 1 ? ' data-max-clone=' . $field['max_clone'] : '';
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
+ $input_open = sprintf(
161
+ '<div class="rwmb-input"%s>',
162
+ $data_max_clone
163
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
+ return $field_label . $input_open;
166
+ }
167
 
168
+ /**
169
+ * Show end HTML markup for fields
170
+ *
171
+ * @param mixed $meta
172
+ * @param array $field
173
+ *
174
+ * @return string
175
+ */
176
+ static function end_html( $meta, $field )
177
+ {
178
+ $button = $field['clone'] ? call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'add_clone_button' ), $field ) : '';
179
+ $desc = $field['desc'] ? "<p id='{$field['id']}_description' class='description'>{$field['desc']}</p>" : '';
180
 
181
+ // Closes the container
182
+ $html = "{$button}{$desc}</div>";
183
 
184
+ return $html;
185
+ }
 
 
 
 
 
 
 
 
 
 
 
186
 
187
+ /**
188
+ * Add clone button
189
+ *
190
+ * @param array $field Field parameter
191
+ *
192
+ * @return string $html
193
+ */
194
+ static function add_clone_button( $field )
195
+ {
196
+ $text = apply_filters( 'rwmb_add_clone_button_text', __( '+ Add more', 'meta-box' ), $field );
197
+ return "<a href='#' class='rwmb-button button-primary add-clone'>$text</a>";
198
+ }
199
+
200
+ /**
201
+ * Remove clone button
202
+ *
203
+ * @param array $field Field parameter
204
+ *
205
+ * @return string $html
206
+ */
207
+ static function remove_clone_button( $field )
208
+ {
209
+ $icon = '<i class="dashicons dashicons-minus"></i>';
210
+ $text = apply_filters( 'rwmb_remove_clone_button_text', $icon, $field );
211
+ return "<a href='#' class='rwmb-button remove-clone'>$text</a>";
212
+ }
213
 
214
+ /**
215
+ * Get meta value
216
+ *
217
+ * @param int $post_id
218
+ * @param bool $saved
219
+ * @param array $field
220
+ *
221
+ * @return mixed
222
+ */
223
+ static function meta( $post_id, $saved, $field )
224
+ {
225
  /**
226
+ * For special fields like 'divider', 'heading' which don't have ID, just return empty string
227
+ * to prevent notice error when displaying fields
 
 
 
228
  */
229
+ if ( empty( $field['id'] ) )
230
+ return '';
231
+
232
+ $single = $field['clone'] || ! $field['multiple'];
233
+ $meta = get_post_meta( $post_id, $field['id'], $single );
234
+
235
+ // Use $field['std'] only when the meta box hasn't been saved (i.e. the first time we run)
236
+ $meta = ( ! $saved && '' === $meta || array() === $meta ) ? $field['std'] : $meta;
237
+
238
+ // Escape attributes
239
+ $meta = call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'esc_meta' ), $meta );
240
+
241
+ // Make sure meta value is an array for clonable and multiple fields
242
+ if ( $field['clone'] || $field['multiple'] )
243
  {
244
+ if ( empty( $meta ) || ! is_array( $meta ) )
245
+ {
246
+ /**
247
+ * Note: if field is clonable, $meta must be an array with values
248
+ * so that the foreach loop in self::show() runs properly
249
+ * @see self::show()
250
+ */
251
+ $meta = $field['clone'] ? array( '' ) : array();
252
+ }
253
  }
254
 
255
+ return $meta;
256
+ }
257
+
258
+ /**
259
+ * Escape meta for field output
260
+ *
261
+ * @param mixed $meta
262
+ *
263
+ * @return mixed
264
+ */
265
+ static function esc_meta( $meta )
266
+ {
267
+ return is_array( $meta ) ? array_map( __METHOD__, $meta ) : esc_attr( $meta );
268
+ }
269
+
270
+ /**
271
+ * Set value of meta before saving into database
272
+ *
273
+ * @param mixed $new
274
+ * @param mixed $old
275
+ * @param int $post_id
276
+ * @param array $field
277
+ *
278
+ * @return int
279
+ */
280
+ static function value( $new, $old, $post_id, $field )
281
+ {
282
+ return $new;
283
+ }
284
+
285
+ /**
286
+ * Save meta value
287
+ *
288
+ * @param $new
289
+ * @param $old
290
+ * @param $post_id
291
+ * @param $field
292
+ */
293
+ static function save( $new, $old, $post_id, $field )
294
+ {
295
+ $name = $field['id'];
296
+
297
+ // Remove post meta if it's empty
298
+ if ( '' === $new || array() === $new )
299
  {
300
+ delete_post_meta( $post_id, $name );
301
+ return;
302
  }
303
 
304
+ // If field is cloneable, value is saved as a single entry in the database
305
+ if ( $field['clone'] )
 
 
 
 
 
 
 
306
  {
307
+ // Reset indexes
308
+ $new = array_values( (array) $new );
309
+ foreach ( $new as $k => $v )
 
310
  {
311
+ if ( '' === $v )
312
+ unset( $new[$k] );
 
313
  }
314
+ update_post_meta( $post_id, $name, $new );
315
+ return;
316
+ }
317
 
318
+ // If field is multiple, value is saved as multiple entries in the database (WordPress behaviour)
319
+ if ( $field['multiple'] )
320
+ {
321
+ $new_values = array_diff( $new, $old );
322
+ foreach ( $new_values as $new_value )
323
  {
324
+ add_post_meta( $post_id, $name, $new_value, false );
 
 
 
 
 
 
 
325
  }
326
+ $old_values = array_diff( $old, $new );
327
+ foreach ( $old_values as $old_value )
 
328
  {
329
+ delete_post_meta( $post_id, $name, $old_value );
 
 
 
 
 
 
 
 
 
 
330
  }
331
+ return;
 
 
332
  }
333
 
334
+ // Default: just update post meta
335
+ update_post_meta( $post_id, $name, $new );
336
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
 
338
+ /**
339
+ * Normalize parameters for field
340
+ *
341
+ * @param array $field
342
+ *
343
+ * @return array
344
+ */
345
+ static function normalize( $field )
346
+ {
347
+ $field = wp_parse_args( $field, array(
348
+ 'id' => '',
349
+ 'name' => '',
350
+ 'multiple' => false,
351
+ 'std' => '',
352
+ 'desc' => '',
353
+ 'format' => '',
354
+ 'before' => '',
355
+ 'after' => '',
356
+ 'field_name' => isset( $field['id'] ) ? $field['id'] : '',
357
+ 'placeholder' => '',
358
+
359
+ 'clone' => false,
360
+ 'max_clone' => 0,
361
+ 'sort_clone' => false,
362
+
363
+ 'class' => '',
364
+ 'disabled' => false,
365
+ 'required' => false,
366
+ 'attributes' => array(),
367
+ ) );
368
+
369
+ //Make sure all letters are lower case for id
370
+ $field['id'] = strtolower( $field['id'] );
371
+
372
+ return $field;
373
+ }
374
+
375
+ /**
376
+ * Get the attributes for a field
377
+ *
378
+ * @param array $field
379
+ * @param mixed $value
380
+ *
381
+ * @return array
382
+ */
383
+ static function get_attributes( $field, $value = null )
384
+ {
385
+ $attributes = wp_parse_args( $field['attributes'], array(
386
+ 'disabled' => $field['disabled'],
387
+ 'required' => $field['required'],
388
+ 'class' => "rwmb-{$field['type']}",
389
+ 'id' => $field['id'],
390
+ 'name' => $field['field_name'],
391
+ ) );
392
+
393
+ return $attributes;
394
+ }
395
+
396
+ /**
397
+ * Renders an attribute array into an html attributes string
398
+ *
399
+ * @param array $attributes
400
+ *
401
+ * @return string
402
+ */
403
+ static function render_attributes( $attributes )
404
+ {
405
+ $output = '';
406
+ foreach ( $attributes as $key => $value )
407
  {
408
+ if ( false === $value || '' === $value )
 
409
  {
410
+ continue;
 
 
 
 
 
 
 
 
411
  }
412
+ $output .= sprintf( true === $value ? ' %s' : ' %s="%s"', $key, esc_attr( $value ) );
413
  }
414
+ return $output;
415
+ }
416
+
417
+ /**
418
+ * Get the field value
419
+ * The difference between this function and 'meta' function is 'meta' function always returns the escaped value
420
+ * of the field saved in the database, while this function returns more meaningful value of the field, for ex.:
421
+ * for file/image: return array of file/image information instead of file/image IDs
422
+ *
423
+ * Each field can extend this function and add more data to the returned value.
424
+ * See specific field classes for details.
425
+ *
426
+ * @param array $field Field parameters
427
+ * @param array $args Additional arguments. Rarely used. See specific fields for details
428
+ * @param int|null $post_id Post ID. null for current post. Optional.
429
+ *
430
+ * @return mixed Field value
431
+ */
432
+ static function get_value( $field, $args = array(), $post_id = null )
433
+ {
434
+ if ( ! $post_id )
435
+ $post_id = get_the_ID();
436
 
437
  /**
438
+ * Get raw meta value in the database, no escape
439
+ * Very similar to self::meta() function
 
 
 
 
 
 
 
 
 
 
 
440
  */
 
 
 
 
441
 
442
+ /**
443
+ * For special fields like 'divider', 'heading' which don't have ID, just return empty string
444
+ * to prevent notice error when display in fields
445
+ */
446
+ $value = '';
447
+ if ( ! empty( $field['id'] ) )
448
+ {
449
+ $single = $field['clone'] || ! $field['multiple'];
450
+ $value = get_post_meta( $post_id, $field['id'], $single );
451
 
452
+ // Make sure meta value is an array for clonable and multiple fields
453
+ if ( $field['clone'] || $field['multiple'] )
 
 
 
 
454
  {
455
+ $value = is_array( $value ) && $value ? $value : array();
 
 
 
 
 
 
 
456
  }
 
 
 
 
 
 
457
  }
458
 
459
  /**
460
+ * Return the meta value by default.
461
+ * For specific fields, the returned value might be different. See each field class for details
 
 
 
 
 
 
 
 
 
 
 
 
 
462
  */
463
+ return $value;
464
+ }
465
+
466
+ /**
467
+ * Output the field value
468
+ * Depends on field value and field types, each field can extend this method to output its value in its own way
469
+ * See specific field classes for details.
470
+ *
471
+ * Note: we don't echo the field value directly. We return the output HTML of field, which will be used in
472
+ * rwmb_the_field function later.
473
+ *
474
+ * @use self::get_value()
475
+ * @see rwmb_the_field()
476
+ *
477
+ * @param array $field Field parameters
478
+ * @param array $args Additional arguments. Rarely used. See specific fields for details
479
+ * @param int|null $post_id Post ID. null for current post. Optional.
480
+ *
481
+ * @return string HTML output of the field
482
+ */
483
+ static function the_value( $field, $args = array(), $post_id = null )
484
+ {
485
+ $value = call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'get_value' ), $field, $args, $post_id );
486
+ $output = $value;
487
+ if ( is_array( $value ) )
488
  {
489
+ $output = '<ul>';
490
+ foreach ( $value as $subvalue )
 
491
  {
492
+ $output .= '<li>' . $subvalue . '</li>';
 
 
 
 
 
493
  }
494
+ $output .= '</ul>';
495
  }
496
+ return $output;
497
  }
498
  }
inc/fields/autocomplete.php CHANGED
@@ -1,99 +1,74 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Autocomplete_Field' ) )
6
  {
7
- class RWMB_Autocomplete_Field extends RWMB_Field_Multiple_Values
 
 
 
8
  {
9
- /**
10
- * Enqueue scripts and styles
11
- *
12
- * @return void
13
- */
14
- static function admin_enqueue_scripts()
15
- {
16
- wp_enqueue_style( 'rwmb-autocomplete', RWMB_CSS_URL . 'autocomplete.css', array( 'wp-admin' ), RWMB_VER );
17
- wp_enqueue_script( 'rwmb-autocomplete', RWMB_JS_URL . 'autocomplete.js', array( 'jquery-ui-autocomplete' ), RWMB_VER, true );
18
- wp_localize_script( 'rwmb-autocomplete', 'RWMB_Autocomplete', array( 'delete' => __( 'Delete', 'meta-box' ) ) );
19
- }
20
 
21
- /**
22
- * Get field HTML
23
- *
24
- * @param mixed $meta
25
- * @param array $field
26
- *
27
- * @return string
28
- */
29
- static function html( $meta, $field )
30
- {
31
- if ( ! is_array( $meta ) )
32
- $meta = array( $meta );
33
 
34
- if ( is_string( $field['options'] ) )
35
- {
36
- $options = $field['options'];
37
- }
38
- else
39
  {
40
- $options = array();
41
- foreach ( $field['options'] as $value => $label )
42
- {
43
- $options[] = array(
44
- 'value' => $value,
45
- 'label' => $label,
46
- );
47
- }
48
- $options = wp_json_encode( $options );
49
  }
 
 
50
 
51
- // Input field that triggers autocomplete.
52
- // This field doesn't store field values, so it doesn't have "name" attribute.
53
- // The value(s) of the field is store in hidden input(s). See below.
54
- $html = sprintf(
55
- '<input type="text" class="rwmb-autocomplete" id="%s" data-name="%s" data-options="%s" size="%s">',
56
- $field['id'],
57
- $field['field_name'],
58
- esc_attr( $options ),
59
- $field['size']
60
- );
61
 
62
- $html .= '<div class="rwmb-autocomplete-results">';
63
 
64
- // Each value is displayed with label and 'Delete' option
65
- // The hidden input has to have ".rwmb-*" class to make clone work
66
- $tpl = '
67
- <div class="rwmb-autocomplete-result">
68
- <div class="label">%s</div>
69
- <div class="actions">%s</div>
70
- <input type="hidden" class="rwmb-autocomplete-value" name="%s" value="%s">
71
- </div>
72
- ';
73
 
74
- if ( is_array( $field['options'] ) )
75
- {
76
- foreach ( $field['options'] as $value => $label )
77
- {
78
- if ( in_array( $value, $meta ) )
79
- {
80
- $html .= sprintf(
81
- $tpl,
82
- $label,
83
- __( 'Delete', 'meta-box' ),
84
- $field['field_name'],
85
- $value
86
- );
87
- }
88
- }
89
- }
90
- else
91
  {
92
- foreach ( $meta as $value )
93
  {
94
- if ( empty( $value ) )
95
- continue;
96
- $label = apply_filters( 'rwmb_autocomplete_result_label', $value, $field );
97
  $html .= sprintf(
98
  $tpl,
99
  $label,
@@ -103,26 +78,41 @@ if ( ! class_exists( 'RWMB_Autocomplete_Field' ) )
103
  );
104
  }
105
  }
106
-
107
- $html .= '</div>'; // .rwmb-autocomplete-results
108
-
109
- return $html;
110
  }
111
-
112
- /**
113
- * Normalize parameters for field
114
- *
115
- * @param array $field
116
- *
117
- * @return array
118
- */
119
- static function normalize_field( $field )
120
  {
121
- $field = parent::normalize_field( $field );
122
- $field = wp_parse_args( $field, array(
123
- 'size' => 30,
124
- ) );
125
- return $field;
 
 
 
 
 
 
 
 
126
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  }
128
  }
1
  <?php
2
+ /**
3
+ * Autocomplete field class.
4
+ */
5
+ class RWMB_Autocomplete_Field extends RWMB_Multiple_Values_Field
6
  {
7
+ /**
8
+ * Enqueue scripts and styles.
9
+ */
10
+ static function admin_enqueue_scripts()
11
  {
12
+ wp_enqueue_style( 'rwmb-autocomplete', RWMB_CSS_URL . 'autocomplete.css', array( 'wp-admin' ), RWMB_VER );
13
+ wp_enqueue_script( 'rwmb-autocomplete', RWMB_JS_URL . 'autocomplete.js', array( 'jquery-ui-autocomplete' ), RWMB_VER, true );
14
+ wp_localize_script( 'rwmb-autocomplete', 'RWMB_Autocomplete', array( 'delete' => __( 'Delete', 'meta-box' ) ) );
15
+ }
 
 
 
 
 
 
 
16
 
17
+ /**
18
+ * Get field HTML
19
+ *
20
+ * @param mixed $meta
21
+ * @param array $field
22
+ * @return string
23
+ */
24
+ static function html( $meta, $field )
25
+ {
26
+ if ( ! is_array( $meta ) )
27
+ $meta = array( $meta );
 
28
 
29
+ $options = $field['options'];
30
+ if ( ! is_string( $field['options'] ) )
31
+ {
32
+ $options = array();
33
+ foreach ( $field['options'] as $value => $label )
34
  {
35
+ $options[] = array(
36
+ 'value' => $value,
37
+ 'label' => $label,
38
+ );
 
 
 
 
 
39
  }
40
+ $options = wp_json_encode( $options );
41
+ }
42
 
43
+ // Input field that triggers autocomplete.
44
+ // This field doesn't store field values, so it doesn't have "name" attribute.
45
+ // The value(s) of the field is store in hidden input(s). See below.
46
+ $html = sprintf(
47
+ '<input type="text" class="rwmb-autocomplete-search" size="%s">
48
+ <input type="hidden" name="%s" class="rwmb-autocomplete" data-options="%s" disabled>',
49
+ $field['size'],
50
+ $field['field_name'],
51
+ esc_attr( $options )
52
+ );
53
 
54
+ $html .= '<div class="rwmb-autocomplete-results">';
55
 
56
+ // Each value is displayed with label and 'Delete' option
57
+ // The hidden input has to have ".rwmb-*" class to make clone work
58
+ $tpl = '
59
+ <div class="rwmb-autocomplete-result">
60
+ <div class="label">%s</div>
61
+ <div class="actions">%s</div>
62
+ <input type="hidden" class="rwmb-autocomplete-value" name="%s" value="%s">
63
+ </div>
64
+ ';
65
 
66
+ if ( is_array( $field['options'] ) )
67
+ {
68
+ foreach ( $field['options'] as $value => $label )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  {
70
+ if ( in_array( $value, $meta ) )
71
  {
 
 
 
72
  $html .= sprintf(
73
  $tpl,
74
  $label,
78
  );
79
  }
80
  }
 
 
 
 
81
  }
82
+ else
 
 
 
 
 
 
 
 
83
  {
84
+ foreach ( $meta as $value )
85
+ {
86
+ if ( empty( $value ) )
87
+ continue;
88
+ $label = apply_filters( 'rwmb_autocomplete_result_label', $value, $field );
89
+ $html .= sprintf(
90
+ $tpl,
91
+ $label,
92
+ __( 'Delete', 'meta-box' ),
93
+ $field['field_name'],
94
+ $value
95
+ );
96
+ }
97
  }
98
+
99
+ $html .= '</div>'; // .rwmb-autocomplete-results
100
+
101
+ return $html;
102
+ }
103
+
104
+ /**
105
+ * Normalize parameters for field
106
+ *
107
+ * @param array $field
108
+ * @return array
109
+ */
110
+ static function normalize( $field )
111
+ {
112
+ $field = parent::normalize( $field );
113
+ $field = wp_parse_args( $field, array(
114
+ 'size' => 30,
115
+ ) );
116
+ return $field;
117
  }
118
  }
inc/fields/button.php CHANGED
@@ -1,40 +1,50 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Button_Field' ) )
6
  {
7
- class RWMB_Button_Field extends RWMB_Field
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  {
9
- /**
10
- * Get field HTML
11
- *
12
- * @param mixed $meta
13
- * @param array $field
14
- *
15
- * @return string
16
- */
17
- static function html( $meta, $field )
18
- {
19
- return sprintf(
20
- '<a href="#" id="%s" class="button hide-if-no-js">%s</a>',
21
- $field['id'],
22
- $field['std']
23
- );
24
- }
25
 
26
- /**
27
- * Normalize parameters for field
28
- *
29
- * @param array $field
30
- *
31
- * @return array
32
- */
33
- static function normalize_field( $field )
34
- {
35
- $field['std'] = $field['std'] ? $field['std'] : __( 'Click me', 'meta-box' );
 
 
 
 
36
 
37
- return $field;
38
- }
39
  }
40
  }
1
  <?php
2
+ /**
3
+ * Button field class.
4
+ */
5
+ class RWMB_Button_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Get field HTML
9
+ *
10
+ * @param mixed $meta
11
+ * @param array $field
12
+ * @return string
13
+ */
14
+ static function html( $meta, $field )
15
+ {
16
+ $attributes = self::get_attributes( $field );
17
+ return sprintf( '<a href="#" %s>%s</a>', self::render_attributes( $attributes ), $field['std'] );
18
+ }
19
+
20
+ /**
21
+ * Normalize parameters for field
22
+ *
23
+ * @param array $field
24
+ * @return array
25
+ */
26
+ static function normalize( $field )
27
  {
28
+ $field = parent::normalize( $field );
29
+ $field['std'] = $field['std'] ? $field['std'] : __( 'Click me', 'meta-box' );
30
+ return $field;
31
+ }
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
+ /**
34
+ * Get the attributes for a field
35
+ *
36
+ * @param array $field
37
+ * @param mixed $value
38
+ * @return array
39
+ */
40
+ static function get_attributes( $field, $value = null )
41
+ {
42
+ $attributes = $field['attributes'];
43
+ $attributes = wp_parse_args( $attributes, array(
44
+ 'id' => $field['id'],
45
+ ) );
46
+ $attributes['class'] .= 'button hide-if-no-js';
47
 
48
+ return $attributes;
 
49
  }
50
  }
inc/fields/checkbox-list.php CHANGED
@@ -1,37 +1,63 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Checkbox_List_Field' ) )
6
  {
7
- class RWMB_Checkbox_List_Field extends RWMB_Field_Multiple_Values
 
 
 
 
 
 
 
 
8
  {
9
- /**
10
- * Get field HTML
11
- *
12
- * @param mixed $meta
13
- * @param array $field
14
- *
15
- * @return string
16
- */
17
- static function html( $meta, $field )
18
  {
19
- $meta = (array) $meta;
20
- $html = array();
21
- $tpl = '<label><input type="checkbox" class="rwmb-checkbox-list" name="%s" value="%s"%s> %s</label>';
 
 
 
 
 
22
 
23
- foreach ( $field['options'] as $value => $label )
24
- {
25
- $html[] = sprintf(
26
- $tpl,
27
- $field['field_name'],
28
- $value,
29
- checked( in_array( $value, $meta ), 1, false ),
30
- $label
31
- );
32
- }
33
 
34
- return implode( '<br>', $html );
35
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  }
37
  }
1
  <?php
2
+ /**
3
+ * Checkbox list field class.
4
+ */
5
+ class RWMB_Checkbox_List_Field extends RWMB_Multiple_Values_Field
6
  {
7
+ /**
8
+ * Get field HTML
9
+ *
10
+ * @param mixed $meta
11
+ * @param array $field
12
+ *
13
+ * @return string
14
+ */
15
+ static function html( $meta, $field )
16
  {
17
+ $meta = (array) $meta;
18
+ $html = array();
19
+ $tpl = '<label><input %s %s> %s</label>';
20
+
21
+ foreach ( $field['options'] as $value => $label )
 
 
 
 
22
  {
23
+ $attributes = self::get_attributes( $field, $value );
24
+ $html[] = sprintf(
25
+ $tpl,
26
+ self::render_attributes( $attributes ),
27
+ checked( in_array( (string) $value, $meta, true ), 1, false ),
28
+ $label
29
+ );
30
+ }
31
 
32
+ return implode( '<br>', $html );
33
+ }
 
 
 
 
 
 
 
 
34
 
35
+ /**
36
+ * Normalize parameters for field
37
+ * @param array $field
38
+ * @return array
39
+ */
40
+ static function normalize( $field )
41
+ {
42
+ $field = parent::normalize( $field );
43
+ $field = RWMB_Checkbox_Field::normalize( $field );
44
+
45
+ return $field;
46
+ }
47
+
48
+ /**
49
+ * Get the attributes for field
50
+ *
51
+ * @param array $field
52
+ * @param mixed $value
53
+ *
54
+ * @return array
55
+ */
56
+ static function get_attributes( $field, $value = null )
57
+ {
58
+ $attributes = RWMB_Checkbox_Field::get_attributes( $field, $value );
59
+ $attributes['id'] = false;
60
+
61
+ return $attributes;
62
  }
63
  }
inc/fields/checkbox.php CHANGED
@@ -1,98 +1,87 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "input" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'input.php';
7
-
8
- if ( ! class_exists( 'RWMB_Checkbox_Field' ) )
9
  {
10
- class RWMB_Checkbox_Field extends RWMB_Input_Field
 
 
 
11
  {
12
- /**
13
- * Enqueue scripts and styles
14
- *
15
- * @return void
16
- */
17
- static function admin_enqueue_scripts()
18
- {
19
- wp_enqueue_style( 'rwmb-checkbox', RWMB_CSS_URL . 'checkbox.css', array(), RWMB_VER );
20
- }
21
-
22
- /**
23
- * Get field HTML
24
- *
25
- * @param mixed $meta
26
- * @param array $field
27
- *
28
- * @return string
29
- */
30
- static function html( $meta, $field )
31
- {
32
- $attributes = $field['attributes'];
33
- $attributes['value'] = 1;
34
- return sprintf(
35
- '<input %s value="1" %s>',
36
- self::render_attributes( $attributes ),
37
- checked( ! empty( $meta ), 1, false )
38
- );
39
- }
40
 
41
- /**
42
- * Normalize parameters for field
43
- *
44
- * @param array $field
45
- *
46
- * @return array
47
- */
48
- static function normalize_field( $field )
49
- {
50
- $field = parent::normalize_field( $field );
51
- $field['attributes']['list'] = false;
52
- $field['attributes']['type'] = 'checkbox';
 
 
 
 
53
 
54
- return $field;
55
- }
 
 
 
 
 
 
 
 
 
 
56
 
57
- /**
58
- * Set the value of checkbox to 1 or 0 instead of 'checked' and empty string
59
- * This prevents using default value once the checkbox has been unchecked
60
- *
61
- * @link https://github.com/rilwis/meta-box/issues/6
62
- *
63
- * @param mixed $new
64
- * @param mixed $old
65
- * @param int $post_id
66
- * @param array $field
67
- *
68
- * @return int
69
- */
70
- static function value( $new, $old, $post_id, $field )
71
- {
72
- return empty( $new ) ? 0 : 1;
73
- }
74
 
75
- /**
76
- * Output the field value
77
- * Display 'Yes' or 'No' instead of '1' and '0'
78
- *
79
- * Note: we don't echo the field value directly. We return the output HTML of field, which will be used in
80
- * rwmb_the_field function later.
81
- *
82
- * @use self::get_value()
83
- * @see rwmb_the_field()
84
- *
85
- * @param array $field Field parameters
86
- * @param array $args Additional arguments. Rarely used. See specific fields for details
87
- * @param int|null $post_id Post ID. null for current post. Optional.
88
- *
89
- * @return string HTML output of the field
90
- */
91
- static function the_value( $field, $args = array(), $post_id = null )
92
- {
93
- $value = self::get_value( $field, $args, $post_id );
94
 
95
- return $value ? __( 'Yes', 'meta-box' ) : __( 'No', 'meta-box' );
96
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  }
98
  }
1
  <?php
2
+ /**
3
+ * Checkbox field class.
4
+ */
5
+ class RWMB_Checkbox_Field extends RWMB_Input_Field
 
 
 
6
  {
7
+ /**
8
+ * Enqueue scripts and styles.
9
+ */
10
+ static function admin_enqueue_scripts()
11
  {
12
+ wp_enqueue_style( 'rwmb-checkbox', RWMB_CSS_URL . 'checkbox.css', array(), RWMB_VER );
13
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ /**
16
+ * Get field HTML
17
+ *
18
+ * @param mixed $meta
19
+ * @param array $field
20
+ * @return string
21
+ */
22
+ static function html( $meta, $field )
23
+ {
24
+ $attributes = self::get_attributes( $field, 1 );
25
+ return sprintf(
26
+ '<input %s %s>',
27
+ self::render_attributes( $attributes ),
28
+ checked( ! empty( $meta ), 1, false )
29
+ );
30
+ }
31
 
32
+ /**
33
+ * Get the attributes for a field.
34
+ *
35
+ * @param array $field
36
+ * @param mixed $value
37
+ * @return array
38
+ */
39
+ static function get_attributes( $field, $value = null )
40
+ {
41
+ $attributes = parent::get_attributes( $field, $value );
42
+ $attributes['type'] = 'checkbox';
43
+ $attributes['list'] = false;
44
 
45
+ return $attributes;
46
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
+ /**
49
+ * Set the value of checkbox to 1 or 0 instead of 'checked' and empty string
50
+ * This prevents using default value once the checkbox has been unchecked
51
+ *
52
+ * @link https://github.com/rilwis/meta-box/issues/6
53
+ *
54
+ * @param mixed $new
55
+ * @param mixed $old
56
+ * @param int $post_id
57
+ * @param array $field
58
+ *
59
+ * @return int
60
+ */
61
+ static function value( $new, $old, $post_id, $field )
62
+ {
63
+ return empty( $new ) ? 0 : 1;
64
+ }
 
 
65
 
66
+ /**
67
+ * Output the field value
68
+ * Display 'Yes' or 'No' instead of '1' and '0'
69
+ *
70
+ * Note: we don't echo the field value directly. We return the output HTML of field, which will be used in
71
+ * rwmb_the_field function later.
72
+ *
73
+ * @use self::get_value()
74
+ * @see rwmb_the_field()
75
+ *
76
+ * @param array $field Field parameters
77
+ * @param array $args Additional arguments. Rarely used. See specific fields for details
78
+ * @param int|null $post_id Post ID. null for current post. Optional.
79
+ *
80
+ * @return string HTML output of the field
81
+ */
82
+ static function the_value( $field, $args = array(), $post_id = null )
83
+ {
84
+ $value = self::get_value( $field, $args, $post_id );
85
+ return $value ? __( 'Yes', 'meta-box' ) : __( 'No', 'meta-box' );
86
  }
87
  }
inc/fields/color.php CHANGED
@@ -1,69 +1,85 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "text" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'text.php';
7
-
8
- if ( ! class_exists( 'RWMB_Color_Field' ) )
9
  {
10
- class RWMB_Color_Field extends RWMB_Text_Field
 
 
 
11
  {
12
- /**
13
- * Enqueue scripts and styles
14
- *
15
- * @return void
16
- */
17
- static function admin_enqueue_scripts()
18
- {
19
- wp_enqueue_style( 'rwmb-color', RWMB_CSS_URL . 'color.css', array( 'wp-color-picker' ), RWMB_VER );
20
- wp_enqueue_script( 'rwmb-color', RWMB_JS_URL . 'color.js', array( 'wp-color-picker' ), RWMB_VER, true );
21
- }
22
 
23
- /**
24
- * Don't save '#' when no color is chosen
25
- *
26
- * @param mixed $new
27
- * @param mixed $old
28
- * @param int $post_id
29
- * @param array $field
30
- *
31
- * @return int
32
- */
33
- static function value( $new, $old, $post_id, $field )
34
- {
35
- return '#' === $new ? '' : $new;
36
- }
37
 
38
- /**
39
- * Normalize parameters for field
40
- *
41
- * @param array $field
42
- *
43
- * @return array
44
- */
45
- static function normalize_field( $field )
46
- {
47
- $field = wp_parse_args( $field, array(
48
- 'size' => 7,
49
- 'maxlength' => 7,
50
- 'pattern' => '^#+([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$',
51
- 'js_options' => array(),
52
- ) );
53
 
54
- $field['js_options'] = wp_parse_args( $field['js_options'], array(
55
- 'defaultColor' => false,
56
- 'hide' => true,
57
- 'palettes' => true,
58
- ) );
59
 
60
- $field = parent::normalize_field( $field );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
- $field['attributes'] = wp_parse_args( $field['attributes'], array(
63
- 'data-options' => wp_json_encode( $field['js_options'] ),
64
- ) );
65
 
66
- return $field;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
 
68
  }
69
  }
1
  <?php
2
+ /**
3
+ * Color field class.
4
+ */
5
+ class RWMB_Color_Field extends RWMB_Text_Field
 
 
 
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ */
10
+ static function admin_enqueue_scripts()
11
  {
12
+ wp_enqueue_style( 'rwmb-color', RWMB_CSS_URL . 'color.css', array( 'wp-color-picker' ), RWMB_VER );
13
+ wp_enqueue_script( 'rwmb-color', RWMB_JS_URL . 'color.js', array( 'wp-color-picker' ), RWMB_VER, true );
14
+ }
 
 
 
 
 
 
 
15
 
16
+ /**
17
+ * Normalize parameters for field.
18
+ *
19
+ * @param array $field
20
+ * @return array
21
+ */
22
+ static function normalize( $field )
23
+ {
24
+ $field = wp_parse_args( $field, array(
25
+ 'size' => 7,
26
+ 'maxlength' => 7,
27
+ 'pattern' => '^#+([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$',
28
+ 'js_options' => array(),
29
+ ) );
30
 
31
+ $field['js_options'] = wp_parse_args( $field['js_options'], array(
32
+ 'defaultColor' => false,
33
+ 'hide' => true,
34
+ 'palettes' => true,
35
+ ) );
 
 
 
 
 
 
 
 
 
 
36
 
37
+ $field = parent::normalize( $field );
 
 
 
 
38
 
39
+ return $field;
40
+ }
41
+
42
+ /**
43
+ * Get the attributes for a field
44
+ *
45
+ * @param array $field
46
+ * @param mixed $value
47
+ * @return array
48
+ */
49
+ static function get_attributes( $field, $value = null )
50
+ {
51
+ $attributes = parent::get_attributes( $field, $value );
52
+ $attributes = wp_parse_args( $attributes, array(
53
+ 'data-options' => wp_json_encode( $field['js_options'] ),
54
+ ) );
55
 
56
+ return $attributes;
57
+ }
 
58
 
59
+ /**
60
+ * Output color field as a dot.
61
+ * @param array $field
62
+ * @param array $args
63
+ * @param null $post_id
64
+ * @return string
65
+ */
66
+ static function the_value( $field, $args = array(), $post_id = null )
67
+ {
68
+ $value = self::get_value( $field, $args, $post_id );
69
+ $template = "<span style='display:inline-block;width:20px;height:20px;border-radius:50%%;background:%s;'></span>";
70
+ if ( is_array( $value ) )
71
+ {
72
+ $output = '<ul>';
73
+ foreach ( $value as $subvalue )
74
+ {
75
+ $output .= '<li>' . sprintf( $template, $subvalue ) . '</li>';
76
+ }
77
+ $output .= '</ul>';
78
+ }
79
+ else
80
+ {
81
+ $output = sprintf( $template, $value );
82
  }
83
+ return $output;
84
  }
85
  }
inc/fields/custom-html.php CHANGED
@@ -1,27 +1,24 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Custom_Html_Field' ) )
6
  {
7
- class RWMB_Custom_Html_Field extends RWMB_Field
 
 
 
 
 
 
 
 
8
  {
9
- /**
10
- * Get field HTML
11
- *
12
- * @param mixed $meta
13
- * @param array $field
14
- *
15
- * @return string
16
- */
17
- static function html( $meta, $field )
18
  {
19
- $html = ! empty( $field['std'] ) ? $field['std'] : '';
20
- if ( ! empty( $field['callback'] ) && is_callable( $field['callback'] ) )
21
- {
22
- $html = call_user_func_array( $field['callback'], array( $meta, $field ) );
23
- }
24
- return $html;
25
  }
 
26
  }
27
  }
1
  <?php
2
+ /**
3
+ * Custom HTML field class.
4
+ */
5
+ class RWMB_Custom_Html_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Get field HTML
9
+ *
10
+ * @param mixed $meta
11
+ * @param array $field
12
+ *
13
+ * @return string
14
+ */
15
+ static function html( $meta, $field )
16
  {
17
+ $html = ! empty( $field['std'] ) ? $field['std'] : '';
18
+ if ( ! empty( $field['callback'] ) && is_callable( $field['callback'] ) )
 
 
 
 
 
 
 
19
  {
20
+ $html = call_user_func_array( $field['callback'], array( $meta, $field ) );
 
 
 
 
 
21
  }
22
+ return $html;
23
  }
24
  }
inc/fields/date.php CHANGED
@@ -1,75 +1,102 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "text" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'text.php';
7
-
8
- if ( ! class_exists( 'RWMB_Date_Field' ) )
9
  {
10
- class RWMB_Date_Field extends RWMB_Text_Field
 
 
 
 
 
 
 
 
11
  {
12
- /**
13
- * Enqueue scripts and styles
14
- *
15
- * @return void
16
- */
17
- static function admin_enqueue_scripts()
18
  {
19
- $url = RWMB_CSS_URL . 'jqueryui';
20
- wp_register_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
21
- wp_register_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
22
- wp_register_style( 'wp-datepicker', RWMB_CSS_URL . 'datepicker.css', array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
23
- wp_enqueue_style( 'jquery-ui-datepicker', "{$url}/jquery.ui.datepicker.css", array( 'wp-datepicker' ), '1.8.17' );
24
 
25
- // Load localized scripts
26
- $locale = str_replace( '_', '-', get_locale() );
27
- $file_paths = array( 'jqueryui/datepicker-i18n/jquery.ui.datepicker-' . $locale . '.js' );
28
- // Also check alternate i18n filename (e.g. jquery.ui.datepicker-de.js instead of jquery.ui.datepicker-de-DE.js)
29
- if ( strlen( $locale ) > 2 )
30
- $file_paths[] = 'jqueryui/datepicker-i18n/jquery.ui.datepicker-' . substr( $locale, 0, 2 ) . '.js';
31
- $deps = array( 'jquery-ui-datepicker' );
32
- foreach ( $file_paths as $file_path )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  {
34
- if ( file_exists( RWMB_DIR . 'js/' . $file_path ) )
35
- {
36
- wp_register_script( 'jquery-ui-datepicker-i18n', RWMB_JS_URL . $file_path, $deps, '1.8.17', true );
37
- $deps[] = 'jquery-ui-datepicker-i18n';
38
- break;
39
- }
40
  }
41
-
42
- wp_enqueue_script( 'rwmb-date', RWMB_JS_URL . 'date.js', $deps, RWMB_VER, true );
43
  }
44
 
 
 
45
 
46
- /**
47
- * Normalize parameters for field
48
- *
49
- * @param array $field
50
- *
51
- * @return array
52
- */
53
- static function normalize_field( $field )
54
- {
55
- $field = wp_parse_args( $field, array(
56
- 'js_options' => array(),
57
- ) );
58
 
59
- // Deprecate 'format', but keep it for backward compatible
60
- // Use 'js_options' instead
61
- $field['js_options'] = wp_parse_args( $field['js_options'], array(
62
- 'dateFormat' => empty( $field['format'] ) ? 'yy-mm-dd' : $field['format'],
63
- 'showButtonPanel' => true,
64
- ) );
 
 
 
 
 
 
 
65
 
66
- $field = parent::normalize_field( $field );
 
 
 
 
 
67
 
68
- $field['attributes'] = wp_parse_args( $field['attributes'], array(
69
- 'data-options' => wp_json_encode( $field['js_options'] ),
70
- ) );
71
 
72
- return $field;
73
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  }
75
  }
1
  <?php
2
+ /**
3
+ * Date field class.
4
+ */
5
+ class RWMB_Date_Field extends RWMB_Text_Field
 
 
 
6
  {
7
+ /**
8
+ * Get field HTML
9
+ *
10
+ * @param mixed $meta
11
+ * @param array $field
12
+ *
13
+ * @return string
14
+ */
15
+ static function html( $meta, $field )
16
  {
17
+ $output = parent::html( $meta, $field );
18
+ if( $field['inline'] )
 
 
 
 
19
  {
20
+ $output .= '<div class="rwmb-date-inline"></div>';
21
+ }
22
+ return $output;
23
+ }
 
24
 
25
+ /**
26
+ * Enqueue scripts and styles
27
+ *
28
+ * @return void
29
+ */
30
+ static function admin_enqueue_scripts()
31
+ {
32
+ $url = RWMB_CSS_URL . 'jqueryui';
33
+ wp_register_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
34
+ wp_register_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
35
+ wp_register_style( 'wp-datepicker', RWMB_CSS_URL . 'datepicker.css', array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
36
+ wp_enqueue_style( 'jquery-ui-datepicker', "{$url}/jquery.ui.datepicker.css", array( 'wp-datepicker' ), '1.8.17' );
37
+
38
+ // Load localized scripts
39
+ $locale = str_replace( '_', '-', get_locale() );
40
+ $file_paths = array( 'jqueryui/datepicker-i18n/jquery.ui.datepicker-' . $locale . '.js' );
41
+ // Also check alternate i18n filename (e.g. jquery.ui.datepicker-de.js instead of jquery.ui.datepicker-de-DE.js)
42
+ if ( strlen( $locale ) > 2 )
43
+ $file_paths[] = 'jqueryui/datepicker-i18n/jquery.ui.datepicker-' . substr( $locale, 0, 2 ) . '.js';
44
+ $deps = array( 'jquery-ui-datepicker' );
45
+ foreach ( $file_paths as $file_path )
46
+ {
47
+ if ( file_exists( RWMB_DIR . 'js/' . $file_path ) )
48
  {
49
+ wp_register_script( 'jquery-ui-datepicker-i18n', RWMB_JS_URL . $file_path, $deps, '1.8.17', true );
50
+ $deps[] = 'jquery-ui-datepicker-i18n';
51
+ break;
 
 
 
52
  }
 
 
53
  }
54
 
55
+ wp_enqueue_script( 'rwmb-date', RWMB_JS_URL . 'date.js', $deps, RWMB_VER, true );
56
+ }
57
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
+ /**
60
+ * Normalize parameters for field
61
+ *
62
+ * @param array $field
63
+ *
64
+ * @return array
65
+ */
66
+ static function normalize( $field )
67
+ {
68
+ $field = wp_parse_args( $field, array(
69
+ 'js_options' => array(),
70
+ 'inline' => false,
71
+ ) );
72
 
73
+ // Deprecate 'format', but keep it for backward compatible
74
+ // Use 'js_options' instead
75
+ $field['js_options'] = wp_parse_args( $field['js_options'], array(
76
+ 'dateFormat' => empty( $field['format'] ) ? 'yy-mm-dd' : $field['format'],
77
+ 'showButtonPanel' => true,
78
+ ) );
79
 
80
+ $field = parent::normalize( $field );
 
 
81
 
82
+ return $field;
83
+ }
84
+
85
+ /**
86
+ * Get the attributes for a field
87
+ *
88
+ * @param array $field
89
+ * @param mixed $value
90
+ *
91
+ * @return array
92
+ */
93
+ static function get_attributes( $field, $value = null )
94
+ {
95
+ $attributes = parent::get_attributes( $field, $value );
96
+ $attributes = wp_parse_args( $attributes, array(
97
+ 'data-options' => wp_json_encode( $field['js_options'] ),
98
+ ) );
99
+
100
+ return $attributes;
101
  }
102
  }
inc/fields/datetime.php CHANGED
@@ -1,178 +1,205 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "text" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'date.php';
7
-
8
- if ( ! class_exists( 'RWMB_Datetime_Field' ) )
9
  {
10
- class RWMB_Datetime_Field extends RWMB_Input_Field
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  {
12
- /**
13
- * Translate date format from jQuery UI datepicker to PHP date()
14
- * It's used to store timestamp value of the field
15
- * Missing: 'o' => '', '!' => '', 'oo' => '', '@' => '', "''" => "'"
16
- * @var array
17
- */
18
- static $date_format_translation = array(
19
- 'd' => 'j', 'dd' => 'd', 'oo' => 'z', 'D' => 'D', 'DD' => 'l',
20
- 'm' => 'n', 'mm' => 'm', 'M' => 'M', 'MM' => 'F', 'y' => 'y', 'yy' => 'Y',
21
- );
22
 
23
- /**
24
- * Translate date format from jQuery UI datepicker to PHP date()
25
- * It's used to store timestamp value of the field
26
- * Missing: 't' => '', T' => '', 'm' => '', 's' => ''
27
- * @var array
28
- */
29
- static $time_format_translation = array(
30
- 'H' => 'G', 'HH' => 'H', 'h' => 'g', 'hh' => 'h',
31
- 'mm' => 'i', 'ss' => 's', 'l' => 'u', 'tt' => 'a', 'TT' => 'A',
32
- );
33
 
34
  /**
35
- * Enqueue scripts and styles
 
 
36
  *
37
- * @return void
38
  */
39
- static function admin_enqueue_scripts()
 
 
 
 
 
 
40
  {
41
- $url = RWMB_CSS_URL . 'jqueryui';
42
- wp_register_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
43
- wp_register_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
44
- wp_register_style( 'jquery-ui-datepicker', "{$url}/jquery.ui.datepicker.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
45
- wp_register_style( 'wp-datepicker', RWMB_CSS_URL . 'datepicker.css', array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
46
- wp_register_style( 'jquery-ui-slider', "{$url}/jquery.ui.slider.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
47
- wp_enqueue_style( 'jquery-ui-timepicker', "{$url}/jquery-ui-timepicker-addon.min.css", array( 'jquery-ui-datepicker', 'jquery-ui-slider', 'wp-datepicker' ), '1.5.0' );
48
-
49
- $url = RWMB_JS_URL . 'jqueryui';
50
- wp_register_script( 'jquery-ui-timepicker', "{$url}/jquery-ui-timepicker-addon.min.js", array( 'jquery-ui-datepicker', 'jquery-ui-slider' ), '1.5.0', true );
51
-
52
- /**
53
- * Localization
54
- * Use 1 minified JS file for timepicker which contains all languages for simpilicity (in version < 4.4.2 we use separated JS files).
55
- * The language is set in Javascript
56
- *
57
- * Note: we use full locale (de-DE) and fallback to short locale (de)
58
- */
59
- $locale = str_replace( '_', '-', get_locale() );
60
- $locale_short = substr( $locale, 0, 2 );
61
-
62
- wp_register_script( 'jquery-ui-timepicker-i18n', "{$url}/jquery-ui-timepicker-addon-i18n.min.js", array( 'jquery-ui-timepicker' ), '1.5.0', true );
63
-
64
- $date_paths = array( 'jqueryui/datepicker-i18n/jquery.ui.datepicker-' . $locale . '.js' );
65
- if ( strlen( $locale ) > 2 )
66
- {
67
- // Also check alternate i18n filenames
68
- // (e.g. jquery.ui.datepicker-de.js instead of jquery.ui.datepicker-de-DE.js)
69
- $date_paths[] = 'jqueryui/datepicker-i18n/jquery.ui.datepicker-' . substr( $locale, 0, 2 ) . '.js';
70
- }
71
- $deps = array( 'jquery-ui-timepicker-i18n' );
72
- foreach ( $date_paths as $date_path )
73
  {
74
- if ( file_exists( RWMB_DIR . 'js/' . $date_path ) )
75
- {
76
- wp_register_script( 'jquery-ui-datepicker-i18n', RWMB_JS_URL . $date_path, array( 'jquery-ui-datepicker' ), '1.8.17', true );
77
- $deps[] = 'jquery-ui-datepicker-i18n';
78
- break;
79
- }
80
  }
81
-
82
- wp_enqueue_script( 'rwmb-datetime', RWMB_JS_URL . 'datetime.js', $deps, RWMB_VER, true );
83
- wp_localize_script( 'rwmb-datetime', 'RWMB_Datetimepicker', array(
84
- 'locale' => $locale,
85
- 'localeShort' => $locale_short,
86
- ) );
87
  }
88
 
89
- /**
90
- * Calculates the timestamp from the datetime string and returns it
91
- * if $field['timestamp'] is set or the datetime string if not
92
- *
93
- * @param mixed $new
94
- * @param mixed $old
95
- * @param int $post_id
96
- * @param array $field
97
- *
98
- * @return string|int
99
- */
100
- static function value( $new, $old, $post_id, $field )
 
 
 
 
 
 
 
101
  {
102
- if ( ! $field['timestamp'] )
103
- return $new;
104
 
105
- $d = DateTime::createFromFormat( self::translate_format( $field ), $new );
 
106
 
107
- return $d ? $d->getTimestamp() : 0;
108
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
- /**
111
- * Get meta value
112
- *
113
- * @param int $post_id
114
- * @param bool $saved
115
- * @param array $field
116
- *
117
- * @return mixed
118
- */
119
- static function meta( $post_id, $saved, $field )
 
 
 
120
  {
121
- $meta = parent::meta( $post_id, $saved, $field );
122
- if ( is_array( $meta ) )
123
  {
124
- foreach ( $meta as $key => $value )
125
- {
126
- $meta[$key] = $field['timestamp'] && $value ? date( self::translate_format( $field ), intval( $value ) ) : $value;
127
- }
128
  }
129
- else
130
- {
131
- $meta = $field['timestamp'] && $meta ? date( self::translate_format( $field ), intval( $meta ) ) : $meta;
132
- }
133
- return $meta;
134
  }
135
-
136
- /**
137
- * Normalize parameters for field
138
- *
139
- * @param array $field
140
- *
141
- * @return array
142
- */
143
- static function normalize_field( $field )
144
  {
145
- $field = wp_parse_args( $field, array(
146
- 'timestamp' => false,
147
- 'js_options' => array()
148
- ) );
149
 
150
- // Deprecate 'format', but keep it for backward compatible
151
- // Use 'js_options' instead
152
- $field['js_options'] = wp_parse_args( $field['js_options'], array(
153
- 'timeFormat' => 'HH:mm',
154
- 'separator' => ' ',
155
- ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
- $field = RWMB_Date_Field::normalize_field( $field );
 
 
 
 
 
 
 
 
 
 
158
 
159
- return $field;
160
- }
161
 
162
- /**
163
- * Returns a date() compatible format string from the JavaScript format
164
- *
165
- * @see http://www.php.net/manual/en/function.date.php
166
- *
167
- * @param array $field
168
- *
169
- * @return string
170
- */
171
- static function translate_format( $field )
172
- {
173
- return strtr( $field['js_options']['dateFormat'], self::$date_format_translation )
174
- . $field['js_options']['separator']
175
- . strtr( $field['js_options']['timeFormat'], self::$time_format_translation );
176
- }
177
  }
178
  }
1
  <?php
2
+ /**
3
+ * Datetime field class.
4
+ */
5
+ class RWMB_Datetime_Field extends RWMB_Input_Field
 
 
 
6
  {
7
+ /**
8
+ * Translate date format from jQuery UI datepicker to PHP date()
9
+ * It's used to store timestamp value of the field
10
+ * Missing: 'o' => '', '!' => '', 'oo' => '', '@' => '', "''" => "'"
11
+ * @var array
12
+ */
13
+ static $date_format_translation = array(
14
+ 'd' => 'j', 'dd' => 'd', 'oo' => 'z', 'D' => 'D', 'DD' => 'l',
15
+ 'm' => 'n', 'mm' => 'm', 'M' => 'M', 'MM' => 'F', 'y' => 'y', 'yy' => 'Y',
16
+ );
17
+
18
+ /**
19
+ * Translate date format from jQuery UI datepicker to PHP date()
20
+ * It's used to store timestamp value of the field
21
+ * Missing: 't' => '', T' => '', 'm' => '', 's' => ''
22
+ * @var array
23
+ */
24
+ static $time_format_translation = array(
25
+ 'H' => 'G', 'HH' => 'H', 'h' => 'g', 'hh' => 'h',
26
+ 'mm' => 'i', 'ss' => 's', 'l' => 'u', 'tt' => 'a', 'TT' => 'A',
27
+ );
28
+
29
+ /**
30
+ * Enqueue scripts and styles
31
+ *
32
+ * @return void
33
+ */
34
+ static function admin_enqueue_scripts()
35
  {
36
+ $url = RWMB_CSS_URL . 'jqueryui';
37
+ wp_register_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
38
+ wp_register_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
39
+ wp_register_style( 'jquery-ui-datepicker', "{$url}/jquery.ui.datepicker.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
40
+ wp_register_style( 'wp-datepicker', RWMB_CSS_URL . 'datepicker.css', array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
41
+ wp_register_style( 'jquery-ui-slider', "{$url}/jquery.ui.slider.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
42
+ wp_enqueue_style( 'jquery-ui-timepicker', "{$url}/jquery-ui-timepicker-addon.min.css", array( 'jquery-ui-datepicker', 'jquery-ui-slider', 'wp-datepicker' ), '1.5.0' );
 
 
 
43
 
44
+ $url = RWMB_JS_URL . 'jqueryui';
45
+ wp_register_script( 'jquery-ui-timepicker', "{$url}/jquery-ui-timepicker-addon.min.js", array( 'jquery-ui-datepicker', 'jquery-ui-slider' ), '1.5.0', true );
 
 
 
 
 
 
 
 
46
 
47
  /**
48
+ * Localization
49
+ * Use 1 minified JS file for timepicker which contains all languages for simpilicity (in version < 4.4.2 we use separated JS files).
50
+ * The language is set in Javascript
51
  *
52
+ * Note: we use full locale (de-DE) and fallback to short locale (de)
53
  */
54
+ $locale = str_replace( '_', '-', get_locale() );
55
+ $locale_short = substr( $locale, 0, 2 );
56
+
57
+ wp_register_script( 'jquery-ui-timepicker-i18n', "{$url}/jquery-ui-timepicker-addon-i18n.min.js", array( 'jquery-ui-timepicker' ), '1.5.0', true );
58
+
59
+ $date_paths = array( 'jqueryui/datepicker-i18n/jquery.ui.datepicker-' . $locale . '.js' );
60
+ if ( strlen( $locale ) > 2 )
61
  {
62
+ // Also check alternate i18n filenames
63
+ // (e.g. jquery.ui.datepicker-de.js instead of jquery.ui.datepicker-de-DE.js)
64
+ $date_paths[] = 'jqueryui/datepicker-i18n/jquery.ui.datepicker-' . substr( $locale, 0, 2 ) . '.js';
65
+ }
66
+ $deps = array( 'jquery-ui-timepicker-i18n' );
67
+ foreach ( $date_paths as $date_path )
68
+ {
69
+ if ( file_exists( RWMB_DIR . 'js/' . $date_path ) )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  {
71
+ wp_register_script( 'jquery-ui-datepicker-i18n', RWMB_JS_URL . $date_path, array( 'jquery-ui-datepicker' ), '1.8.17', true );
72
+ $deps[] = 'jquery-ui-datepicker-i18n';
73
+ break;
 
 
 
74
  }
 
 
 
 
 
 
75
  }
76
 
77
+ wp_enqueue_script( 'rwmb-datetime', RWMB_JS_URL . 'datetime.js', $deps, RWMB_VER, true );
78
+ wp_localize_script( 'rwmb-datetime', 'RWMB_Datetimepicker', array(
79
+ 'locale' => $locale,
80
+ 'localeShort' => $locale_short,
81
+ ) );
82
+ }
83
+
84
+ /**
85
+ * Get field HTML
86
+ *
87
+ * @param mixed $meta
88
+ * @param array $field
89
+ *
90
+ * @return string
91
+ */
92
+ static function html( $meta, $field )
93
+ {
94
+ $output = parent::html( $meta, $field );
95
+ if( $field['inline'] )
96
  {
97
+ $output .= '<div class="rwmb-datetime-inline"></div>';
98
+ }
99
 
100
+ return $output;
101
+ }
102
 
103
+ /**
104
+ * Calculates the timestamp from the datetime string and returns it
105
+ * if $field['timestamp'] is set or the datetime string if not
106
+ *
107
+ * @param mixed $new
108
+ * @param mixed $old
109
+ * @param int $post_id
110
+ * @param array $field
111
+ *
112
+ * @return string|int
113
+ */
114
+ static function value( $new, $old, $post_id, $field )
115
+ {
116
+ if ( ! $field['timestamp'] )
117
+ return $new;
118
+ $date = DateTime::createFromFormat( self::translate_format( $field ), $new );
119
+ return $date ? $date->getTimestamp() : 0;
120
+ }
121
 
122
+ /**
123
+ * Get meta value
124
+ *
125
+ * @param int $post_id
126
+ * @param bool $saved
127
+ * @param array $field
128
+ *
129
+ * @return mixed
130
+ */
131
+ static function meta( $post_id, $saved, $field )
132
+ {
133
+ $meta = parent::meta( $post_id, $saved, $field );
134
+ if ( is_array( $meta ) )
135
  {
136
+ foreach ( $meta as $key => $value )
 
137
  {
138
+ $meta[$key] = $field['timestamp'] && $value ? date( self::translate_format( $field ), intval( $value ) ) : $value;
 
 
 
139
  }
 
 
 
 
 
140
  }
141
+ else
 
 
 
 
 
 
 
 
142
  {
143
+ $meta = $field['timestamp'] && $meta ? date( self::translate_format( $field ), intval( $meta ) ) : $meta;
144
+ }
145
+ return $meta;
146
+ }
147
 
148
+ /**
149
+ * Normalize parameters for field
150
+ *
151
+ * @param array $field
152
+ *
153
+ * @return array
154
+ */
155
+ static function normalize( $field )
156
+ {
157
+ $field = wp_parse_args( $field, array(
158
+ 'timestamp' => false,
159
+ 'inline' => false,
160
+ 'js_options' => array()
161
+ ) );
162
+
163
+ // Deprecate 'format', but keep it for backward compatible
164
+ // Use 'js_options' instead
165
+ $field['js_options'] = wp_parse_args( $field['js_options'], array(
166
+ 'timeFormat' => 'HH:mm',
167
+ 'separator' => ' ',
168
+ ) );
169
+
170
+ $field = RWMB_Date_Field::normalize( $field );
171
+
172
+ return $field;
173
+ }
174
 
175
+ /**
176
+ * Get the attributes for a field
177
+ *
178
+ * @param array $field
179
+ * @param mixed $value
180
+ *
181
+ * @return array
182
+ */
183
+ static function get_attributes( $field, $value = null )
184
+ {
185
+ $attributes = RWMB_Date_Field::get_attributes( $field, $value );
186
 
187
+ return $attributes;
188
+ }
189
 
190
+ /**
191
+ * Returns a date() compatible format string from the JavaScript format
192
+ *
193
+ * @see http://www.php.net/manual/en/function.date.php
194
+ *
195
+ * @param array $field
196
+ *
197
+ * @return string
198
+ */
199
+ static function translate_format( $field )
200
+ {
201
+ return strtr( $field['js_options']['dateFormat'], self::$date_format_translation )
202
+ . $field['js_options']['separator']
203
+ . strtr( $field['js_options']['timeFormat'], self::$time_format_translation );
 
204
  }
205
  }
inc/fields/divider.php CHANGED
@@ -1,46 +1,43 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Divider_Field' ) )
6
  {
7
- class RWMB_Divider_Field extends RWMB_Field
 
 
 
 
 
8
  {
9
- /**
10
- * Enqueue scripts and styles
11
- *
12
- * @return void
13
- */
14
- static function admin_enqueue_scripts()
15
- {
16
- wp_enqueue_style( 'rwmb-divider', RWMB_CSS_URL . 'divider.css', array(), RWMB_VER );
17
- }
18
 
19
- /**
20
- * Show begin HTML markup for fields
21
- *
22
- * @param mixed $meta
23
- * @param array $field
24
- *
25
- * @return string
26
- */
27
- static function begin_html( $meta, $field )
28
- {
29
- $attributes = empty( $field['id'] ) ? '' : " id='{$field['id']}'";
30
- return "<hr$attributes>";
31
- }
32
 
33
- /**
34
- * Show end HTML markup for fields
35
- *
36
- * @param mixed $meta
37
- * @param array $field
38
- *
39
- * @return string
40
- */
41
- static function end_html( $meta, $field )
42
- {
43
- return '';
44
- }
45
  }
46
  }
1
  <?php
2
+ /**
3
+ * Divider field class.
4
+ */
5
+ class RWMB_Divider_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ *
10
+ * @return void
11
+ */
12
+ static function admin_enqueue_scripts()
13
  {
14
+ wp_enqueue_style( 'rwmb-divider', RWMB_CSS_URL . 'divider.css', array(), RWMB_VER );
15
+ }
 
 
 
 
 
 
 
16
 
17
+ /**
18
+ * Show begin HTML markup for fields
19
+ *
20
+ * @param mixed $meta
21
+ * @param array $field
22
+ *
23
+ * @return string
24
+ */
25
+ static function begin_html( $meta, $field )
26
+ {
27
+ $attributes = empty( $field['id'] ) ? '' : " id='{$field['id']}'";
28
+ return "<hr$attributes>";
29
+ }
30
 
31
+ /**
32
+ * Show end HTML markup for fields
33
+ *
34
+ * @param mixed $meta
35
+ * @param array $field
36
+ *
37
+ * @return string
38
+ */
39
+ static function end_html( $meta, $field )
40
+ {
41
+ return '';
 
42
  }
43
  }
inc/fields/email.php CHANGED
@@ -1,53 +1,50 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "text" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'text.php';
7
-
8
- if ( ! class_exists( 'RWMB_Email_Field' ) )
9
  {
10
- class RWMB_Email_Field extends RWMB_Text_Field
 
 
 
 
 
 
 
11
  {
12
- /**
13
- * Normalize parameters for field
14
- *
15
- * @param array $field
16
- *
17
- * @return array
18
- */
19
- static function normalize_field( $field )
20
- {
21
- $field = parent::normalize_field( $field );
22
 
23
- $field['attributes']['type'] = 'email';
24
-
25
- return $field;
26
- }
27
 
28
- /**
29
- * Sanitize email
30
- *
31
- * @param mixed $new
32
- * @param mixed $old
33
- * @param int $post_id
34
- * @param array $field
35
- *
36
- * @return string
37
- */
38
- static function value( $new, $old, $post_id, $field )
39
- {
40
- if ( $field['clone'] )
41
- {
42
- $new = (array) $new;
43
- $new = array_map( 'sanitize_email', $new );
44
- }
45
- else
46
- {
47
- $new = sanitize_email( $new );
48
- }
49
 
50
- return $new;
51
- }
 
 
 
 
 
 
 
 
 
 
 
52
  }
53
  }
1
  <?php
2
+ /**
3
+ * Email field class.
4
+ */
5
+ class RWMB_Email_Field extends RWMB_Text_Field
 
 
 
6
  {
7
+ /**
8
+ * Normalize parameters for field
9
+ *
10
+ * @param array $field
11
+ *
12
+ * @return array
13
+ */
14
+ static function normalize( $field )
15
  {
16
+ $field = parent::normalize( $field );
 
 
 
 
 
 
 
 
 
17
 
18
+ return $field;
19
+ }
 
 
20
 
21
+ /**
22
+ * Get the attributes for a field
23
+ *
24
+ * @param array $field
25
+ * @param mixed $value
26
+ *
27
+ * @return array
28
+ */
29
+ static function get_attributes( $field, $value = null )
30
+ {
31
+ $attributes = parent::get_attributes( $field, $value );
32
+ $attributes['type'] = 'email';
33
+ return $attributes;
34
+ }
 
 
 
 
 
 
 
35
 
36
+ /**
37
+ * Sanitize email
38
+ *
39
+ * @param mixed $new
40
+ * @param mixed $old
41
+ * @param int $post_id
42
+ * @param array $field
43
+ *
44
+ * @return string
45
+ */
46
+ static function value( $new, $old, $post_id, $field )
47
+ {
48
+ return $field['clone'] ? array_map( 'sanitize_email', (array) $new ) : sanitize_email( $new );
49
  }
50
  }
inc/fields/fieldset-text.php CHANGED
@@ -1,90 +1,84 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "text" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'text.php';
7
-
8
- if ( ! class_exists( 'RWMB_Fieldset_Text_Field' ) )
9
  {
10
- class RWMB_Fieldset_Text_Field extends RWMB_Text_Field
 
 
 
 
 
 
 
 
11
  {
12
- /**
13
- * Get field HTML
14
- *
15
- * @param mixed $meta
16
- * @param array $field
17
- *
18
- * @return string
19
- */
20
- static function html( $meta, $field )
21
  {
22
- $html = array();
23
- $tpl = '<label>%s %s</label>';
24
-
25
- foreach ( $field['options'] as $key => $label )
26
- {
27
- $value = isset( $meta[$key] ) ? $meta[$key] : '';
28
- $field['attributes']['name'] = $field['field_name'] . "[{$key}]";
29
- $html[] = sprintf( $tpl, $label, parent::html( $value, $field) );
30
- }
31
 
32
- $out = '<fieldset><legend>' . $field['desc'] . '</legend>' . implode( ' ', $html ) . '</fieldset>';
33
 
34
- return $out;
35
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- /**
38
- * Normalize parameters for field
39
- *
40
- * @param array $field
41
- *
42
- * @return array
43
- */
44
- static function normalize_field( $field )
45
  {
46
- $field = parent::normalize_field( $field );
47
- $field['multiple'] = false;
48
- $field['attributes']['id'] = false;
49
- return $field;
50
  }
 
51
 
52
- /**
53
- * Output the field value
54
- * Display options in format Label: value in unordered list
55
- *
56
- * @param array $field Field parameters
57
- * @param array $args Additional arguments. Not used for these fields.
58
- * @param int|null $post_id Post ID. null for current post. Optional.
59
- *
60
- * @return mixed Field value
61
- */
62
- static function the_value( $field, $args = array(), $post_id = null )
63
  {
64
- $value = self::get_value( $field, $args, $post_id );
65
- if ( ! $value )
66
- return '';
67
-
68
- $output = '<table>';
69
- $output .= '<thead><tr>';
70
- foreach ( $field['options'] as $label )
71
  {
72
- $output .= "<th>$label</th>";
73
  }
74
- $output .= '</tr></thead><tbody>';
75
-
76
- foreach ( $value as $subvalue )
77
- {
78
- $output .= '<tr>';
79
- foreach ( $subvalue as $value )
80
- {
81
- $output .= "<td>$value</td>";
82
- }
83
- $output .= '</tr>';
84
- }
85
- $output .= '</tbody></table>';
86
-
87
- return $output;
88
  }
 
 
 
89
  }
90
  }
1
  <?php
2
+ /**
3
+ * Fieldset text class.
4
+ */
5
+ class RWMB_Fieldset_Text_Field extends RWMB_Text_Field
 
 
 
6
  {
7
+ /**
8
+ * Get field HTML
9
+ *
10
+ * @param mixed $meta
11
+ * @param array $field
12
+ *
13
+ * @return string
14
+ */
15
+ static function html( $meta, $field )
16
  {
17
+ $html = array();
18
+ $tpl = '<label>%s %s</label>';
19
+
20
+ foreach ( $field['options'] as $key => $label )
 
 
 
 
 
21
  {
22
+ $value = isset( $meta[$key] ) ? $meta[$key] : '';
23
+ $field['attributes']['name'] = $field['field_name'] . "[{$key}]";
24
+ $html[] = sprintf( $tpl, $label, parent::html( $value, $field ) );
25
+ }
 
 
 
 
 
26
 
27
+ $out = '<fieldset><legend>' . $field['desc'] . '</legend>' . implode( ' ', $html ) . '</fieldset>';
28
 
29
+ return $out;
30
+ }
31
+
32
+ /**
33
+ * Normalize parameters for field
34
+ *
35
+ * @param array $field
36
+ *
37
+ * @return array
38
+ */
39
+ static function normalize( $field )
40
+ {
41
+ $field = parent::normalize( $field );
42
+ $field['multiple'] = false;
43
+ $field['attributes']['id'] = false;
44
+ return $field;
45
+ }
46
+
47
+ /**
48
+ * Output the field value
49
+ * Display options in format Label: value in unordered list
50
+ *
51
+ * @param array $field Field parameters
52
+ * @param array $args Additional arguments. Not used for these fields.
53
+ * @param int|null $post_id Post ID. null for current post. Optional.
54
+ *
55
+ * @return mixed Field value
56
+ */
57
+ static function the_value( $field, $args = array(), $post_id = null )
58
+ {
59
+ $value = self::get_value( $field, $args, $post_id );
60
+ if ( ! $value )
61
+ return '';
62
 
63
+ $output = '<table>';
64
+ $output .= '<thead><tr>';
65
+ foreach ( $field['options'] as $label )
 
 
 
 
 
66
  {
67
+ $output .= "<th>$label</th>";
 
 
 
68
  }
69
+ $output .= '</tr></thead><tbody>';
70
 
71
+ foreach ( $value as $subvalue )
 
 
 
 
 
 
 
 
 
 
72
  {
73
+ $output .= '<tr>';
74
+ foreach ( $subvalue as $value )
 
 
 
 
 
75
  {
76
+ $output .= "<td>$value</td>";
77
  }
78
+ $output .= '</tr>';
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  }
80
+ $output .= '</tbody></table>';
81
+
82
+ return $output;
83
  }
84
  }
inc/fields/file-advanced.php CHANGED
@@ -1,9 +1,42 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- require_once RWMB_FIELDS_DIR . 'media.php';
6
- if ( ! class_exists( 'RWMB_File_Advanced_Field' ) )
7
  {
8
- class RWMB_File_Advanced_Field extends RWMB_Media_Field {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
1
  <?php
2
+ /**
3
+ * File advanced field class which users WordPress media popup to upload and select files.
4
+ */
5
+ class RWMB_File_Advanced_Field extends RWMB_Media_Field
 
6
  {
7
+ /**
8
+ * Get the field value.
9
+ * @param array $field
10
+ * @param array $args
11
+ * @param null $post_id
12
+ * @return mixed
13
+ */
14
+ static function get_value( $field, $args = array(), $post_id = null )
15
+ {
16
+ return RWMB_File_Field::get_value( $field, $args, $post_id );
17
+ }
18
+
19
+ /**
20
+ * Output the field value.
21
+ * @param array $field
22
+ * @param array $args
23
+ * @param null $post_id
24
+ * @return mixed
25
+ */
26
+ static function the_value( $field, $args = array(), $post_id = null )
27
+ {
28
+ return RWMB_File_Field::the_value( $field, $args, $post_id );
29
+ }
30
+
31
+ /**
32
+ * Get uploaded file information.
33
+ *
34
+ * @param int $file_id Attachment image ID (post ID). Required.
35
+ * @param array $args Array of arguments (for size).
36
+ * @return array|bool False if file not found. Array of image info on success
37
+ */
38
+ static function file_info( $file_id, $args = array() )
39
+ {
40
+ return RWMB_File_Field::file_info( $file_id, $args );
41
+ }
42
  }
inc/fields/file-input.php CHANGED
@@ -1,63 +1,64 @@
1
  <?php
2
- if ( ! class_exists( 'RWMB_File_Input_Field' ) )
 
 
 
3
  {
4
- class RWMB_File_Input_Field extends RWMB_Field
 
 
 
 
 
5
  {
6
- /**
7
- * Enqueue scripts and styles
8
- *
9
- * @return void
10
- */
11
- static function admin_enqueue_scripts()
12
- {
13
- // Make sure scripts for new media uploader in WordPress 3.5 is enqueued
14
- wp_enqueue_media();
15
- wp_enqueue_script( 'rwmb-file-input', RWMB_JS_URL . 'file-input.js', array( 'jquery' ), RWMB_VER, true );
16
- wp_localize_script( 'rwmb-file-input', 'rwmbFileInput', array(
17
- 'frameTitle' => __( 'Select File', 'meta-box' ),
18
- ) );
19
- }
20
 
21
- /**
22
- * Get field HTML
23
- *
24
- * @param mixed $meta
25
- * @param array $field
26
- *
27
- * @return string
28
- */
29
- static function html( $meta, $field )
30
- {
31
- return sprintf(
32
- '<input type="text" class="rwmb-file-input" name="%s" id="%s" value="%s" placeholder="%s" size="%s">
33
- <a href="#" class="rwmb-file-input-select button-primary">%s</a>
34
- <a href="#" class="rwmb-file-input-remove button %s">%s</a>',
35
- $field['field_name'],
36
- $field['id'],
37
- $meta,
38
- $field['placeholder'],
39
- $field['size'],
40
- __( 'Select', 'meta-box' ),
41
- $meta ? '' : 'hidden',
42
- __( 'Remove', 'meta-box' )
43
- );
44
- }
45
 
46
- /**
47
- * Normalize parameters for field
48
- *
49
- * @param array $field
50
- *
51
- * @return array
52
- */
53
- static function normalize_field( $field )
54
- {
55
- $field = wp_parse_args( $field, array(
56
- 'size' => 30,
57
- 'placeholder' => '',
58
- ) );
 
59
 
60
- return $field;
61
- }
62
  }
63
  }
1
  <?php
2
+ /**
3
+ * File input field class which uses an input for file URL.
4
+ */
5
+ class RWMB_File_Input_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ *
10
+ * @return void
11
+ */
12
+ static function admin_enqueue_scripts()
13
  {
14
+ // Make sure scripts for new media uploader in WordPress 3.5 is enqueued
15
+ wp_enqueue_media();
16
+ wp_enqueue_script( 'rwmb-file-input', RWMB_JS_URL . 'file-input.js', array( 'jquery' ), RWMB_VER, true );
17
+ wp_localize_script( 'rwmb-file-input', 'rwmbFileInput', array(
18
+ 'frameTitle' => __( 'Select File', 'meta-box' ),
19
+ ) );
20
+ }
 
 
 
 
 
 
 
21
 
22
+ /**
23
+ * Get field HTML
24
+ *
25
+ * @param mixed $meta
26
+ * @param array $field
27
+ *
28
+ * @return string
29
+ */
30
+ static function html( $meta, $field )
31
+ {
32
+ return sprintf(
33
+ '<input type="text" class="rwmb-file-input" name="%s" id="%s" value="%s" placeholder="%s" size="%s">
34
+ <a href="#" class="rwmb-file-input-select button-primary">%s</a>
35
+ <a href="#" class="rwmb-file-input-remove button %s">%s</a>',
36
+ $field['field_name'],
37
+ $field['id'],
38
+ $meta,
39
+ $field['placeholder'],
40
+ $field['size'],
41
+ __( 'Select', 'meta-box' ),
42
+ $meta ? '' : 'hidden',
43
+ __( 'Remove', 'meta-box' )
44
+ );
45
+ }
46
 
47
+ /**
48
+ * Normalize parameters for field
49
+ *
50
+ * @param array $field
51
+ *
52
+ * @return array
53
+ */
54
+ static function normalize( $field )
55
+ {
56
+ $field = parent::normalize( $field );
57
+ $field = wp_parse_args( $field, array(
58
+ 'size' => 30,
59
+ 'placeholder' => '',
60
+ ) );
61
 
62
+ return $field;
 
63
  }
64
  }
inc/fields/file.php CHANGED
@@ -1,382 +1,367 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_File_Field' ) )
6
  {
7
- class RWMB_File_Field extends RWMB_Field
 
 
 
8
  {
9
- /**
10
- * Enqueue scripts and styles
11
- *
12
- * @return void
13
- */
14
- static function admin_enqueue_scripts()
15
- {
16
- wp_enqueue_style( 'rwmb-file', RWMB_CSS_URL . 'file.css', array(), RWMB_VER );
17
- wp_enqueue_script( 'rwmb-file', RWMB_JS_URL . 'file.js', array( 'jquery' ), RWMB_VER, true );
18
- wp_localize_script( 'rwmb-file', 'rwmbFile', array(
19
- 'maxFileUploadsSingle' => __( 'You may only upload maximum %d file', 'meta-box' ),
20
- 'maxFileUploadsPlural' => __( 'You may only upload maximum %d files', 'meta-box' ),
21
- ) );
22
- }
23
 
24
- /**
25
- * Add actions
26
- *
27
- * @return void
28
- */
29
- static function add_actions()
30
- {
31
- // Add data encoding type for file uploading
32
- add_action( 'post_edit_form_tag', array( __CLASS__, 'post_edit_form_tag' ) );
33
 
34
- // Delete file via Ajax
35
- add_action( 'wp_ajax_rwmb_delete_file', array( __CLASS__, 'wp_ajax_delete_file' ) );
36
 
37
- // allow reordering
38
- add_action( 'wp_ajax_rwmb_reorder_files', array( __CLASS__, 'wp_ajax_reorder_files' ) );
39
- }
40
 
41
- /**
42
- * Ajax callback for reordering images
43
- *
44
- * @return void
45
- */
46
- static function wp_ajax_reorder_files()
 
 
 
 
 
 
 
47
  {
48
- $field_id = isset( $_POST['field_id'] ) ? $_POST['field_id'] : 0;
49
- $order = isset( $_POST['order'] ) ? $_POST['order'] : '';
50
- $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
51
-
52
- check_ajax_referer( "rwmb-reorder-files_{$field_id}" );
53
 
54
- parse_str( $order, $items );
 
 
 
 
 
 
 
 
55
 
56
- delete_post_meta( $post_id, $field_id );
 
 
 
 
 
 
 
 
 
 
57
 
58
- foreach ( $items['item'] as $item )
59
- {
60
- add_post_meta( $post_id, $field_id, $item, false );
61
- }
62
 
 
63
  wp_send_json_success();
64
- }
 
 
65
 
66
- /**
67
- * Add data encoding type for file uploading
68
- *
69
- * @return void
70
- */
71
- static function post_edit_form_tag()
72
- {
73
- echo ' enctype="multipart/form-data"';
74
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
- /**
77
- * Ajax callback for deleting files.
78
- * Modified from a function used by "Verve Meta Boxes" plugin
79
- *
80
- * @link http://goo.gl/LzYSq
81
- * @return void
82
- */
83
- static function wp_ajax_delete_file()
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  {
85
- $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
86
- $field_id = isset( $_POST['field_id'] ) ? $_POST['field_id'] : 0;
87
- $attachment_id = isset( $_POST['attachment_id'] ) ? intval( $_POST['attachment_id'] ) : 0;
88
- $force_delete = isset( $_POST['force_delete'] ) ? intval( $_POST['force_delete'] ) : 0;
89
 
90
- check_ajax_referer( "rwmb-delete-file_{$field_id}" );
91
 
92
- delete_post_meta( $post_id, $field_id, $attachment_id );
93
- $ok = $force_delete ? wp_delete_attachment( $attachment_id ) : true;
94
 
95
- if ( $ok )
96
- wp_send_json_success();
97
- else
98
- wp_send_json_error( __( 'Error: Cannot delete file', 'meta-box' ) );
99
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
- /**
102
- * Get field HTML
103
- *
104
- * @param mixed $meta
105
- * @param array $field
106
- *
107
- * @return string
108
- */
109
- static function html( $meta, $field )
110
- {
111
- $i18n_title = apply_filters( 'rwmb_file_upload_string', _x( 'Upload Files', 'file upload', 'meta-box' ), $field );
112
- $i18n_more = apply_filters( 'rwmb_file_add_string', _x( '+ Add new file', 'file upload', 'meta-box' ), $field );
113
-
114
- // Uploaded files
115
- $html = self::get_uploaded_files( $meta, $field );
116
- $new_file_classes = array( 'new-files' );
117
- if ( ! empty( $field['max_file_uploads'] ) && count( $meta ) >= (int) $field['max_file_uploads'] )
118
- $new_file_classes[] = 'hidden';
119
-
120
- // Show form upload
121
- $html .= sprintf(
122
- '<div class="%s">
123
- <h4>%s</h4>
124
- <div class="file-input"><input type="file" name="%s[]" /></div>
125
- <a class="rwmb-add-file" href="#"><strong>%s</strong></a>
126
- </div>',
127
- implode( ' ', $new_file_classes ),
128
- $i18n_title,
129
- $field['id'],
130
- $i18n_more
131
- );
132
 
133
- return $html;
134
- }
135
 
136
- static function get_uploaded_files( $files, $field )
137
  {
138
- $reorder_nonce = wp_create_nonce( "rwmb-reorder-files_{$field['id']}" );
139
- $delete_nonce = wp_create_nonce( "rwmb-delete-file_{$field['id']}" );
140
-
141
- $classes = array( 'rwmb-file', 'rwmb-uploaded' );
142
- if ( count( $files ) <= 0 )
143
- $classes[] = 'hidden';
144
- $ol = '<ul class="%s" data-field_id="%s" data-delete_nonce="%s" data-reorder_nonce="%s" data-force_delete="%s" data-max_file_uploads="%s" data-mime_type="%s">';
145
- $html = sprintf(
146
- $ol,
147
- implode( ' ', $classes ),
148
- $field['id'],
149
- $delete_nonce,
150
- $reorder_nonce,
151
- $field['force_delete'] ? 1 : 0,
152
- $field['max_file_uploads'],
153
- $field['mime_type']
154
- );
155
-
156
- foreach ( $files as $attachment_id )
157
- {
158
- $html .= self::file_html( $attachment_id );
159
- }
160
 
161
- $html .= '</ul>';
 
162
 
163
- return $html;
164
- }
165
 
166
- static function file_html( $attachment_id )
167
- {
168
- $i18n_delete = apply_filters( 'rwmb_file_delete_string', _x( 'Delete', 'file upload', 'meta-box' ) );
169
- $i18n_edit = apply_filters( 'rwmb_file_edit_string', _x( 'Edit', 'file upload', 'meta-box' ) );
170
- $li = '
171
- <li id="item_%s">
172
- <div class="rwmb-icon">%s</div>
173
- <div class="rwmb-info">
174
- <a href="%s" target="_blank">%s</a>
175
- <p>%s</p>
176
- <a title="%s" href="%s" target="_blank">%s</a> |
177
- <a title="%s" class="rwmb-delete-file" href="#" data-attachment_id="%s">%s</a>
178
- </div>
179
- </li>';
180
-
181
- $mime_type = get_post_mime_type( $attachment_id );
182
-
183
- return sprintf(
184
- $li,
185
- $attachment_id,
186
- wp_get_attachment_image( $attachment_id, array( 60, 60 ), true ),
187
- wp_get_attachment_url( $attachment_id ),
188
- get_the_title( $attachment_id ),
189
- $mime_type,
190
- $i18n_edit,
191
- get_edit_post_link( $attachment_id ),
192
- $i18n_edit,
193
- $i18n_delete,
194
- $attachment_id,
195
- $i18n_delete
196
  );
197
- }
198
-
199
- /**
200
- * Get meta values to save
201
- *
202
- * @param mixed $new
203
- * @param mixed $old
204
- * @param int $post_id
205
- * @param array $field
206
- *
207
- * @return array|mixed
208
- */
209
- static function value( $new, $old, $post_id, $field )
210
- {
211
- $name = $field['id'];
212
- if ( empty( $_FILES[$name] ) )
213
- return $new;
214
-
215
- $new = array();
216
- $files = self::fix_file_array( $_FILES[$name] );
217
 
218
- foreach ( $files as $file_item )
219
  {
220
- $file = wp_handle_upload( $file_item, array( 'test_form' => false ) );
221
 
222
- if ( ! isset( $file['file'] ) )
223
- continue;
224
-
225
- $file_name = $file['file'];
226
-
227
- $attachment = array(
228
- 'post_mime_type' => $file['type'],
229
- 'guid' => $file['url'],
230
- 'post_parent' => $post_id,
231
- 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $file_name ) ),
232
- 'post_content' => '',
233
- );
234
- $id = wp_insert_attachment( $attachment, $file_name, $post_id );
235
-
236
- if ( ! is_wp_error( $id ) )
237
- {
238
- wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file_name ) );
239
-
240
- // Save file ID in meta field
241
- $new[] = $id;
242
- }
243
  }
244
-
245
- return array_unique( array_merge( $old, $new ) );
246
  }
247
 
248
- /**
249
- * Fixes the odd indexing of multiple file uploads from the format:
250
- * $_FILES['field']['key']['index']
251
- * To the more standard and appropriate:
252
- * $_FILES['field']['index']['key']
253
- *
254
- * @param array $files
255
- *
256
- * @return array
257
- */
258
- static function fix_file_array( $files )
 
 
 
 
 
 
259
  {
260
- $output = array();
261
- foreach ( $files as $key => $list )
262
  {
263
- foreach ( $list as $index => $value )
264
- {
265
- $output[$index][$key] = $value;
266
- }
267
  }
268
-
269
- return $output;
270
  }
271
 
272
- /**
273
- * Normalize parameters for field
274
- *
275
- * @param array $field
276
- *
277
- * @return array
278
- */
279
- static function normalize_field( $field )
280
- {
281
- $field = wp_parse_args( $field, array(
282
- 'std' => array(),
283
- 'force_delete' => false,
284
- 'max_file_uploads' => 0,
285
- 'mime_type' => '',
286
- ) );
287
- $field['multiple'] = true;
288
-
289
- return $field;
290
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
 
292
  /**
293
- * Get the field value
294
- * The difference between this function and 'meta' function is 'meta' function always returns the escaped value
295
- * of the field saved in the database, while this function returns more meaningful value of the field
296
- *
297
- * @param array $field Field parameters
298
- * @param array $args Not used for this field
299
- * @param int|null $post_id Post ID. null for current post. Optional.
300
- *
301
- * @return mixed Full info of uploaded files
302
  */
303
- static function get_value( $field, $args = array(), $post_id = null )
 
 
 
 
304
  {
305
- if ( ! $post_id )
306
- $post_id = get_the_ID();
307
-
308
- /**
309
- * Get raw meta value in the database, no escape
310
- * Very similar to self::meta() function
311
- */
312
- $file_ids = get_post_meta( $post_id, $field['id'], false );
313
-
314
- // For each file, get full file info
315
- $value = array();
316
- foreach ( $file_ids as $file_id )
317
  {
318
- if ( $file_info = call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'file_info' ), $file_id, $args ) )
319
- {
320
- $value[$file_id] = $file_info;
321
- }
322
  }
323
-
324
- return $value;
325
  }
326
 
327
- /**
328
- * Output the field value
329
- * Display unordered list of files
330
- *
331
- * @param array $field Field parameters
332
- * @param array $args Additional arguments. Not used for these fields.
333
- * @param int|null $post_id Post ID. null for current post. Optional.
334
- *
335
- * @return mixed Field value
336
- */
337
- static function the_value( $field, $args = array(), $post_id = null )
338
- {
339
- $value = self::get_value( $field, $args, $post_id );
340
- if ( ! $value )
341
- return '';
342
 
343
- $output = '<ul>';
344
- foreach ( $value as $file_id => $file_info )
345
- {
346
- $output .= sprintf(
347
- '<li><a href="%s" target="_blank">%s</a></li>',
348
- wp_get_attachment_url( $file_id ),
349
- get_the_title( $file_id )
350
- );
351
- }
352
- $output .= '</ul>';
 
 
 
 
 
353
 
354
- return $output;
 
 
 
 
 
 
 
355
  }
 
356
 
357
- /**
358
- * Get uploaded file information
359
- *
360
- * @param int $file_id Attachment file ID (post ID). Required.
361
- * @param array $args Array of arguments (for size).
362
- *
363
- * @return array|bool False if file not found. Array of (id, name, path, url) on success
364
- */
365
- static function file_info( $file_id, $args = array() )
366
- {
367
- $path = get_attached_file( $file_id );
368
- if ( ! $path )
369
- {
370
- return false;
371
- }
372
 
373
- return array(
374
- 'ID' => $file_id,
375
- 'name' => basename( $path ),
376
- 'path' => $path,
377
- 'url' => wp_get_attachment_url( $file_id ),
378
- 'title' => get_the_title( $file_id ),
379
- );
 
 
 
 
 
 
 
380
  }
 
 
 
 
 
 
 
 
381
  }
382
  }
1
  <?php
2
+ /**
3
+ * File field class which uses HTML <input type="file"> to upload file.
4
+ */
5
+ class RWMB_File_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ */
10
+ static function admin_enqueue_scripts()
11
  {
12
+ wp_enqueue_style( 'rwmb-file', RWMB_CSS_URL . 'file.css', array(), RWMB_VER );
13
+ wp_enqueue_script( 'rwmb-file', RWMB_JS_URL . 'file.js', array( 'jquery' ), RWMB_VER, true );
14
+ wp_localize_script( 'rwmb-file', 'rwmbFile', array(
15
+ 'maxFileUploadsSingle' => __( 'You may only upload maximum %d file', 'meta-box' ),
16
+ 'maxFileUploadsPlural' => __( 'You may only upload maximum %d files', 'meta-box' ),
17
+ ) );
18
+ }
 
 
 
 
 
 
 
19
 
20
+ /**
21
+ * Add custom actions
22
+ */
23
+ static function add_actions()
24
+ {
25
+ // Add data encoding type for file uploading
26
+ add_action( 'post_edit_form_tag', array( __CLASS__, 'post_edit_form_tag' ) );
 
 
27
 
28
+ // Delete file via Ajax
29
+ add_action( 'wp_ajax_rwmb_delete_file', array( __CLASS__, 'wp_ajax_delete_file' ) );
30
 
31
+ // Allow reordering files
32
+ add_action( 'wp_ajax_rwmb_reorder_files', array( __CLASS__, 'wp_ajax_reorder_files' ) );
33
+ }
34
 
35
+ /**
36
+ * Ajax callback for reordering images
37
+ */
38
+ static function wp_ajax_reorder_files()
39
+ {
40
+ $post_id = (int) filter_input( INPUT_POST, 'post_id', FILTER_SANITIZE_NUMBER_INT );
41
+ $field_id = (string) filter_input( INPUT_POST, 'field_id' );
42
+ $order = (string) filter_input( INPUT_POST, 'order' );
43
+
44
+ check_ajax_referer( "rwmb-reorder-files_{$field_id}" );
45
+ parse_str( $order, $items );
46
+ delete_post_meta( $post_id, $field_id );
47
+ foreach ( $items['item'] as $item )
48
  {
49
+ add_post_meta( $post_id, $field_id, $item, false );
50
+ }
51
+ wp_send_json_success();
52
+ }
 
53
 
54
+ /**
55
+ * Add data encoding type for file uploading
56
+ *
57
+ * @return void
58
+ */
59
+ static function post_edit_form_tag()
60
+ {
61
+ echo ' enctype="multipart/form-data"';
62
+ }
63
 
64
+ /**
65
+ * Ajax callback for deleting files.
66
+ * Modified from a function used by "Verve Meta Boxes" plugin
67
+ * @link http://goo.gl/LzYSq
68
+ */
69
+ static function wp_ajax_delete_file()
70
+ {
71
+ $post_id = (int) filter_input( INPUT_POST, 'post_id', FILTER_SANITIZE_NUMBER_INT );
72
+ $field_id = (string) filter_input( INPUT_POST, 'field_id' );
73
+ $attachment_id = (int) filter_input( INPUT_POST, 'attachment_id', FILTER_SANITIZE_NUMBER_INT );
74
+ $force_delete = (int) filter_input( INPUT_POST, 'force_delete', FILTER_SANITIZE_NUMBER_INT );
75
 
76
+ check_ajax_referer( "rwmb-delete-file_{$field_id}" );
77
+ delete_post_meta( $post_id, $field_id, $attachment_id );
78
+ $success = $force_delete ? wp_delete_attachment( $attachment_id ) : true;
 
79
 
80
+ if ( $success )
81
  wp_send_json_success();
82
+ else
83
+ wp_send_json_error( __( 'Error: Cannot delete file', 'meta-box' ) );
84
+ }
85
 
86
+ /**
87
+ * Get field HTML
88
+ *
89
+ * @param mixed $meta
90
+ * @param array $field
91
+ *
92
+ * @return string
93
+ */
94
+ static function html( $meta, $field )
95
+ {
96
+ $i18n_title = apply_filters( 'rwmb_file_upload_string', _x( 'Upload Files', 'file upload', 'meta-box' ), $field );
97
+ $i18n_more = apply_filters( 'rwmb_file_add_string', _x( '+ Add new file', 'file upload', 'meta-box' ), $field );
98
+
99
+ // Uploaded files
100
+ $html = self::get_uploaded_files( $meta, $field );
101
+ $new_file_classes = array( 'new-files' );
102
+ if ( ! empty( $field['max_file_uploads'] ) && count( $meta ) >= (int) $field['max_file_uploads'] )
103
+ $new_file_classes[] = 'hidden';
104
+
105
+ // Show form upload
106
+ $html .= sprintf(
107
+ '<div class="%s">
108
+ <h4>%s</h4>
109
+ <div class="file-input"><input type="file" name="%s[]" /></div>
110
+ <a class="rwmb-add-file" href="#"><strong>%s</strong></a>
111
+ </div>',
112
+ implode( ' ', $new_file_classes ),
113
+ $i18n_title,
114
+ $field['id'],
115
+ $i18n_more
116
+ );
117
+
118
+ return $html;
119
+ }
120
 
121
+ static function get_uploaded_files( $files, $field )
122
+ {
123
+ $reorder_nonce = wp_create_nonce( "rwmb-reorder-files_{$field['id']}" );
124
+ $delete_nonce = wp_create_nonce( "rwmb-delete-file_{$field['id']}" );
125
+
126
+ $classes = array( 'rwmb-file', 'rwmb-uploaded' );
127
+ if ( count( $files ) <= 0 )
128
+ $classes[] = 'hidden';
129
+ $list = '<ul class="%s" data-field_id="%s" data-delete_nonce="%s" data-reorder_nonce="%s" data-force_delete="%s" data-max_file_uploads="%s" data-mime_type="%s">';
130
+ $html = sprintf(
131
+ $list,
132
+ implode( ' ', $classes ),
133
+ $field['id'],
134
+ $delete_nonce,
135
+ $reorder_nonce,
136
+ $field['force_delete'] ? 1 : 0,
137
+ $field['max_file_uploads'],
138
+ $field['mime_type']
139
+ );
140
+
141
+ foreach ( $files as $attachment_id )
142
  {
143
+ $html .= self::file_html( $attachment_id );
144
+ }
 
 
145
 
146
+ $html .= '</ul>';
147
 
148
+ return $html;
149
+ }
150
 
151
+ static function file_html( $attachment_id )
152
+ {
153
+ $i18n_delete = apply_filters( 'rwmb_file_delete_string', _x( 'Delete', 'file upload', 'meta-box' ) );
154
+ $i18n_edit = apply_filters( 'rwmb_file_edit_string', _x( 'Edit', 'file upload', 'meta-box' ) );
155
+ $item = '
156
+ <li id="item_%s">
157
+ <div class="rwmb-icon">%s</div>
158
+ <div class="rwmb-info">
159
+ <a href="%s" target="_blank">%s</a>
160
+ <p>%s</p>
161
+ <a title="%s" href="%s" target="_blank">%s</a> |
162
+ <a title="%s" class="rwmb-delete-file" href="#" data-attachment_id="%s">%s</a>
163
+ </div>
164
+ </li>';
165
+
166
+ $mime_type = get_post_mime_type( $attachment_id );
167
+
168
+ return sprintf(
169
+ $item,
170
+ $attachment_id,
171
+ wp_get_attachment_image( $attachment_id, array( 60, 60 ), true ),
172
+ wp_get_attachment_url( $attachment_id ),
173
+ get_the_title( $attachment_id ),
174
+ $mime_type,
175
+ $i18n_edit,
176
+ get_edit_post_link( $attachment_id ),
177
+ $i18n_edit,
178
+ $i18n_delete,
179
+ $attachment_id,
180
+ $i18n_delete
181
+ );
182
+ }
183
 
184
+ /**
185
+ * Get meta values to save
186
+ *
187
+ * @param mixed $new
188
+ * @param mixed $old
189
+ * @param int $post_id
190
+ * @param array $field
191
+ *
192
+ * @return array|mixed
193
+ */
194
+ static function value( $new, $old, $post_id, $field )
195
+ {
196
+ $name = $field['id'];
197
+ if ( empty( $_FILES[$name] ) )
198
+ return $new;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
+ $new = array();
201
+ $files = self::fix_file_array( $_FILES[$name] );
202
 
203
+ foreach ( $files as $file_item )
204
  {
205
+ $file = wp_handle_upload( $file_item, array( 'test_form' => false ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
207
+ if ( ! isset( $file['file'] ) )
208
+ continue;
209
 
210
+ $file_name = $file['file'];
 
211
 
212
+ $attachment = array(
213
+ 'post_mime_type' => $file['type'],
214
+ 'guid' => $file['url'],
215
+ 'post_parent' => $post_id,
216
+ 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $file_name ) ),
217
+ 'post_content' => '',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  );
219
+ $id = wp_insert_attachment( $attachment, $file_name, $post_id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
+ if ( ! is_wp_error( $id ) )
222
  {
223
+ wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file_name ) );
224
 
225
+ // Save file ID in meta field
226
+ $new[] = $id;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  }
 
 
228
  }
229
 
230
+ return array_unique( array_merge( $old, $new ) );
231
+ }
232
+
233
+ /**
234
+ * Fixes the odd indexing of multiple file uploads from the format:
235
+ * $_FILES['field']['key']['index']
236
+ * To the more standard and appropriate:
237
+ * $_FILES['field']['index']['key']
238
+ *
239
+ * @param array $files
240
+ *
241
+ * @return array
242
+ */
243
+ static function fix_file_array( $files )
244
+ {
245
+ $output = array();
246
+ foreach ( $files as $key => $list )
247
  {
248
+ foreach ( $list as $index => $value )
 
249
  {
250
+ $output[$index][$key] = $value;
 
 
 
251
  }
 
 
252
  }
253
 
254
+ return $output;
255
+ }
256
+
257
+ /**
258
+ * Normalize parameters for field
259
+ *
260
+ * @param array $field
261
+ *
262
+ * @return array
263
+ */
264
+ static function normalize( $field )
265
+ {
266
+ $field = parent::normalize( $field );
267
+ $field = wp_parse_args( $field, array(
268
+ 'std' => array(),
269
+ 'force_delete' => false,
270
+ 'max_file_uploads' => 0,
271
+ 'mime_type' => '',
272
+ ) );
273
+ $field['multiple'] = true;
274
+
275
+ return $field;
276
+ }
277
+
278
+ /**
279
+ * Get the field value
280
+ * The difference between this function and 'meta' function is 'meta' function always returns the escaped value
281
+ * of the field saved in the database, while this function returns more meaningful value of the field
282
+ *
283
+ * @param array $field Field parameters
284
+ * @param array $args Not used for this field
285
+ * @param int|null $post_id Post ID. null for current post. Optional.
286
+ *
287
+ * @return mixed Full info of uploaded files
288
+ */
289
+ static function get_value( $field, $args = array(), $post_id = null )
290
+ {
291
+ if ( ! $post_id )
292
+ $post_id = get_the_ID();
293
 
294
  /**
295
+ * Get raw meta value in the database, no escape
296
+ * Very similar to self::meta() function
 
 
 
 
 
 
 
297
  */
298
+ $file_ids = get_post_meta( $post_id, $field['id'], false );
299
+
300
+ // For each file, get full file info
301
+ $value = array();
302
+ foreach ( $file_ids as $file_id )
303
  {
304
+ if ( $file_info = call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'file_info' ), $file_id, $args ) )
 
 
 
 
 
 
 
 
 
 
 
305
  {
306
+ $value[$file_id] = $file_info;
 
 
 
307
  }
 
 
308
  }
309
 
310
+ return $value;
311
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
312
 
313
+ /**
314
+ * Output the field value
315
+ * Display unordered list of files
316
+ *
317
+ * @param array $field Field parameters
318
+ * @param array $args Additional arguments. Not used for these fields.
319
+ * @param int|null $post_id Post ID. null for current post. Optional.
320
+ *
321
+ * @return mixed Field value
322
+ */
323
+ static function the_value( $field, $args = array(), $post_id = null )
324
+ {
325
+ $value = self::get_value( $field, $args, $post_id );
326
+ if ( ! $value )
327
+ return '';
328
 
329
+ $output = '<ul>';
330
+ foreach ( $value as $file_id => $file_info )
331
+ {
332
+ $output .= sprintf(
333
+ '<li><a href="%s" target="_blank">%s</a></li>',
334
+ wp_get_attachment_url( $file_id ),
335
+ get_the_title( $file_id )
336
+ );
337
  }
338
+ $output .= '</ul>';
339
 
340
+ return $output;
341
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
342
 
343
+ /**
344
+ * Get uploaded file information
345
+ *
346
+ * @param int $file_id Attachment file ID (post ID). Required.
347
+ * @param array $args Array of arguments (for size).
348
+ *
349
+ * @return array|bool False if file not found. Array of (id, name, path, url) on success
350
+ */
351
+ static function file_info( $file_id, $args = array() )
352
+ {
353
+ $path = get_attached_file( $file_id );
354
+ if ( ! $path )
355
+ {
356
+ return false;
357
  }
358
+
359
+ return array(
360
+ 'ID' => $file_id,
361
+ 'name' => basename( $path ),
362
+ 'path' => $path,
363
+ 'url' => wp_get_attachment_url( $file_id ),
364
+ 'title' => get_the_title( $file_id ),
365
+ );
366
  }
367
  }
inc/fields/heading.php CHANGED
@@ -1,48 +1,45 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Heading_Field' ) )
6
  {
7
- class RWMB_Heading_Field extends RWMB_Field
 
 
 
 
 
8
  {
9
- /**
10
- * Enqueue scripts and styles
11
- *
12
- * @return void
13
- */
14
- static function admin_enqueue_scripts()
15
- {
16
- wp_enqueue_style( 'rwmb-heading', RWMB_CSS_URL . 'heading.css', array(), RWMB_VER );
17
- }
18
 
19
- /**
20
- * Show begin HTML markup for fields
21
- *
22
- * @param mixed $meta
23
- * @param array $field
24
- *
25
- * @return string
26
- */
27
- static function begin_html( $meta, $field )
28
- {
29
- $attributes = empty( $field['id'] ) ? '' : " id='{$field['id']}'";
30
- return sprintf( '<h4%s>%s</h4>', $attributes, $field['name'] );
31
- }
32
 
33
- /**
34
- * Show end HTML markup for fields
35
- *
36
- * @param mixed $meta
37
- * @param array $field
38
- *
39
- * @return string
40
- */
41
- static function end_html( $meta, $field )
42
- {
43
- $id = $field['id'] ? " id='{$field['id']}-description'" : '';
44
 
45
- return $field['desc'] ? "<p{$id} class='description'>{$field['desc']}</p>" : '';
46
- }
47
  }
48
  }
1
  <?php
2
+ /**
3
+ * Heading field class.
4
+ */
5
+ class RWMB_Heading_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ *
10
+ * @return void
11
+ */
12
+ static function admin_enqueue_scripts()
13
  {
14
+ wp_enqueue_style( 'rwmb-heading', RWMB_CSS_URL . 'heading.css', array(), RWMB_VER );
15
+ }
 
 
 
 
 
 
 
16
 
17
+ /**
18
+ * Show begin HTML markup for fields
19
+ *
20
+ * @param mixed $meta
21
+ * @param array $field
22
+ *
23
+ * @return string
24
+ */
25
+ static function begin_html( $meta, $field )
26
+ {
27
+ $attributes = empty( $field['id'] ) ? '' : " id='{$field['id']}'";
28
+ return sprintf( '<h4%s>%s</h4>', $attributes, $field['name'] );
29
+ }
30
 
31
+ /**
32
+ * Show end HTML markup for fields
33
+ *
34
+ * @param mixed $meta
35
+ * @param array $field
36
+ *
37
+ * @return string
38
+ */
39
+ static function end_html( $meta, $field )
40
+ {
41
+ $id = $field['id'] ? " id='{$field['id']}-description'" : '';
42
 
43
+ return $field['desc'] ? "<p{$id} class='description'>{$field['desc']}</p>" : '';
 
44
  }
45
  }
inc/fields/hidden.php CHANGED
@@ -1,31 +1,22 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "input" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'input.php';
7
-
8
- if ( ! class_exists( 'RWMB_Hidden_Field' ) )
9
  {
10
- class RWMB_Hidden_Field extends RWMB_Input_Field
 
 
 
 
 
 
 
 
11
  {
12
- /**
13
- * Normalize parameters for field
14
- *
15
- * @param array $field
16
- *
17
- * @return array
18
- */
19
- static function normalize_field( $field )
20
- {
21
- $field = parent::normalize_field( $field );
22
-
23
- $field['attributes'] = array(
24
- 'name' => $field['field_name'],
25
- 'id' => $field['clone'] ? false : $field['id'],
26
- );
27
 
28
- return $field;
29
- }
30
  }
31
  }
1
  <?php
2
+ /**
3
+ * Hidden field class.
4
+ */
5
+ class RWMB_Hidden_Field extends RWMB_Input_Field
 
 
 
6
  {
7
+ /**
8
+ * Get the attributes for a field
9
+ *
10
+ * @param array $field
11
+ * @param mixed $value
12
+ *
13
+ * @return array
14
+ */
15
+ static function get_attributes( $field, $value = null )
16
  {
17
+ $attributes = parent::get_attributes( $field, $value );
18
+ $attributes['type'] = 'hidden';
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ return $attributes;
 
21
  }
22
  }
inc/fields/image-advanced.php CHANGED
@@ -1,52 +1,57 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- require_once RWMB_FIELDS_DIR . 'media.php';
6
- if ( ! class_exists( 'RWMB_Image_Advanced_Field' ) )
7
  {
8
- class RWMB_Image_Advanced_Field extends RWMB_Media_Field
 
 
 
 
 
 
 
9
  {
10
- /**
11
- * Normalize parameters for field
12
- *
13
- * @param array $field
14
- *
15
- * @return array
16
- */
17
- static function normalize_field( $field )
18
- {
19
- $field = parent::normalize_field( $field );
20
- $field['mime_type'] = 'image';
21
 
22
- return $field;
23
- }
 
 
 
 
 
 
 
 
 
24
 
25
- /**
26
- * Get field HTML
27
- *
28
- * @param mixed $meta
29
- * @param array $field
30
- *
31
- * @return string
32
- */
33
- static function html( $meta, $field )
34
- {
35
- $i18n_add = apply_filters( 'rwmb_media_add_string', _x( '+ Add Media', 'media', 'meta-box' ) );
36
- $meta = (array) $meta;
37
- $meta = implode( ',', $meta );
38
- $html = sprintf(
39
- '<input type="hidden" name="%s" value="%s" class="rwmb-image-advanced">
40
- <div class="rwmb-media-view" data-mime-type="%s" data-max-files="%s" data-force-delete="%s"></div>',
41
- $field['field_name'],
42
- esc_attr( $meta ),
43
- $field['mime_type'],
44
- $field['max_file_uploads'] ,
45
- $field['force_delete'] ? 'true' : 'false',
46
- $i18n_add
47
- );
48
 
49
- return $html;
50
- }
 
 
 
 
 
 
 
 
51
  }
52
  }
1
  <?php
2
+ /**
3
+ * Image advanced field class which users WordPress media popup to upload and select images.
4
+ */
5
+ class RWMB_Image_Advanced_Field extends RWMB_Media_Field
 
6
  {
7
+ /**
8
+ * Normalize parameters for field
9
+ *
10
+ * @param array $field
11
+ *
12
+ * @return array
13
+ */
14
+ static function normalize( $field )
15
  {
16
+ $field = parent::normalize( $field );
17
+ $field['mime_type'] = 'image';
18
+
19
+ return $field;
20
+ }
 
 
 
 
 
 
21
 
22
+ /**
23
+ * Get the field value.
24
+ * @param array $field
25
+ * @param array $args
26
+ * @param null $post_id
27
+ * @return mixed
28
+ */
29
+ static function get_value( $field, $args = array(), $post_id = null )
30
+ {
31
+ return RWMB_Image_Field::get_value( $field, $args, $post_id );
32
+ }
33
 
34
+ /**
35
+ * Output the field value.
36
+ * @param array $field
37
+ * @param array $args
38
+ * @param null $post_id
39
+ * @return mixed
40
+ */
41
+ static function the_value( $field, $args = array(), $post_id = null )
42
+ {
43
+ return RWMB_Image_Field::the_value( $field, $args, $post_id );
44
+ }
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
+ /**
47
+ * Get uploaded file information.
48
+ *
49
+ * @param int $file_id Attachment image ID (post ID). Required.
50
+ * @param array $args Array of arguments (for size).
51
+ * @return array|bool False if file not found. Array of image info on success
52
+ */
53
+ static function file_info( $file_id, $args = array() )
54
+ {
55
+ return RWMB_Image_Field::file_info( $file_id, $args );
56
  }
57
  }
inc/fields/image-select.php CHANGED
@@ -1,123 +1,116 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Image_Select_Field' ) )
6
  {
7
- class RWMB_Image_Select_Field extends RWMB_Field
 
 
 
8
  {
9
- /**
10
- * Enqueue scripts and styles
11
- *
12
- * @return void
13
- */
14
- static function admin_enqueue_scripts()
15
- {
16
- wp_enqueue_style( 'rwmb-image-select', RWMB_CSS_URL . 'image-select.css', array(), RWMB_VER );
17
- wp_enqueue_script( 'rwmb-image-select', RWMB_JS_URL . 'image-select.js', array( 'jquery' ), RWMB_VER, true );
18
- }
19
 
20
- /**
21
- * Get field HTML
22
- *
23
- * @param mixed $meta
24
- * @param array $field
25
- *
26
- * @return string
27
- */
28
- static function html( $meta, $field )
 
 
 
 
 
29
  {
30
- $html = array();
31
- $tpl = '<label class="rwmb-image-select"><img src="%s"><input type="%s" class="hidden" name="%s" value="%s"%s></label>';
 
 
 
 
 
 
 
32
 
33
- $meta = (array) $meta;
34
- foreach ( $field['options'] as $value => $image )
35
- {
36
- $html[] = sprintf(
37
- $tpl,
38
- $image,
39
- $field['multiple'] ? 'checkbox' : 'radio',
40
- $field['field_name'],
41
- $value,
42
- checked( in_array( $value, $meta ), true, false )
43
- );
44
- }
45
 
46
- return implode( ' ', $html );
47
- }
 
 
 
 
 
 
 
 
48
 
49
- /**
50
- * Normalize parameters for field
51
- *
52
- * @param array $field
53
- *
54
- * @return array
55
- */
56
- static function normalize_field( $field )
57
- {
58
- $field['field_name'] .= $field['multiple'] ? '[]' : '';
59
 
60
- return $field;
61
- }
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
- /**
64
- * Output the field value
65
- * Display unordered list of images with option for size and link to full size
66
- *
67
- * @param array $field Field parameters
68
- * @param array $args Additional arguments. Not used for these fields.
69
- * @param int|null $post_id Post ID. null for current post. Optional.
70
- *
71
- * @return mixed Field value
72
- */
73
- static function the_value( $field, $args = array(), $post_id = null )
74
  {
75
- $value = self::get_value( $field, $args, $post_id );
76
- if ( ! $value )
77
- return '';
78
-
79
- if ( $field['clone'] )
80
  {
81
- $output = '<ul>';
82
- if ( $field['multiple'] )
83
  {
84
- foreach ( $value as $subvalue )
 
85
  {
86
- $output .= '<li><ul>';
87
- foreach ( $subvalue as &$option )
88
- {
89
- $output .= sprintf( '<li><img src="%s"></li>', esc_url( $field['options'][$value] ) );
90
- }
91
- $output .= '</ul></li>';
92
  }
 
93
  }
94
- else
95
- {
96
- foreach ( $value as &$subvalue )
97
- {
98
- $output .= sprintf( '<li><img src="%s"></li>', esc_url( $field['options'][$subvalue] ) );
99
- }
100
- }
101
- $output .= '</ul>';
102
  }
103
  else
104
  {
105
- if ( $field['multiple'] )
106
  {
107
- $output = '<ul>';
108
- foreach ( $value as &$subvalue )
109
- {
110
- $output .= sprintf( '<li><img src="%s"></li>', esc_url( $field['options'][$subvalue] ) );
111
- }
112
- $output .= '</ul>';
113
  }
114
- else
 
 
 
 
 
 
 
 
115
  {
116
- $output = sprintf( '<img src="%s">', esc_url( $field['options'][$value] ) );
117
  }
 
 
 
 
 
118
  }
119
-
120
- return $output;
121
  }
 
 
122
  }
123
  }
1
  <?php
2
+ /**
3
+ * Image select field class which uses images as radio options.
4
+ */
5
+ class RWMB_Image_Select_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ */
10
+ static function admin_enqueue_scripts()
11
  {
12
+ wp_enqueue_style( 'rwmb-image-select', RWMB_CSS_URL . 'image-select.css', array(), RWMB_VER );
13
+ wp_enqueue_script( 'rwmb-image-select', RWMB_JS_URL . 'image-select.js', array( 'jquery' ), RWMB_VER, true );
14
+ }
 
 
 
 
 
 
 
15
 
16
+ /**
17
+ * Get field HTML
18
+ *
19
+ * @param mixed $meta
20
+ * @param array $field
21
+ * @return string
22
+ */
23
+ static function html( $meta, $field )
24
+ {
25
+ $html = array();
26
+ $tpl = '<label class="rwmb-image-select"><img src="%s"><input type="%s" class="hidden" name="%s" value="%s"%s></label>';
27
+
28
+ $meta = (array) $meta;
29
+ foreach ( $field['options'] as $value => $image )
30
  {
31
+ $html[] = sprintf(
32
+ $tpl,
33
+ $image,
34
+ $field['multiple'] ? 'checkbox' : 'radio',
35
+ $field['field_name'],
36
+ $value,
37
+ checked( in_array( $value, $meta ), true, false )
38
+ );
39
+ }
40
 
41
+ return implode( ' ', $html );
42
+ }
 
 
 
 
 
 
 
 
 
 
43
 
44
+ /**
45
+ * Normalize parameters for field
46
+ *
47
+ * @param array $field
48
+ * @return array
49
+ */
50
+ static function normalize( $field )
51
+ {
52
+ $field = parent::normalize( $field );
53
+ $field['field_name'] .= $field['multiple'] ? '[]' : '';
54
 
55
+ return $field;
56
+ }
 
 
 
 
 
 
 
 
57
 
58
+ /**
59
+ * Output the field value
60
+ * Display unordered list of images with option for size and link to full size
61
+ *
62
+ * @param array $field Field parameters
63
+ * @param array $args Additional arguments. Not used for these fields.
64
+ * @param int|null $post_id Post ID. null for current post. Optional.
65
+ * @return mixed Field value
66
+ */
67
+ static function the_value( $field, $args = array(), $post_id = null )
68
+ {
69
+ $value = self::get_value( $field, $args, $post_id );
70
+ if ( ! $value )
71
+ return '';
72
 
73
+ if ( $field['clone'] )
 
 
 
 
 
 
 
 
 
 
74
  {
75
+ $output = '<ul>';
76
+ if ( $field['multiple'] )
 
 
 
77
  {
78
+ foreach ( $value as $subvalue )
 
79
  {
80
+ $output .= '<li><ul>';
81
+ foreach ( $subvalue as $option )
82
  {
83
+ $output .= sprintf( '<li><img src="%s"></li>', esc_url( $field['options'][$option] ) );
 
 
 
 
 
84
  }
85
+ $output .= '</ul></li>';
86
  }
 
 
 
 
 
 
 
 
87
  }
88
  else
89
  {
90
+ foreach ( $value as $subvalue )
91
  {
92
+ $output .= sprintf( '<li><img src="%s"></li>', esc_url( $field['options'][$subvalue] ) );
 
 
 
 
 
93
  }
94
+ }
95
+ $output .= '</ul>';
96
+ }
97
+ else
98
+ {
99
+ if ( $field['multiple'] )
100
+ {
101
+ $output = '<ul>';
102
+ foreach ( $value as $subvalue )
103
  {
104
+ $output .= sprintf( '<li><img src="%s"></li>', esc_url( $field['options'][$subvalue] ) );
105
  }
106
+ $output .= '</ul>';
107
+ }
108
+ else
109
+ {
110
+ $output = sprintf( '<img src="%s">', esc_url( $field['options'][$value] ) );
111
  }
 
 
112
  }
113
+
114
+ return $output;
115
  }
116
  }
inc/fields/image.php CHANGED
@@ -1,242 +1,234 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
 
5
- if ( ! class_exists( 'RWMB_Image_Field' ) )
 
 
 
6
  {
7
- class RWMB_Image_Field extends RWMB_File_Field
 
 
 
8
  {
9
- /**
10
- * Enqueue scripts and styles
11
- *
12
- * @return void
13
- */
14
- static function admin_enqueue_scripts()
15
- {
16
- // Enqueue same scripts and styles as for file field
17
- parent::admin_enqueue_scripts();
18
 
19
- wp_enqueue_style( 'rwmb-image', RWMB_CSS_URL . 'image.css', array(), RWMB_VER );
20
- wp_enqueue_script( 'rwmb-image', RWMB_JS_URL . 'image.js', array( 'jquery-ui-sortable' ), RWMB_VER, true );
21
- }
22
 
23
- /**
24
- * Add actions
25
- *
26
- * @return void
27
- */
28
- static function add_actions()
29
- {
30
- // Do same actions as file field
31
- parent::add_actions();
32
 
33
- // Reorder images via Ajax
34
- add_action( 'wp_ajax_rwmb_reorder_images', array( __CLASS__, 'wp_ajax_reorder_images' ) );
35
- }
36
 
37
- /**
38
- * Ajax callback for reordering images
39
- *
40
- * @return void
41
- */
42
- static function wp_ajax_reorder_images()
 
 
 
 
 
 
 
43
  {
44
- $field_id = isset( $_POST['field_id'] ) ? $_POST['field_id'] : 0;
45
- $order = isset( $_POST['order'] ) ? $_POST['order'] : '';
46
- $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
47
-
48
- check_ajax_referer( "rwmb-reorder-images_{$field_id}" );
49
-
50
- parse_str( $order, $items );
51
-
52
- delete_post_meta( $post_id, $field_id );
53
- foreach ( $items['item'] as $item )
54
- {
55
- add_post_meta( $post_id, $field_id, $item, false );
56
- }
57
- wp_send_json_success();
58
  }
 
 
59
 
60
- /**
61
- * Get field HTML
62
- *
63
- * @param mixed $meta
64
- * @param array $field
65
- *
66
- * @return string
67
- */
68
- static function html( $meta, $field )
69
- {
70
- $i18n_title = apply_filters( 'rwmb_image_upload_string', _x( 'Upload Images', 'image upload', 'meta-box' ), $field );
71
- $i18n_more = apply_filters( 'rwmb_image_add_string', _x( '+ Add new image', 'image upload', 'meta-box' ), $field );
72
-
73
- // Uploaded images
74
- $html = self::get_uploaded_images( $meta, $field );
75
-
76
- // Show form upload
77
- $html .= sprintf(
78
- '<h4>%s</h4>
79
- <div class="new-files">
80
- <div class="file-input"><input type="file" name="%s[]" /></div>
81
- <a class="rwmb-add-file" href="#"><strong>%s</strong></a>
82
- </div>',
83
- $i18n_title,
84
- $field['id'],
85
- $i18n_more
86
- );
87
-
88
- return $html;
89
- }
90
 
91
- /**
92
- * Get HTML markup for uploaded images
93
- *
94
- * @param array $images
95
- * @param array $field
96
- *
97
- * @return string
98
- */
99
- static function get_uploaded_images( $images, $field )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  {
101
- $reorder_nonce = wp_create_nonce( "rwmb-reorder-images_{$field['id']}" );
102
- $delete_nonce = wp_create_nonce( "rwmb-delete-file_{$field['id']}" );
103
- $classes = array( 'rwmb-images', 'rwmb-uploaded' );
104
- if ( count( $images ) <= 0 )
105
- $classes[] = 'hidden';
106
- $ul = '<ul class="%s" data-field_id="%s" data-delete_nonce="%s" data-reorder_nonce="%s" data-force_delete="%s" data-max_file_uploads="%s">';
107
- $html = sprintf(
108
- $ul,
109
- implode( ' ', $classes ),
110
- $field['id'],
111
- $delete_nonce,
112
- $reorder_nonce,
113
- $field['force_delete'] ? 1 : 0,
114
- $field['max_file_uploads']
115
- );
116
-
117
- foreach ( $images as $image )
118
- {
119
- $html .= self::img_html( $image );
120
- }
121
 
122
- $html .= '</ul>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
- return $html;
125
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
126
 
127
- /**
128
- * Get HTML markup for ONE uploaded image
129
- *
130
- * @param int $image Image ID
131
- *
132
- * @return string
133
- */
134
- static function img_html( $image )
135
  {
136
- $i18n_delete = apply_filters( 'rwmb_image_delete_string', _x( 'Delete', 'image upload', 'meta-box' ) );
137
- $i18n_edit = apply_filters( 'rwmb_image_edit_string', _x( 'Edit', 'image upload', 'meta-box' ) );
138
- $li = '
139
- <li id="item_%s">
140
- <img src="%s" />
141
- <div class="rwmb-image-bar">
142
- <a title="%s" class="rwmb-edit-file" href="%s" target="_blank">%s</a> |
143
- <a title="%s" class="rwmb-delete-file" href="#" data-attachment_id="%s">&times;</a>
144
- </div>
145
- </li>
146
- ';
147
-
148
- $src = wp_get_attachment_image_src( $image, 'thumbnail' );
149
- $src = $src[0];
150
- $link = get_edit_post_link( $image );
151
-
152
- return sprintf(
153
- $li,
154
- $image,
155
- $src,
156
- $i18n_edit, $link, $i18n_edit,
157
- $i18n_delete, $image
158
  );
159
- }
160
-
161
- /**
162
- * Output the field value
163
- * Display unordered list of images with option for size and link to full size
164
- *
165
- * @param array $field Field parameters
166
- * @param array $args Additional arguments. Not used for these fields.
167
- * @param int|null $post_id Post ID. null for current post. Optional.
168
- *
169
- * @return mixed Field value
170
- */
171
- static function the_value( $field, $args = array(), $post_id = null )
172
- {
173
- $value = self::get_value( $field, $args, $post_id );
174
- if ( ! $value )
175
- return '';
176
 
177
- $output = '<ul>';
178
- foreach ( $value as $file_id => $file_info )
179
  {
180
  $img = sprintf(
181
- '<img src="%s" alt="%s" title="%s">',
182
- esc_url( $file_info['url'] ),
183
- esc_attr( $file_info['alt'] ),
184
- esc_attr( $file_info['title'] )
185
  );
186
-
187
- // Link thumbnail to full size image?
188
- if ( isset( $args['link'] ) && $args['link'] )
189
- {
190
- $img = sprintf(
191
- '<a href="%s" title="%s">%s</a>',
192
- esc_url( $file_info['full_url'] ),
193
- esc_attr( $file_info['title'] ),
194
- $img
195
- );
196
- }
197
-
198
- $output .= "<li>$img</li>";
199
  }
200
- $output .= '</ul>';
201
 
202
- return $output;
203
  }
 
204
 
205
- /**
206
- * Get uploaded file information
207
- *
208
- * @param int $file_id Attachment image ID (post ID). Required.
209
- * @param array $args Array of arguments (for size).
210
- *
211
- * @return array|bool False if file not found. Array of image info on success
212
- */
213
- static function file_info( $file_id, $args = array() )
214
- {
215
- $args = wp_parse_args( $args, array(
216
- 'size' => 'thumbnail',
217
- ) );
218
 
219
- $img_src = wp_get_attachment_image_src( $file_id, $args['size'] );
220
- if ( ! $img_src )
221
- {
222
- return false;
223
- }
 
 
 
 
 
 
 
 
224
 
225
- $attachment = get_post( $file_id );
226
- $path = get_attached_file( $file_id );
227
- return array(
228
- 'ID' => $file_id,
229
- 'name' => basename( $path ),
230
- 'path' => $path,
231
- 'url' => $img_src[0],
232
- 'width' => $img_src[1],
233
- 'height' => $img_src[2],
234
- 'full_url' => wp_get_attachment_url( $file_id ),
235
- 'title' => $attachment->post_title,
236
- 'caption' => $attachment->post_excerpt,
237
- 'description' => $attachment->post_content,
238
- 'alt' => get_post_meta( $file_id, '_wp_attachment_image_alt', true ),
239
- );
 
 
 
 
 
 
 
 
 
240
  }
 
241
  }
242
  }
1
  <?php
 
 
2
 
3
+ /**
4
+ * Image field class which uses <input type="file"> to upload.
5
+ */
6
+ class RWMB_Image_Field extends RWMB_File_Field
7
  {
8
+ /**
9
+ * Enqueue scripts and styles.
10
+ */
11
+ static function admin_enqueue_scripts()
12
  {
13
+ // Enqueue same scripts and styles as for file field
14
+ parent::admin_enqueue_scripts();
 
 
 
 
 
 
 
15
 
16
+ wp_enqueue_style( 'rwmb-image', RWMB_CSS_URL . 'image.css', array(), RWMB_VER );
17
+ wp_enqueue_script( 'rwmb-image', RWMB_JS_URL . 'image.js', array( 'jquery-ui-sortable' ), RWMB_VER, true );
18
+ }
19
 
20
+ /**
21
+ * Add custom actions.
22
+ */
23
+ static function add_actions()
24
+ {
25
+ // Do same actions as file field
26
+ parent::add_actions();
 
 
27
 
28
+ // Reorder images via Ajax
29
+ add_action( 'wp_ajax_rwmb_reorder_images', array( __CLASS__, 'wp_ajax_reorder_images' ) );
30
+ }
31
 
32
+ /**
33
+ * Ajax callback for reordering images.
34
+ */
35
+ static function wp_ajax_reorder_images()
36
+ {
37
+ $post_id = (int) filter_input( INPUT_POST, 'post_id', FILTER_SANITIZE_NUMBER_INT );
38
+ $field_id = (string) filter_input( INPUT_POST, 'field_id' );
39
+ $order = (string) filter_input( INPUT_POST, 'order' );
40
+
41
+ check_ajax_referer( "rwmb-reorder-images_{$field_id}" );
42
+ parse_str( $order, $items );
43
+ delete_post_meta( $post_id, $field_id );
44
+ foreach ( $items['item'] as $item )
45
  {
46
+ add_post_meta( $post_id, $field_id, $item, false );
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  }
48
+ wp_send_json_success();
49
+ }
50
 
51
+ /**
52
+ * Get field HTML
53
+ *
54
+ * @param mixed $meta
55
+ * @param array $field
56
+ *
57
+ * @return string
58
+ */
59
+ static function html( $meta, $field )
60
+ {
61
+ $i18n_title = apply_filters( 'rwmb_image_upload_string', _x( 'Upload Images', 'image upload', 'meta-box' ), $field );
62
+ $i18n_more = apply_filters( 'rwmb_image_add_string', _x( '+ Add new image', 'image upload', 'meta-box' ), $field );
63
+
64
+ // Uploaded images
65
+ $html = self::get_uploaded_images( $meta, $field );
66
+
67
+ // Show form upload
68
+ $html .= sprintf(
69
+ '<h4>%s</h4>
70
+ <div class="new-files">
71
+ <div class="file-input"><input type="file" name="%s[]" /></div>
72
+ <a class="rwmb-add-file" href="#"><strong>%s</strong></a>
73
+ </div>',
74
+ $i18n_title,
75
+ $field['id'],
76
+ $i18n_more
77
+ );
78
+
79
+ return $html;
80
+ }
81
 
82
+ /**
83
+ * Get HTML markup for uploaded images
84
+ *
85
+ * @param array $images
86
+ * @param array $field
87
+ *
88
+ * @return string
89
+ */
90
+ static function get_uploaded_images( $images, $field )
91
+ {
92
+ $reorder_nonce = wp_create_nonce( "rwmb-reorder-images_{$field['id']}" );
93
+ $delete_nonce = wp_create_nonce( "rwmb-delete-file_{$field['id']}" );
94
+ $classes = array( 'rwmb-images', 'rwmb-uploaded' );
95
+ if ( count( $images ) <= 0 )
96
+ $classes[] = 'hidden';
97
+ $list = '<ul class="%s" data-field_id="%s" data-delete_nonce="%s" data-reorder_nonce="%s" data-force_delete="%s" data-max_file_uploads="%s">';
98
+ $html = sprintf(
99
+ $list,
100
+ implode( ' ', $classes ),
101
+ $field['id'],
102
+ $delete_nonce,
103
+ $reorder_nonce,
104
+ $field['force_delete'] ? 1 : 0,
105
+ $field['max_file_uploads']
106
+ );
107
+
108
+ foreach ( $images as $image )
109
  {
110
+ $html .= self::img_html( $image );
111
+ }
112
+ $html .= '</ul>';
113
+ return $html;
114
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
+ /**
117
+ * Get HTML markup for ONE uploaded image
118
+ *
119
+ * @param int $image Image ID
120
+ * @return string
121
+ */
122
+ static function img_html( $image )
123
+ {
124
+ $i18n_delete = apply_filters( 'rwmb_image_delete_string', _x( 'Delete', 'image upload', 'meta-box' ) );
125
+ $i18n_edit = apply_filters( 'rwmb_image_edit_string', _x( 'Edit', 'image upload', 'meta-box' ) );
126
+ $item = '
127
+ <li id="item_%s">
128
+ <img src="%s" />
129
+ <div class="rwmb-image-bar">
130
+ <a title="%s" class="rwmb-edit-file" href="%s" target="_blank">%s</a> |
131
+ <a title="%s" class="rwmb-delete-file" href="#" data-attachment_id="%s">&times;</a>
132
+ </div>
133
+ </li>
134
+ ';
135
+
136
+ $src = wp_get_attachment_image_src( $image, 'thumbnail' );
137
+ $src = $src[0];
138
+ $link = get_edit_post_link( $image );
139
+
140
+ return sprintf(
141
+ $item,
142
+ $image,
143
+ $src,
144
+ $i18n_edit, $link, $i18n_edit,
145
+ $i18n_delete, $image
146
+ );
147
+ }
148
 
149
+ /**
150
+ * Output the field value
151
+ * Display unordered list of images with option for size and link to full size
152
+ *
153
+ * @param array $field Field parameters
154
+ * @param array $args Additional arguments. Not used for these fields.
155
+ * @param int|null $post_id Post ID. null for current post. Optional.
156
+ *
157
+ * @return mixed Field value
158
+ */
159
+ static function the_value( $field, $args = array(), $post_id = null )
160
+ {
161
+ $value = self::get_value( $field, $args, $post_id );
162
+ if ( ! $value )
163
+ return '';
164
 
165
+ $output = '<ul>';
166
+ foreach ( $value as $file_info )
 
 
 
 
 
 
167
  {
168
+ $img = sprintf(
169
+ '<img src="%s" alt="%s" title="%s">',
170
+ esc_url( $file_info['url'] ),
171
+ esc_attr( $file_info['alt'] ),
172
+ esc_attr( $file_info['title'] )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
 
175
+ // Link thumbnail to full size image?
176
+ if ( isset( $args['link'] ) && $args['link'] )
177
  {
178
  $img = sprintf(
179
+ '<a href="%s" title="%s">%s</a>',
180
+ esc_url( $file_info['full_url'] ),
181
+ esc_attr( $file_info['title'] ),
182
+ $img
183
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  }
 
185
 
186
+ $output .= "<li>$img</li>";
187
  }
188
+ $output .= '</ul>';
189
 
190
+ return $output;
191
+ }
 
 
 
 
 
 
 
 
 
 
 
192
 
193
+ /**
194
+ * Get uploaded file information
195
+ *
196
+ * @param int $file_id Attachment image ID (post ID). Required.
197
+ * @param array $args Array of arguments (for size).
198
+ *
199
+ * @return array|bool False if file not found. Array of image info on success
200
+ */
201
+ static function file_info( $file_id, $args = array() )
202
+ {
203
+ $args = wp_parse_args( $args, array(
204
+ 'size' => 'thumbnail',
205
+ ) );
206
 
207
+ $img_src = wp_get_attachment_image_src( $file_id, $args['size'] );
208
+ if ( ! $img_src )
209
+ {
210
+ return false;
211
+ }
212
+
213
+ $attachment = get_post( $file_id );
214
+ $path = get_attached_file( $file_id );
215
+ $info = array(
216
+ 'ID' => $file_id,
217
+ 'name' => basename( $path ),
218
+ 'path' => $path,
219
+ 'url' => $img_src[0],
220
+ 'width' => $img_src[1],
221
+ 'height' => $img_src[2],
222
+ 'full_url' => wp_get_attachment_url( $file_id ),
223
+ 'title' => $attachment->post_title,
224
+ 'caption' => $attachment->post_excerpt,
225
+ 'description' => $attachment->post_content,
226
+ 'alt' => get_post_meta( $file_id, '_wp_attachment_image_alt', true ),
227
+ );
228
+ if ( function_exists( 'wp_get_attachment_image_srcset' ) )
229
+ {
230
+ $info['srcset'] = wp_get_attachment_image_srcset( $file_id );
231
  }
232
+ return $info;
233
  }
234
  }
inc/fields/input.php CHANGED
@@ -1,87 +1,83 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Input_Field' ) )
6
  {
7
- abstract class RWMB_Input_Field extends RWMB_Field
 
 
 
 
 
 
 
8
  {
9
- /**
10
- * Get field HTML
11
- *
12
- * @param mixed $meta
13
- * @param array $field
14
- *
15
- * @return string
16
- */
17
- static function html( $meta, $field )
18
- {
19
- $attributes = $field['attributes'];
20
- $attributes['value'] = $meta;
21
-
22
- return sprintf(
23
- '<input %s>%s',
24
- self::render_attributes( $attributes ),
25
- self::datalist_html( $field )
26
- );
27
- }
28
 
29
- /**
30
- * Normalize parameters for field
31
- *
32
- * @param array $field
33
- *
34
- * @return array
35
- */
36
- static function normalize_field( $field )
 
 
 
 
 
 
37
  {
38
- $field = parent::normalize_field( $field );
39
- $field = wp_parse_args( $field, array(
40
- 'datalist' => false,
41
- 'readonly' => false,
42
- ) );
43
- if ( $field['datalist'] )
44
- {
45
- $field['datalist'] = wp_parse_args( $field['datalist'], array(
46
- 'id' => $field['id'] . '_list',
47
- 'options' => array(),
48
- ) );
49
- }
50
-
51
- $field['attributes'] = wp_parse_args( $field['attributes'], array(
52
- 'list' => $field['datalist'] ? $field['datalist']['id'] : false,
53
- 'readonly' => $field['readonly'],
54
  ) );
55
-
56
- return $field;
57
  }
 
 
58
 
59
- /**
60
- * Create datalist, if any
61
- *
62
- * @param array $field
63
- *
64
- * @return array
65
- */
66
- static function datalist_html( $field )
67
- {
68
- if ( empty( $field['datalist'] ) )
69
- return '';
70
-
71
- $datalist = $field['datalist'];
72
- $html = sprintf(
73
- '<datalist id="%s">',
74
- $datalist['id']
75
- );
76
 
77
- foreach ( $datalist['options'] as $option )
78
- {
79
- $html .= sprintf( '<option value="%s"></option>', $option );
80
- }
81
 
82
- $html .= '</datalist>';
 
 
 
 
 
 
 
 
 
83
 
84
- return $html;
 
 
 
 
85
  }
 
 
86
  }
87
  }
1
  <?php
2
+ /**
3
+ * Abstract input field class which is used for all <input> fields.
4
+ */
5
+ abstract class RWMB_Input_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Get field HTML
9
+ *
10
+ * @param mixed $meta
11
+ * @param array $field
12
+ * @return string
13
+ */
14
+ static function html( $meta, $field )
15
  {
16
+ $attributes = call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'get_attributes' ), $field, $meta );
17
+ return sprintf( '<input %s>%s', self::render_attributes( $attributes ), self::datalist_html( $field ) );
18
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ /**
21
+ * Normalize parameters for field
22
+ *
23
+ * @param array $field
24
+ * @return array
25
+ */
26
+ static function normalize( $field )
27
+ {
28
+ $field = parent::normalize( $field );
29
+ $field = wp_parse_args( $field, array(
30
+ 'datalist' => false,
31
+ 'readonly' => false,
32
+ ) );
33
+ if ( $field['datalist'] )
34
  {
35
+ $field['datalist'] = wp_parse_args( $field['datalist'], array(
36
+ 'id' => $field['id'] . '_list',
37
+ 'options' => array(),
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  ) );
 
 
39
  }
40
+ return $field;
41
+ }
42
 
43
+ /**
44
+ * Get the attributes for a field
45
+ *
46
+ * @param array $field
47
+ * @param mixed $value
48
+ * @return array
49
+ */
50
+ static function get_attributes( $field, $value = null )
51
+ {
52
+ $attributes = parent::get_attributes( $field, $value );
53
+ $attributes = wp_parse_args( $attributes, array(
54
+ 'list' => $field['datalist'] ? $field['datalist']['id'] : false,
55
+ 'readonly' => $field['readonly'],
56
+ 'value' => $value,
57
+ 'placeholder' => $field['placeholder'],
58
+ ) );
 
59
 
60
+ return $attributes;
61
+ }
 
 
62
 
63
+ /**
64
+ * Create datalist, if any
65
+ *
66
+ * @param array $field
67
+ * @return array
68
+ */
69
+ static function datalist_html( $field )
70
+ {
71
+ if ( empty( $field['datalist'] ) )
72
+ return '';
73
 
74
+ $datalist = $field['datalist'];
75
+ $html = sprintf( '<datalist id="%s">', $datalist['id'] );
76
+ foreach ( $datalist['options'] as $option )
77
+ {
78
+ $html .= sprintf( '<option value="%s"></option>', $option );
79
  }
80
+ $html .= '</datalist>';
81
+ return $html;
82
  }
83
  }
inc/fields/key-value.php CHANGED
@@ -1,158 +1,149 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Key_Value_Field' ) )
6
  {
7
- class RWMB_Key_Value_Field extends RWMB_Field
 
 
 
 
 
 
 
8
  {
9
- /**
10
- * Get field HTML
11
- *
12
- * @param mixed $meta
13
- * @param array $field
14
- *
15
- * @return string
16
- */
17
- static function html( $meta, $field )
18
- {
19
- $tpl = '<input type="text" class="rwmb-key-val" name="%s[]" value="%s" placeholder="' . esc_attr__( 'Key', 'meta-box' ) . '">';
20
- $tpl .= '<input type="text" class="rwmb-key-val" name="%s[]" value="%s" placeholder="' . esc_attr__( 'Value', 'meta-box' ) . '">';
21
-
22
- $key = isset( $meta[0] ) ? $meta[0] : '';
23
- $val = isset( $meta[1] ) ? $meta[1] : '';
24
-
25
- $html = sprintf( $tpl, $field['field_name'], $key, $field['field_name'], $val );
26
-
27
- return $html;
28
- }
29
-
30
- /**
31
- * Show begin HTML markup for fields
32
- *
33
- * @param mixed $meta
34
- * @param array $field
35
- *
36
- * @return string
37
- */
38
- static function begin_html( $meta, $field )
39
- {
40
- $desc = $field['desc'] ? "<p id='{$field['id']}_description' class='description'>{$field['desc']}</p>" : '';
41
-
42
- if ( empty( $field['name'] ) )
43
- return '<div class="rwmb-input">' . $desc;
44
-
45
- return sprintf(
46
- '<div class="rwmb-label">
47
- <label for="%s">%s</label>
48
- </div>
49
- <div class="rwmb-input">
50
- %s',
51
- $field['id'],
52
- $field['name'],
53
- $desc
54
- );
55
- }
56
-
57
- /**
58
- * Show end HTML markup for fields
59
- * Do not show field description. Field description is shown before list of fields
60
- *
61
- * @param mixed $meta
62
- * @param array $field
63
- *
64
- * @return string
65
- */
66
- static function end_html( $meta, $field )
67
- {
68
- $button = $field['clone'] ? call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'add_clone_button' ), $field ) : '';
69
 
70
- // Closes the container
71
- $html = "$button</div>";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
- return $html;
74
- }
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
- /**
77
- * Escape meta for field output
78
- *
79
- * @param mixed $meta
80
- *
81
- * @return mixed
82
- */
83
- static function esc_meta( $meta )
 
84
  {
85
- foreach ( (array) $meta as $k => $pairs )
86
- {
87
- $meta[$k] = array_map( 'esc_attr', (array) $pairs );
88
- }
89
- return $meta;
90
  }
 
 
91
 
92
- /**
93
- * Sanitize email
94
- *
95
- * @param mixed $new
96
- * @param mixed $old
97
- * @param int $post_id
98
- * @param array $field
99
- *
100
- * @return string
101
- */
102
- static function value( $new, $old, $post_id, $field )
 
 
103
  {
104
- foreach ( $new as &$arr )
105
- {
106
- if ( empty( $arr[0] ) && empty( $arr[1] ) )
107
- $arr = false;
108
- }
109
-
110
- $new = array_filter( $new );
111
-
112
- return $new;
113
  }
 
 
 
114
 
115
- /**
116
- * Normalize parameters for field
117
- *
118
- * @param array $field
119
- *
120
- * @return array
121
- */
122
- static function normalize_field( $field )
123
- {
124
- $field['clone'] = true;
125
- $field['multiple'] = false;
 
 
126
 
127
- return $field;
128
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
 
130
- /**
131
- * Output the field value
132
- * Display unordered list of key - value pairs
133
- *
134
- * @use self::get_value()
135
- * @see rwmb_the_field()
136
- *
137
- * @param array $field Field parameters
138
- * @param array $args Additional arguments. Rarely used. See specific fields for details
139
- * @param int|null $post_id Post ID. null for current post. Optional.
140
- *
141
- * @return string HTML output of the field
142
- */
143
- static function the_value( $field, $args = array(), $post_id = null )
144
  {
145
- $value = self::get_value( $field, $args, $post_id );
146
- if ( ! is_array( $value ) )
147
- return '';
148
-
149
- $output = '<ul>';
150
- foreach ( $value as $subvalue )
151
- {
152
- $output .= sprintf( '<li><label>%s</label>: %s</li>', $subvalue[0], $subvalue[1] );
153
- }
154
- $output .= '</ul>';
155
- return $output;
156
  }
 
 
157
  }
158
  }
1
  <?php
2
+ /**
3
+ * Key-value field class.
4
+ */
5
+ abstract class RWMB_Key_Value_Field extends RWMB_Text_Field
6
  {
7
+ /**
8
+ * Get field HTML
9
+ *
10
+ * @param mixed $meta
11
+ * @param array $field
12
+ * @return string
13
+ */
14
+ static function html( $meta, $field )
15
  {
16
+ // Key
17
+ $key = isset( $meta[0] ) ? $meta[0] : '';
18
+ $attributes = self::get_attributes( $field, $key );
19
+ $attributes['placeholder'] = esc_attr__( 'Key', 'meta-box' );
20
+ $html = sprintf( '<input %s>', self::render_attributes( $attributes ) );
21
+
22
+ // Value
23
+ $val = isset( $meta[1] ) ? $meta[1] : '';
24
+ $attributes = self::get_attributes( $field, $val );
25
+ $attributes['placeholder'] = esc_attr__( 'Value', 'meta-box' );
26
+ $html .= sprintf( '<input %s>', self::render_attributes( $attributes ) );
27
+
28
+ return $html;
29
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
+ /**
32
+ * Show begin HTML markup for fields
33
+ *
34
+ * @param mixed $meta
35
+ * @param array $field
36
+ * @return string
37
+ */
38
+ static function begin_html( $meta, $field )
39
+ {
40
+ $desc = $field['desc'] ? "<p id='{$field['id']}_description' class='description'>{$field['desc']}</p>" : '';
41
+
42
+ if ( empty( $field['name'] ) )
43
+ return '<div class="rwmb-input">' . $desc;
44
+
45
+ return sprintf(
46
+ '<div class="rwmb-label">
47
+ <label for="%s">%s</label>
48
+ </div>
49
+ <div class="rwmb-input">
50
+ %s',
51
+ $field['id'],
52
+ $field['name'],
53
+ $desc
54
+ );
55
+ }
56
 
57
+ /**
58
+ * Show end HTML markup for fields
59
+ * Do not show field description. Field description is shown before list of fields
60
+ *
61
+ * @param mixed $meta
62
+ * @param array $field
63
+ * @return string
64
+ */
65
+ static function end_html( $meta, $field )
66
+ {
67
+ $button = $field['clone'] ? self::add_clone_button( $field ) : '';
68
+ $html = "$button</div>";
69
+ return $html;
70
+ }
71
 
72
+ /**
73
+ * Escape meta for field output
74
+ *
75
+ * @param mixed $meta
76
+ * @return mixed
77
+ */
78
+ static function esc_meta( $meta )
79
+ {
80
+ foreach ( (array) $meta as $k => $pairs )
81
  {
82
+ $meta[$k] = array_map( 'esc_attr', (array) $pairs );
 
 
 
 
83
  }
84
+ return $meta;
85
+ }
86
 
87
+ /**
88
+ * Sanitize field value.
89
+ *
90
+ * @param mixed $new
91
+ * @param mixed $old
92
+ * @param int $post_id
93
+ * @param array $field
94
+ *
95
+ * @return string
96
+ */
97
+ static function value( $new, $old, $post_id, $field )
98
+ {
99
+ foreach ( $new as &$arr )
100
  {
101
+ if ( empty( $arr[0] ) && empty( $arr[1] ) )
102
+ $arr = false;
 
 
 
 
 
 
 
103
  }
104
+ $new = array_filter( $new );
105
+ return $new;
106
+ }
107
 
108
+ /**
109
+ * Normalize parameters for field
110
+ *
111
+ * @param array $field
112
+ * @return array
113
+ */
114
+ static function normalize( $field )
115
+ {
116
+ $field = parent::normalize( $field );
117
+ $field['clone'] = true;
118
+ $field['multiple'] = true;
119
+ return $field;
120
+ }
121
 
122
+ /**
123
+ * Output the field value
124
+ * Display unordered list of key - value pairs
125
+ *
126
+ * @use self::get_value()
127
+ * @see rwmb_the_field()
128
+ *
129
+ * @param array $field Field parameters
130
+ * @param array $args Additional arguments. Rarely used. See specific fields for details
131
+ * @param int|null $post_id Post ID. null for current post. Optional.
132
+ *
133
+ * @return string HTML output of the field
134
+ */
135
+ static function the_value( $field, $args = array(), $post_id = null )
136
+ {
137
+ $value = self::get_value( $field, $args, $post_id );
138
+ if ( ! is_array( $value ) )
139
+ return '';
140
 
141
+ $output = '<ul>';
142
+ foreach ( $value as $subvalue )
 
 
 
 
 
 
 
 
 
 
 
 
143
  {
144
+ $output .= sprintf( '<li><label>%s</label>: %s</li>', $subvalue[0], $subvalue[1] );
 
 
 
 
 
 
 
 
 
 
145
  }
146
+ $output .= '</ul>';
147
+ return $output;
148
  }
149
  }
inc/fields/map.php CHANGED
@@ -1,164 +1,162 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Map_Field' ) )
6
  {
7
- class RWMB_Map_Field extends RWMB_Field
 
 
 
 
 
8
  {
9
  /**
10
- * Enqueue scripts and styles
11
- *
12
- * @return void
13
  */
14
- static function admin_enqueue_scripts()
15
- {
16
- /**
17
- * Allows developers load more libraries via a filter.
18
- * @link https://developers.google.com/maps/documentation/javascript/libraries
19
- */
20
- $google_maps_url = apply_filters( 'rwmb_google_maps_url', 'https://maps.google.com/maps/api/js?sensor=false' );
21
- wp_register_script( 'google-maps', esc_url_raw( $google_maps_url ), array(), '', true );
22
- wp_enqueue_style( 'rwmb-map', RWMB_CSS_URL . 'map.css' );
23
- wp_enqueue_script( 'rwmb-map', RWMB_JS_URL . 'map.js', array( 'jquery-ui-autocomplete', 'google-maps' ), RWMB_VER, true );
24
- }
25
 
26
- /**
27
- * Get field HTML
28
- *
29
- * @param mixed $meta
30
- * @param array $field
31
- *
32
- * @return string
33
- */
34
- static function html( $meta, $field )
35
- {
36
- $html = '<div class="rwmb-map-field">';
 
 
 
 
 
 
 
 
37
 
 
 
38
  $html .= sprintf(
39
- '<div class="rwmb-map-canvas" data-default-loc="%s"></div>
40
- <input type="hidden" name="%s" class="rwmb-map-coordinate" value="%s">',
41
- esc_attr( $field['std'] ),
42
- esc_attr( $field['field_name'] ),
43
- esc_attr( $meta )
44
  );
 
45
 
46
- if ( $address = $field['address_field'] )
47
- {
48
- $html .= sprintf(
49
- '<button class="button rwmb-map-goto-address-button" value="%s">%s</button>',
50
- is_array( $address ) ? implode( ',', $address ) : $address,
51
- __( 'Find Address', 'meta-box' )
52
- );
53
- }
54
 
55
- $html .= '</div>';
 
56
 
57
- return $html;
58
- }
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
- /**
61
- * Normalize parameters for field
62
- *
63
- * @param array $field
64
- *
65
- * @return array
66
- */
67
- static function normalize_field( $field )
68
- {
69
- $field = wp_parse_args( $field, array(
70
- 'std' => '',
71
- 'address_field' => '',
72
- ) );
73
 
74
- return $field;
75
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
- /**
78
- * Get the field value
79
- * The difference between this function and 'meta' function is 'meta' function always returns the escaped value
80
- * of the field saved in the database, while this function returns more meaningful value of the field
81
- *
82
- * @param array $field Field parameters
83
- * @param array $args Not used for this field
84
- * @param int|null $post_id Post ID. null for current post. Optional.
85
- *
86
- * @return mixed Array(latitude, longitude, zoom)
87
- */
88
- static function get_value( $field, $args = array(), $post_id = null )
 
 
 
 
 
 
89
  {
90
- $value = parent::get_value( $field, $args, $post_id );
91
- list( $latitude, $longitude, $zoom ) = explode( ',', $value . ',,' );
92
- return compact( 'latitude', 'longitude', 'zoom' );
93
  }
94
 
95
  /**
96
- * Output the field value
97
- * Display Google maps
98
- *
99
- * @param array $field Field parameters
100
- * @param array $args Additional arguments. Not used for these fields.
101
- * @param int|null $post_id Post ID. null for current post. Optional.
102
- *
103
- * @return mixed Field value
104
  */
105
- static function the_value( $field, $args = array(), $post_id = null )
106
- {
107
- $value = self::get_value( $field, $args, $post_id );
108
- if ( ! $value['latitude'] || ! $value['longitude'] )
109
- {
110
- return '';
111
- }
112
- if ( ! $value['zoom'] )
113
- {
114
- $value['zoom'] = 14;
115
- }
116
-
117
- /**
118
- * Enqueue scripts
119
- * Note: We still can enqueue script which outputs in the footer
120
- */
121
- /**
122
- * Allows developers load more libraries via a filter.
123
- * @link https://developers.google.com/maps/documentation/javascript/libraries
124
- */
125
- $google_maps_url = apply_filters( 'rwmb_google_maps_url', 'https://maps.google.com/maps/api/js?sensor=false' );
126
- wp_register_script( 'google-maps', esc_url_raw( $google_maps_url ), array(), '', true );
127
- wp_enqueue_script( 'rwmb-map-frontend', RWMB_JS_URL . 'map-frontend.js', array( 'google-maps' ), '', true );
128
 
129
- // Map parameters
130
- $args = wp_parse_args( $args, array(
131
- 'latitude' => $value['latitude'],
132
- 'longitude' => $value['longitude'],
133
- 'width' => '100%',
134
- 'height' => '480px',
135
- 'marker' => true, // Display marker?
136
- 'marker_title' => '', // Marker title, when hover
137
- 'info_window' => '', // Content of info window (when click on marker). HTML allowed
138
- 'js_options' => array(),
139
- ) );
140
 
141
- /**
142
- * Google Maps options
143
- * Option name is the same as specified in Google Maps documentation
144
- * This array will be convert to Javascript Object and pass as map options
145
- * @link https://developers.google.com/maps/documentation/javascript/reference
146
- */
147
- $args['js_options'] = wp_parse_args( $args['js_options'], array(
148
- // Default to 'zoom' level set in admin, but can be overwritten
149
- 'zoom' => $value['zoom'],
150
 
151
- // Map type, see https://developers.google.com/maps/documentation/javascript/reference#MapTypeId
152
- 'mapTypeId' => 'ROADMAP',
153
- ) );
154
 
155
- $output = sprintf(
156
- '<div class="rwmb-map-canvas" data-map_options="%s" style="width:%s;height:%s"></div>',
157
- esc_attr( wp_json_encode( $args ) ),
158
- esc_attr( $args['width'] ),
159
- esc_attr( $args['height'] )
160
- );
161
- return $output;
162
- }
163
  }
164
  }
1
  <?php
2
+ /**
3
+ * Map field class.
4
+ */
5
+ class RWMB_Map_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ *
10
+ * @return void
11
+ */
12
+ static function admin_enqueue_scripts()
13
  {
14
  /**
15
+ * Allows developers load more libraries via a filter.
16
+ * @link https://developers.google.com/maps/documentation/javascript/libraries
 
17
  */
18
+ $google_maps_url = apply_filters( 'rwmb_google_maps_url', 'https://maps.google.com/maps/api/js?sensor=false' );
19
+ wp_register_script( 'google-maps', esc_url_raw( $google_maps_url ), array(), '', true );
20
+ wp_enqueue_style( 'rwmb-map', RWMB_CSS_URL . 'map.css' );
21
+ wp_enqueue_script( 'rwmb-map', RWMB_JS_URL . 'map.js', array( 'jquery-ui-autocomplete', 'google-maps' ), RWMB_VER, true );
22
+ }
 
 
 
 
 
 
23
 
24
+ /**
25
+ * Get field HTML
26
+ *
27
+ * @param mixed $meta
28
+ * @param array $field
29
+ *
30
+ * @return string
31
+ */
32
+ static function html( $meta, $field )
33
+ {
34
+ $html = '<div class="rwmb-map-field">';
35
+
36
+ $html .= sprintf(
37
+ '<div class="rwmb-map-canvas" data-default-loc="%s"></div>
38
+ <input type="hidden" name="%s" class="rwmb-map-coordinate" value="%s">',
39
+ esc_attr( $field['std'] ),
40
+ esc_attr( $field['field_name'] ),
41
+ esc_attr( $meta )
42
+ );
43
 
44
+ if ( $address = $field['address_field'] )
45
+ {
46
  $html .= sprintf(
47
+ '<button class="button rwmb-map-goto-address-button" value="%s">%s</button>',
48
+ is_array( $address ) ? implode( ',', $address ) : $address,
49
+ __( 'Find Address', 'meta-box' )
 
 
50
  );
51
+ }
52
 
53
+ $html .= '</div>';
 
 
 
 
 
 
 
54
 
55
+ return $html;
56
+ }
57
 
58
+ /**
59
+ * Normalize parameters for field
60
+ *
61
+ * @param array $field
62
+ *
63
+ * @return array
64
+ */
65
+ static function normalize( $field )
66
+ {
67
+ $field = parent::normalize( $field );
68
+ $field = wp_parse_args( $field, array(
69
+ 'std' => '',
70
+ 'address_field' => '',
71
+ ) );
72
 
73
+ return $field;
74
+ }
 
 
 
 
 
 
 
 
 
 
 
75
 
76
+ /**
77
+ * Get the field value
78
+ * The difference between this function and 'meta' function is 'meta' function always returns the escaped value
79
+ * of the field saved in the database, while this function returns more meaningful value of the field
80
+ *
81
+ * @param array $field Field parameters
82
+ * @param array $args Not used for this field
83
+ * @param int|null $post_id Post ID. null for current post. Optional.
84
+ *
85
+ * @return mixed Array(latitude, longitude, zoom)
86
+ */
87
+ static function get_value( $field, $args = array(), $post_id = null )
88
+ {
89
+ $value = parent::get_value( $field, $args, $post_id );
90
+ list( $latitude, $longitude, $zoom ) = explode( ',', $value . ',,' );
91
+ return compact( 'latitude', 'longitude', 'zoom' );
92
+ }
93
 
94
+ /**
95
+ * Output the field value
96
+ * Display Google maps
97
+ *
98
+ * @param array $field Field parameters
99
+ * @param array $args Additional arguments. Not used for these fields.
100
+ * @param int|null $post_id Post ID. null for current post. Optional.
101
+ *
102
+ * @return mixed Field value
103
+ */
104
+ static function the_value( $field, $args = array(), $post_id = null )
105
+ {
106
+ $value = self::get_value( $field, $args, $post_id );
107
+ if ( ! $value['latitude'] || ! $value['longitude'] )
108
+ {
109
+ return '';
110
+ }
111
+ if ( ! $value['zoom'] )
112
  {
113
+ $value['zoom'] = 14;
 
 
114
  }
115
 
116
  /**
117
+ * Enqueue scripts
118
+ * Note: We still can enqueue script which outputs in the footer
 
 
 
 
 
 
119
  */
120
+ /**
121
+ * Allows developers load more libraries via a filter.
122
+ * @link https://developers.google.com/maps/documentation/javascript/libraries
123
+ */
124
+ $google_maps_url = apply_filters( 'rwmb_google_maps_url', 'https://maps.google.com/maps/api/js?sensor=false' );
125
+ wp_register_script( 'google-maps', esc_url_raw( $google_maps_url ), array(), '', true );
126
+ wp_enqueue_script( 'rwmb-map-frontend', RWMB_JS_URL . 'map-frontend.js', array( 'google-maps' ), '', true );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
+ // Map parameters
129
+ $args = wp_parse_args( $args, array(
130
+ 'latitude' => $value['latitude'],
131
+ 'longitude' => $value['longitude'],
132
+ 'width' => '100%',
133
+ 'height' => '480px',
134
+ 'marker' => true, // Display marker?
135
+ 'marker_title' => '', // Marker title, when hover
136
+ 'info_window' => '', // Content of info window (when click on marker). HTML allowed
137
+ 'js_options' => array(),
138
+ ) );
139
 
140
+ /**
141
+ * Google Maps options
142
+ * Option name is the same as specified in Google Maps documentation
143
+ * This array will be convert to Javascript Object and pass as map options
144
+ * @link https://developers.google.com/maps/documentation/javascript/reference
145
+ */
146
+ $args['js_options'] = wp_parse_args( $args['js_options'], array(
147
+ // Default to 'zoom' level set in admin, but can be overwritten
148
+ 'zoom' => $value['zoom'],
149
 
150
+ // Map type, see https://developers.google.com/maps/documentation/javascript/reference#MapTypeId
151
+ 'mapTypeId' => 'ROADMAP',
152
+ ) );
153
 
154
+ $output = sprintf(
155
+ '<div class="rwmb-map-canvas" data-map_options="%s" style="width:%s;height:%s"></div>',
156
+ esc_attr( wp_json_encode( $args ) ),
157
+ esc_attr( $args['width'] ),
158
+ esc_attr( $args['height'] )
159
+ );
160
+ return $output;
 
161
  }
162
  }
inc/fields/media.php CHANGED
@@ -1,255 +1,211 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Media_Field' ) )
6
  {
7
- class RWMB_Media_Field extends RWMB_Field
 
 
 
 
 
8
  {
9
- /**
10
- * Enqueue scripts and styles
11
- *
12
- * @return void
13
- */
14
- static function admin_enqueue_scripts()
15
- {
16
- wp_enqueue_media();
17
- wp_enqueue_style( 'rwmb-media', RWMB_CSS_URL . 'media.css', array(), RWMB_VER );
18
- wp_enqueue_script( 'rwmb-media', RWMB_JS_URL . 'media.js', array( 'jquery-ui-sortable', 'underscore', 'backbone' ), RWMB_VER, true );
19
- }
20
-
21
- /**
22
- * Add actions
23
- *
24
- * @return void
25
- */
26
- static function add_actions()
27
- {
28
- // Print attachment templates
29
- add_action( 'print_media_templates', array( __CLASS__, 'print_templates' ) );
30
- }
31
-
32
- /**
33
- * Get field HTML
34
- *
35
- * @param mixed $meta
36
- * @param array $field
37
- *
38
- * @return string
39
- */
40
- static function html( $meta, $field )
41
- {
42
- $meta = (array) $meta;
43
- $meta = implode( ',', $meta );
44
- $html = sprintf(
45
- '<input type="hidden" name="%s" value="%s" class="rwmb-media">
46
- <div class="rwmb-media-view" data-mime-type="%s" data-max-files="%s" data-force-delete="%s"></div>',
47
- $field['field_name'],
48
- esc_attr( $meta ),
49
- $field['mime_type'],
50
- $field['max_file_uploads'],
51
- $field['force_delete'] ? 'true' : 'false'
52
- );
53
-
54
- return $html;
55
- }
56
-
57
- /**
58
- * Normalize parameters for field
59
- *
60
- * @param array $field
61
- *
62
- * @return array
63
- */
64
- static function normalize_field( $field )
65
- {
66
- $field = wp_parse_args( $field, array(
67
- 'std' => array(),
68
- 'mime_type' => '',
69
- 'max_file_uploads' => 0,
70
- 'force_delete' => false,
71
- ) );
72
-
73
- $field['multiple'] = false;
74
 
75
- return $field;
76
- }
 
 
 
 
 
 
 
 
77
 
78
- /**
79
- * Get meta value
80
- *
81
- * @param int $post_id
82
- * @param bool $saved
83
- * @param array $field
84
- *
85
- * @return mixed
86
- */
87
- static function meta( $post_id, $saved, $field )
88
- {
89
- $field['multiple'] = true;
90
- return parent::meta( $post_id, $saved, $field );
91
- }
 
 
 
 
 
 
 
 
 
 
 
92
 
93
- /**
94
- * Get field value
95
- * It's the combination of new (uploaded) images and saved images
96
- *
97
- * @param array $new
98
- * @param array $old
99
- * @param int $post_id
100
- * @param array $field
101
- *
102
- * @return array|mixed
103
- */
104
- static function value( $new, $old, $post_id, $field )
105
- {
106
- if ( $field['clone'] )
107
- {
108
- foreach ( $new as &$value )
109
- {
110
- $value = wp_parse_id_list( $value );
111
- }
112
- }
113
- else
114
- {
115
- $new = wp_parse_id_list( $new );
116
- }
117
- return $new;
118
- }
119
 
120
- /**
121
- * Save meta value
122
- *
123
- * @param $new
124
- * @param $old
125
- * @param $post_id
126
- * @param $field
127
- */
128
- static function save( $new, $old, $post_id, $field )
129
- {
130
- $name = $field['id'];
131
 
132
- delete_post_meta( $post_id, $name );
 
133
 
134
- if ( '' === $new || array() === $new )
135
- {
136
- return;
137
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
- // If field is cloneable, value is saved as a single entry in the database
140
- if ( $field['clone'] )
141
- {
142
- $new = (array) $new;
143
- $new = array_filter( $new );
144
- update_post_meta( $post_id, $name, $new );
145
- return;
146
- }
147
- else
148
- {
149
- foreach ( $new as $new_value )
150
- {
151
- add_post_meta( $post_id, $name, $new_value, false );
152
- }
153
- return;
154
- }
155
- }
156
 
157
- /**
158
- * Template for media item
159
- * @return void
160
- */
161
- static function print_templates()
162
- {
163
- $i18n_add = apply_filters( 'rwmb_media_add_string', _x( '+ Add Media', 'media', 'meta-box' ) );
164
- $i18n_remove = apply_filters( 'rwmb_media_remove_string', _x( 'Remove', 'media', 'meta-box' ) );
165
- $i18n_edit = apply_filters( 'rwmb_media_edit_string', _x( 'Edit', 'media', 'meta-box' ) );
166
- $i18n_view = apply_filters( 'rwmb_media_view_string', _x( 'View', 'media', 'meta-box' ) );
167
- $i18n_single_files = apply_filters( 'rwmb_media_single_files_string', _x( ' file', 'media', 'meta-box' ) );
168
- $i18n_multiple_files = apply_filters( 'rwmb_media_multiple_files_string', _x( ' files', 'media', 'meta-box' ) );
169
- $i18n_title = _x( 'No Title', 'media', 'meta-box' );
170
- ?>
171
- <script id="tmpl-rwmb-media-item" type="text/html">
172
- <div class="rwmb-media-preview">
173
- <div class="rwmb-media-content">
174
- <div class="centered">
175
- <# if ( 'image' === data.type && data.sizes ) { #>
176
- <# if ( data.sizes.thumbnail ) { #>
177
- <img src="{{{ data.sizes.thumbnail.url }}}">
178
- <# } else { #>
179
- <img src="{{{ data.sizes.full.url }}}">
180
- <# } #>
181
  <# } else { #>
182
- <# if ( data.image && data.image.src && data.image.src !== data.icon ) { #>
183
- <img src="{{ data.image.src }}" />
184
- <# } else { #>
185
- <img src="{{ data.icon }}" />
186
- <# } #>
187
- <# } #>
188
- </div>
189
- </div>
190
- </div>
191
- <div class="rwmb-media-info">
192
- <h4>
193
- <a href="{{{ data.url }}}" target="_blank" title="<?php echo esc_attr( $i18n_view ); ?>">
194
- <# if( data.title ) { #> {{{ data.title }}}
195
- <# } else { #> <?php echo esc_attr( $i18n_title ); ?>
196
  <# } #>
197
- </a>
198
- </h4>
199
- <p>{{{ data.mime }}}</p>
200
- <p>
201
- <a class="rwmb-edit-media" title="<?php echo esc_attr( $i18n_edit ); ?>" href="{{{ data.editLink }}}" target="_blank">
202
- <span class="dashicons dashicons-edit"></span><?php echo esc_attr( $i18n_edit ); ?>
203
- </a>
204
- <a href="#" class="rwmb-remove-media" title="<?php echo esc_attr( $i18n_remove ); ?>">
205
- <span class="dashicons dashicons-no-alt"></span><?php echo esc_attr( $i18n_remove ); ?>
206
- </a>
207
- </p>
208
- </div>
209
- </script>
210
-
211
- <script id="tmpl-rwmb-image-item" type="text/html">
212
- <div class="rwmb-media-preview">
213
- <div class="rwmb-media-content">
214
- <div class="centered">
215
- <# if ( 'image' === data.type && data.sizes ) { #>
216
- <# if ( data.sizes.thumbnail ) { #>
217
- <img src="{{{ data.sizes.thumbnail.url }}}">
218
- <# } else { #>
219
- <img src="{{{ data.sizes.full.url }}}">
220
- <# } #>
221
  <# } else { #>
222
- <# if ( data.image && data.image.src && data.image.src !== data.icon ) { #>
223
- <img src="{{ data.image.src }}" />
224
- <# } else { #>
225
- <img src="{{ data.icon }}" />
226
- <# } #>
227
  <# } #>
228
- </div>
229
  </div>
230
  </div>
231
- <div class="rwmb-overlay"></div>
232
- <div class="rwmb-media-bar">
 
 
 
 
 
 
 
 
 
233
  <a class="rwmb-edit-media" title="<?php echo esc_attr( $i18n_edit ); ?>" href="{{{ data.editLink }}}" target="_blank">
234
- <span class="dashicons dashicons-edit"></span>
235
  </a>
236
  <a href="#" class="rwmb-remove-media" title="<?php echo esc_attr( $i18n_remove ); ?>">
237
- <span class="dashicons dashicons-no-alt"></span>
238
  </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  </div>
240
- </script>
241
-
242
- <script id="tmpl-rwmb-add-media" type="text/html">
243
- <?php echo $i18n_add; ?>
244
- </script>
245
-
246
- <script id="tmpl-rwmb-media-status" type="text/html">
247
- <# if ( data.maxFiles > 0 ) { #>
248
- {{{ data.items }}}/{{{ data.maxFiles }}}
249
- <# if ( data.items > 1 || data.items < 1 ) { #> <?php echo $i18n_multiple_files; ?> <# } else {#> <?php echo $i18n_single_files; ?> <# } #>
250
- <# } #>
251
- </script>
252
- <?php
253
- }
 
 
 
 
 
 
 
 
 
254
  }
255
  }
1
  <?php
2
+ /**
3
+ * Media field class which users WordPress media popup to upload and select files.
4
+ */
5
+ class RWMB_Media_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ *
10
+ * @return void
11
+ */
12
+ static function admin_enqueue_scripts()
13
  {
14
+ wp_enqueue_media();
15
+ wp_enqueue_style( 'rwmb-media', RWMB_CSS_URL . 'media.css', array(), RWMB_VER );
16
+ wp_enqueue_script( 'rwmb-media', RWMB_JS_URL . 'media.js', array( 'jquery-ui-sortable', 'underscore', 'backbone' ), RWMB_VER, true );
17
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
+ /**
20
+ * Add actions
21
+ *
22
+ * @return void
23
+ */
24
+ static function add_actions()
25
+ {
26
+ // Print attachment templates
27
+ add_action( 'print_media_templates', array( __CLASS__, 'print_templates' ) );
28
+ }
29
 
30
+ /**
31
+ * Get field HTML
32
+ *
33
+ * @param mixed $meta
34
+ * @param array $field
35
+ *
36
+ * @return string
37
+ */
38
+ static function html( $meta, $field )
39
+ {
40
+ $meta = (array) $meta;
41
+ $meta = implode( ',', $meta );
42
+ $attributes = self::get_attributes( $field, $meta );
43
+
44
+ $html = sprintf(
45
+ '<input %s>
46
+ <div class="rwmb-media-view" data-mime-type="%s" data-max-files="%s" data-force-delete="%s"></div>',
47
+ self::render_attributes( $attributes ),
48
+ $field['mime_type'],
49
+ $field['max_file_uploads'],
50
+ $field['force_delete'] ? 'true' : 'false'
51
+ );
52
+
53
+ return $html;
54
+ }
55
 
56
+ /**
57
+ * Normalize parameters for field
58
+ *
59
+ * @param array $field
60
+ *
61
+ * @return array
62
+ */
63
+ static function normalize( $field )
64
+ {
65
+ $field = parent::normalize( $field );
66
+ $field = wp_parse_args( $field, array(
67
+ 'std' => array(),
68
+ 'mime_type' => '',
69
+ 'max_file_uploads' => 0,
70
+ 'force_delete' => false,
71
+ ) );
 
 
 
 
 
 
 
 
 
 
72
 
73
+ $field['multiple'] = true;
 
 
 
 
 
 
 
 
 
 
74
 
75
+ return $field;
76
+ }
77
 
78
+ /**
79
+ * Get the attributes for a field
80
+ *
81
+ * @param array $field
82
+ * @param mixed $value
83
+ *
84
+ * @return array
85
+ */
86
+ static function get_attributes( $field, $value = null )
87
+ {
88
+ $attributes = parent::get_attributes( $field, $value );
89
+ $attributes['type'] = 'hidden';
90
+ $attributes['name'] .= ! $field['clone'] && $field['multiple'] ? '[]' : '';
91
+ $attributes['disabled'] = true;
92
+ $attributes['id'] = false;
93
+ $attributes['value'] = $value;
94
+
95
+ return $attributes;
96
+ }
97
 
98
+ /**
99
+ * Save meta value
100
+ *
101
+ * @param $new
102
+ * @param $old
103
+ * @param $post_id
104
+ * @param $field
105
+ */
106
+ static function save( $new, $old, $post_id, $field )
107
+ {
108
+ delete_post_meta( $post_id, $field['id'] );
109
+ parent::save( $new, array(), $post_id, $field );
110
+ }
 
 
 
 
111
 
112
+ /**
113
+ * Template for media item
114
+ * @return void
115
+ */
116
+ static function print_templates()
117
+ {
118
+ $i18n_add = apply_filters( 'rwmb_media_add_string', _x( '+ Add Media', 'media', 'meta-box' ) );
119
+ $i18n_remove = apply_filters( 'rwmb_media_remove_string', _x( 'Remove', 'media', 'meta-box' ) );
120
+ $i18n_edit = apply_filters( 'rwmb_media_edit_string', _x( 'Edit', 'media', 'meta-box' ) );
121
+ $i18n_view = apply_filters( 'rwmb_media_view_string', _x( 'View', 'media', 'meta-box' ) );
122
+ $i18n_single_files = apply_filters( 'rwmb_media_single_files_string', _x( ' file', 'media', 'meta-box' ) );
123
+ $i18n_multiple_files = apply_filters( 'rwmb_media_multiple_files_string', _x( ' files', 'media', 'meta-box' ) );
124
+ $i18n_title = _x( 'No Title', 'media', 'meta-box' );
125
+ ?>
126
+ <script id="tmpl-rwmb-media-item" type="text/html">
127
+ <input type="hidden" name="{{{ data.fieldName }}}" value="{{{ data.id }}}" class="rwmb-media-input">
128
+ <div class="rwmb-media-preview">
129
+ <div class="rwmb-media-content">
130
+ <div class="centered">
131
+ <# if ( 'image' === data.type && data.sizes ) { #>
132
+ <# if ( data.sizes.thumbnail ) { #>
133
+ <img src="{{{ data.sizes.thumbnail.url }}}">
 
 
134
  <# } else { #>
135
+ <img src="{{{ data.sizes.full.url }}}">
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  <# } #>
137
+ <# } else { #>
138
+ <# if ( data.image && data.image.src && data.image.src !== data.icon ) { #>
139
+ <img src="{{ data.image.src }}" />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  <# } else { #>
141
+ <img src="{{ data.icon }}" />
 
 
 
 
142
  <# } #>
143
+ <# } #>
144
  </div>
145
  </div>
146
+ </div>
147
+ <div class="rwmb-media-info">
148
+ <h4>
149
+ <a href="{{{ data.url }}}" target="_blank" title="<?php echo esc_attr( $i18n_view ); ?>">
150
+ <# if( data.title ) { #> {{{ data.title }}}
151
+ <# } else { #> <?php echo esc_attr( $i18n_title ); ?>
152
+ <# } #>
153
+ </a>
154
+ </h4>
155
+ <p>{{{ data.mime }}}</p>
156
+ <p>
157
  <a class="rwmb-edit-media" title="<?php echo esc_attr( $i18n_edit ); ?>" href="{{{ data.editLink }}}" target="_blank">
158
+ <span class="dashicons dashicons-edit"></span><?php echo esc_attr( $i18n_edit ); ?>
159
  </a>
160
  <a href="#" class="rwmb-remove-media" title="<?php echo esc_attr( $i18n_remove ); ?>">
161
+ <span class="dashicons dashicons-no-alt"></span><?php echo esc_attr( $i18n_remove ); ?>
162
  </a>
163
+ </p>
164
+ </div>
165
+ </script>
166
+
167
+ <script id="tmpl-rwmb-image-item" type="text/html">
168
+ <input type="hidden" name="{{{ data.fieldName }}}" value="{{{ data.id }}}" class="rwmb-media-input">
169
+ <div class="rwmb-media-preview">
170
+ <div class="rwmb-media-content">
171
+ <div class="centered">
172
+ <# if ( 'image' === data.type && data.sizes ) { #>
173
+ <# if ( data.sizes.thumbnail ) { #>
174
+ <img src="{{{ data.sizes.thumbnail.url }}}">
175
+ <# } else { #>
176
+ <img src="{{{ data.sizes.full.url }}}">
177
+ <# } #>
178
+ <# } else { #>
179
+ <# if ( data.image && data.image.src && data.image.src !== data.icon ) { #>
180
+ <img src="{{ data.image.src }}" />
181
+ <# } else { #>
182
+ <img src="{{ data.icon }}" />
183
+ <# } #>
184
+ <# } #>
185
+ </div>
186
  </div>
187
+ </div>
188
+ <div class="rwmb-overlay"></div>
189
+ <div class="rwmb-media-bar">
190
+ <a class="rwmb-edit-media" title="<?php echo esc_attr( $i18n_edit ); ?>" href="{{{ data.editLink }}}" target="_blank">
191
+ <span class="dashicons dashicons-edit"></span>
192
+ </a>
193
+ <a href="#" class="rwmb-remove-media" title="<?php echo esc_attr( $i18n_remove ); ?>">
194
+ <span class="dashicons dashicons-no-alt"></span>
195
+ </a>
196
+ </div>
197
+ </script>
198
+
199
+ <script id="tmpl-rwmb-add-media" type="text/html">
200
+ <?php echo $i18n_add; ?>
201
+ </script>
202
+
203
+ <script id="tmpl-rwmb-media-status" type="text/html">
204
+ <# if ( data.maxFiles > 0 ) { #>
205
+ {{{ data.items }}}/{{{ data.maxFiles }}}
206
+ <# if ( data.items > 1 || data.items < 1 ) { #> <?php echo $i18n_multiple_files; ?> <# } else {#> <?php echo $i18n_single_files; ?> <# } #>
207
+ <# } #>
208
+ </script>
209
+ <?php
210
  }
211
  }
inc/fields/multiple-values.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This class implements common methods used in fields which have multiple values
4
+ * like checkbox list, autocomplete, etc.
5
+ *
6
+ * The difference when handling actions for these fields are the way they get/set
7
+ * meta value. Briefly:
8
+ * - If field is cloneable, value is saved as a single entry in the database
9
+ * - Otherwise value is saved as multiple entries
10
+ */
11
+ abstract class RWMB_Multiple_Values_Field extends RWMB_Field
12
+ {
13
+ /**
14
+ * Normalize parameters for field
15
+ *
16
+ * @param array $field
17
+ *
18
+ * @return array
19
+ */
20
+ static function normalize( $field )
21
+ {
22
+ $field = parent::normalize( $field );
23
+ $field['multiple'] = true;
24
+ $field['field_name'] = $field['id'];
25
+ if ( ! $field['clone'] )
26
+ $field['field_name'] .= '[]';
27
+
28
+ return $field;
29
+ }
30
+
31
+ /**
32
+ * Output the field value
33
+ * Display option name instead of option value
34
+ *
35
+ * @param array $field Field parameters
36
+ * @param array $args Additional arguments. Not used for these fields.
37
+ * @param int|null $post_id Post ID. null for current post. Optional.
38
+ *
39
+ * @return mixed Field value
40
+ */
41
+ static function the_value( $field, $args = array(), $post_id = null )
42
+ {
43
+ $value = self::get_value( $field, $args, $post_id );
44
+ if ( ! $value )
45
+ return '';
46
+
47
+ $output = '<ul>';
48
+ if ( $field['clone'] )
49
+ {
50
+ foreach ( $value as $subvalue )
51
+ {
52
+ $output .= '<li>';
53
+ $output .= '<ul>';
54
+ foreach ( $subvalue as $option )
55
+ {
56
+ $output .= '<li>' . $field['options'][$option] . '</li>';
57
+ }
58
+ $output .= '</ul>';
59
+ $output .= '</li>';
60
+ }
61
+ }
62
+ else
63
+ {
64
+ foreach ( $value as $option )
65
+ {
66
+ $output .= '<li>' . $field['options'][$option] . '</li>';
67
+ }
68
+ }
69
+ $output .= '</ul>';
70
+
71
+ return $output;
72
+ }
73
+ }
inc/fields/number.php CHANGED
@@ -1,40 +1,47 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "input" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'input.php';
7
-
8
- if ( ! class_exists( 'RWMB_Number_Field' ) )
9
  {
10
- class RWMB_Number_Field extends RWMB_Input_Field
 
 
 
 
 
 
 
11
  {
12
- /**
13
- * Normalize parameters for field
14
- *
15
- * @param array $field
16
- *
17
- * @return array
18
- */
19
- static function normalize_field( $field )
20
- {
21
- $field = parent::normalize_field( $field );
22
 
23
- $field = wp_parse_args( $field, array(
24
- 'step' => 1,
25
- 'min' => 0,
26
- 'max' => false,
27
- ) );
28
 
29
- $field['attributes'] = wp_parse_args( $field['attributes'], array(
30
- 'step' => $field['step'],
31
- 'max' => $field['max'],
32
- 'min' => $field['min'],
33
- ) );
34
 
35
- $field['attributes']['type'] = 'number';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- return $field;
38
- }
39
  }
40
  }
1
  <?php
2
+ /**
3
+ * Number field class.
4
+ */
5
+ class RWMB_Number_Field extends RWMB_Input_Field
 
 
 
6
  {
7
+ /**
8
+ * Normalize parameters for field
9
+ *
10
+ * @param array $field
11
+ *
12
+ * @return array
13
+ */
14
+ static function normalize( $field )
15
  {
16
+ $field = parent::normalize( $field );
 
 
 
 
 
 
 
 
 
17
 
18
+ $field = wp_parse_args( $field, array(
19
+ 'step' => 1,
20
+ 'min' => 0,
21
+ 'max' => false,
22
+ ) );
23
 
24
+ return $field;
25
+ }
 
 
 
26
 
27
+ /**
28
+ * Get the attributes for a field
29
+ *
30
+ * @param array $field
31
+ * @param mixed $value
32
+ *
33
+ * @return array
34
+ */
35
+ static function get_attributes( $field, $value = null )
36
+ {
37
+ $attributes = parent::get_attributes( $field, $value );
38
+ $attributes = wp_parse_args( $attributes, array(
39
+ 'step' => $field['step'],
40
+ 'max' => $field['max'],
41
+ 'min' => $field['min'],
42
+ ) );
43
+ $attributes['type'] = 'number';
44
 
45
+ return $attributes;
 
46
  }
47
  }
inc/fields/object-choice.php ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Abstract field to select an object: post, user, taxonomy, etc.
4
+ */
5
+ abstract class RWMB_Object_Choice_Field extends RWMB_Field
6
+ {
7
+ /**
8
+ * Get field HTML
9
+ *
10
+ * @param mixed $meta
11
+ * @param array $field
12
+ *
13
+ * @return string
14
+ */
15
+ static function html( $meta, $field )
16
+ {
17
+ $field_class = RW_Meta_Box::get_class_name( $field );
18
+ $meta = (array) $meta;
19
+ $options = call_user_func( array( $field_class, 'get_options' ), $field );
20
+ $output = '';
21
+ switch ( $field['field_type'] )
22
+ {
23
+ case 'checkbox_list':
24
+ case 'radio_list':
25
+ $output .= call_user_func( array( $field_class, 'render_list' ), $options, $meta, $field );
26
+ break;
27
+ case 'select_tree':
28
+ $output .= call_user_func( array( $field_class, 'render_select_tree' ), $options, $meta, $field );
29
+ break;
30
+ case 'select_advanced':
31
+ case 'select':
32
+ default:
33
+ $output .= call_user_func( array( $field_class, 'render_select' ), $options, $meta, $field );
34
+ break;
35
+ }
36
+ return $output;
37
+ }
38
+
39
+ /**
40
+ * Normalize parameters for field
41
+ *
42
+ * @param array $field
43
+ *
44
+ * @return array
45
+ */
46
+ static function normalize( $field )
47
+ {
48
+ $field = parent::normalize( $field );
49
+ $field = wp_parse_args( $field, array(
50
+ 'flatten' => true,
51
+ 'query_args' => array(),
52
+ 'field_type' => 'select',
53
+ ) );
54
+
55
+ if ( 'checkbox_tree' === $field['field_type'] )
56
+ {
57
+ $field['field_type'] = 'checkbox_list';
58
+ $field['flatten'] = false;
59
+ }
60
+
61
+ switch ( $field['field_type'] )
62
+ {
63
+ case 'checkbox_list':
64
+ case 'radio_list':
65
+ $field = wp_parse_args( $field, array(
66
+ 'collapse' => true
67
+ ) );
68
+ $field['flatten'] = 'radio_list' === $field['field_type'] ? true : $field['flatten'];
69
+ $field['multiple'] = 'radio_list' === $field['field_type'] ? false : true;
70
+ $field = RWMB_Input_Field::normalize( $field );
71
+ break;
72
+ case 'select_advanced':
73
+ $field = RWMB_Select_Advanced_Field::normalize( $field );
74
+ $field['flatten'] = true;
75
+ break;
76
+ case 'select_tree':
77
+ $field = RWMB_Select_Field::normalize( $field );
78
+ $field['multiple'] = true;
79
+ break;
80
+ case 'select':
81
+ default:
82
+ $field = RWMB_Select_Field::normalize( $field );
83
+ break;
84
+ }
85
+
86
+ return $field;
87
+ }
88
+
89
+ /**
90
+ * Get the attributes for a field
91
+ *
92
+ * @param array $field
93
+ * @param mixed $value
94
+ *
95
+ * @return array
96
+ */
97
+ static function get_attributes( $field, $value = null )
98
+ {
99
+ switch ( $field['field_type'] )
100
+ {
101
+ case 'checkbox_list':
102
+ case 'radio_list':
103
+ $attributes = RWMB_Input_Field::get_attributes( $field, $value );
104
+ $attributes['class'] .= " rwmb-choice";
105
+ $attributes['id'] = false;
106
+ $attributes['type'] = 'radio_list' === $field['field_type'] ? 'radio' : 'checkbox';
107
+ break;
108
+ case 'select_advanced':
109
+ $attributes = RWMB_Select_Advanced_Field::get_attributes( $field, $value );
110
+ $attributes['class'] .= " rwmb-select_advanced";
111
+ break;
112
+ case 'select_tree':
113
+ $attributes = RWMB_Select_Field::get_attributes( $field, $value );
114
+ $attributes['multiple'] = false;
115
+ $attributes['id'] = false;
116
+ $attributes['class'] .= " rwmb-select";
117
+ break;
118
+ case 'select':
119
+ default:
120
+ $attributes = RWMB_Select_Field::get_attributes( $field, $value );
121
+ $attributes['class'] .= " rwmb-select";
122
+ break;
123
+ }
124
+
125
+ $attributes['name'] .= ! $field['clone'] && $field['multiple'] ? '[]' : '';
126
+
127
+ return $attributes;
128
+ }
129
+
130
+ /**
131
+ * Get field names of object to be used by walker
132
+ *
133
+ * @return array
134
+ */
135
+ static function get_db_fields()
136
+ {
137
+ return array(
138
+ 'parent' => '',
139
+ 'id' => '',
140
+ 'label' => '',
141
+ );
142
+ }
143
+
144
+ /**
145
+ * Enqueue scripts and styles
146
+ *
147
+ * @return void
148
+ */
149
+ static function admin_enqueue_scripts()
150
+ {
151
+ wp_enqueue_style( 'rwmb-object-choice', RWMB_CSS_URL . 'object-choice.css', array(), RWMB_VER );
152
+ wp_enqueue_script( 'rwmb-object-choice', RWMB_JS_URL . 'object-choice.js', array(), RWMB_VER, true );
153
+ RWMB_Select_Field::admin_enqueue_scripts();
154
+ RWMB_Select_Advanced_Field::admin_enqueue_scripts();
155
+ }
156
+
157
+ /**
158
+ * Render checkbox_list or radio_list using walker
159
+ *
160
+ * @param $options
161
+ * @param $meta
162
+ * @param $field
163
+ *
164
+ * @return array
165
+ */
166
+ static function render_list( $options, $meta, $field )
167
+ {
168
+ $field_class = RW_Meta_Box::get_class_name( $field );
169
+ $db_fields = call_user_func( array( $field_class, 'get_db_fields' ), $field );
170
+ $walker = new RWMB_Choice_List_Walker( $db_fields, $field, $meta );
171
+
172
+ $output = sprintf( '<ul class="rwmb-choice-list %s">', $field['collapse'] ? 'collapse' : '' );
173
+
174
+ $output .= $walker->walk( $options, $field['flatten'] ? - 1 : 0 );
175
+ $output .= '</ul>';
176
+ return $output;
177
+ }
178
+
179
+ /**
180
+ * Render select or select_advanced using walker
181
+ *
182
+ * @param $options
183
+ * @param $meta
184
+ * @param $field
185
+ *
186
+ * @return array
187
+ */
188
+ static function render_select( $options, $meta, $field )
189
+ {
190
+ $field_class = RW_Meta_Box::get_class_name( $field );
191
+ $attributes = call_user_func( array( $field_class, 'get_attributes' ), $field, $meta );
192
+ $db_fields = call_user_func( array( $field_class, 'get_db_fields' ), $field );
193
+ $walker = new RWMB_Select_Walker( $db_fields, $field, $meta );
194
+
195
+ $output = sprintf(
196
+ '<select %s>',
197
+ self::render_attributes( $attributes )
198
+ );
199
+ if ( false === $field['multiple'] )
200
+ {
201
+ $output .= isset( $field['placeholder'] ) ? "<option value=''>{$field['placeholder']}</option>" : '<option></option>';
202
+ }
203
+ $output .= $walker->walk( $options, $field['flatten'] ? - 1 : 0 );
204
+ $output .= '</select>';
205
+ return $output;
206
+ }
207
+
208
+ /**
209
+ * Render select_tree
210
+ *
211
+ * @param $options
212
+ * @param $meta
213
+ * @param $field
214
+ *
215
+ * @return array
216
+ */
217
+ static function render_select_tree( $options, $meta, $field )
218
+ {
219
+ $field_class = RW_Meta_Box::get_class_name( $field );
220
+ $db_fields = call_user_func( array( $field_class, 'get_db_fields' ), $field );
221
+ $walker = new RWMB_Select_Tree_Walker( $db_fields, $field, $meta );
222
+ $output = $walker->walk( $options );
223
+
224
+ return $output;
225
+ }
226
+
227
+ /**
228
+ * Get options for walker
229
+ *
230
+ * @param array $field
231
+ *
232
+ * @return array
233
+ */
234
+ static function get_options( $field )
235
+ {
236
+ return array();
237
+ }
238
+ }
inc/fields/oembed.php CHANGED
@@ -1,118 +1,103 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
 
 
 
 
 
 
 
 
 
 
 
4
 
5
- // Make sure "text" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'url.php';
 
 
 
 
 
7
 
8
- if ( ! class_exists( 'RWMB_OEmbed_Field' ) )
9
- {
10
- class RWMB_OEmbed_Field extends RWMB_URL_Field
 
11
  {
12
- /**
13
- * Enqueue scripts and styles
14
- *
15
- * @return void
16
- */
17
- static function admin_enqueue_scripts()
18
- {
19
- wp_enqueue_style( 'rwmb-oembed', RWMB_CSS_URL . 'oembed.css' );
20
- wp_enqueue_script( 'rwmb-oembed', RWMB_JS_URL . 'oembed.js', array(), RWMB_VER, true );
21
- }
22
 
23
- /**
24
- * Add actions
25
- *
26
- * @return void
27
- */
28
- static function add_actions()
29
- {
30
- add_action( 'wp_ajax_rwmb_get_embed', array( __CLASS__, 'wp_ajax_get_embed' ) );
31
- }
 
32
 
33
- /**
34
- * Ajax callback for returning oEmbed HTML
35
- *
36
- * @return void
37
- */
38
- static function wp_ajax_get_embed()
39
  {
40
- $url = isset( $_POST['url'] ) ? $_POST['url'] : '';
41
- wp_send_json_success( self::get_embed( $url ) );
42
  }
43
 
44
- /**
45
- * Get embed html from url
46
- *
47
- * @param string $url
48
- *
49
- * @return string
50
- */
51
- static function get_embed( $url )
52
- {
53
- // Try oembed first
54
- $embed = @wp_oembed_get( $url );
55
-
56
- // If no oembed provides found, try WordPress auto embed
57
- if ( ! $embed )
58
- {
59
- $embed = $GLOBALS['wp_embed']->shortcode( array(), $url );
60
- }
61
-
62
- return $embed ? $embed : __( 'Embed HTML not available.', 'meta-box' );
63
- }
64
 
65
- /**
66
- * Get field HTML
67
- *
68
- * @param mixed $meta
69
- * @param array $field
70
- *
71
- * @return string
72
- */
73
- static function html( $meta, $field )
74
- {
75
- return sprintf(
76
- '<input type="url" class="rwmb-oembed" name="%s" id="%s" value="%s" size="%s">
77
- <a href="#" class="show-embed button">%s</a>
78
- <span class="spinner"></span>
79
- <div class="embed-code">%s</div>',
80
- $field['field_name'],
81
- $field['id'],
82
- $meta,
83
- $field['size'],
84
- __( 'Preview', 'meta-box' ),
85
- $meta ? self::get_embed( $meta ) : ''
86
- );
87
- }
88
 
89
- /**
90
- * Output the field value
91
- * Display embed media
92
- *
93
- * @param array $field Field parameters
94
- * @param array $args Additional arguments. Not used for these fields.
95
- * @param int|null $post_id Post ID. null for current post. Optional.
96
- *
97
- * @return mixed Field value
98
- */
99
- static function the_value( $field, $args = array(), $post_id = null )
 
 
 
100
  {
101
- $value = self::get_value( $field, $args, $post_id );
102
- if ( $field['clone'] )
103
  {
104
- $output = '<ul>';
105
- foreach ( $value as $subvalue )
106
- {
107
- $output .= '<li>' . self::get_embed( $subvalue ) . '</li>';
108
- }
109
- $output .= '</ul>';
110
  }
111
- else
112
- {
113
- $output = self::get_embed( $value );
114
- }
115
- return $output;
116
  }
 
117
  }
118
  }
1
  <?php
2
+ /**
3
+ * oEmbed field class.
4
+ */
5
+ class RWMB_OEmbed_Field extends RWMB_URL_Field
6
+ {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ */
10
+ static function admin_enqueue_scripts()
11
+ {
12
+ wp_enqueue_style( 'rwmb-oembed', RWMB_CSS_URL . 'oembed.css' );
13
+ wp_enqueue_script( 'rwmb-oembed', RWMB_JS_URL . 'oembed.js', array(), RWMB_VER, true );
14
+ }
15
 
16
+ /**
17
+ * Add actions
18
+ */
19
+ static function add_actions()
20
+ {
21
+ add_action( 'wp_ajax_rwmb_get_embed', array( __CLASS__, 'wp_ajax_get_embed' ) );
22
+ }
23
 
24
+ /**
25
+ * Ajax callback for returning oEmbed HTML
26
+ */
27
+ static function wp_ajax_get_embed()
28
  {
29
+ $url = (string) filter_input( INPUT_POST, 'url', FILTER_SANITIZE_URL );
30
+ wp_send_json_success( self::get_embed( $url ) );
31
+ }
 
 
 
 
 
 
 
32
 
33
+ /**
34
+ * Get embed html from url
35
+ *
36
+ * @param string $url
37
+ * @return string
38
+ */
39
+ static function get_embed( $url )
40
+ {
41
+ // Try oembed first
42
+ $embed = wp_oembed_get( $url );
43
 
44
+ // If no oembed provides found, try WordPress auto embed
45
+ if ( ! $embed )
 
 
 
 
46
  {
47
+ $embed = $GLOBALS['wp_embed']->shortcode( array(), $url );
 
48
  }
49
 
50
+ return $embed ? $embed : __( 'Embed HTML not available.', 'meta-box' );
51
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
+ /**
54
+ * Get field HTML
55
+ *
56
+ * @param mixed $meta
57
+ * @param array $field
58
+ * @return string
59
+ */
60
+ static function html( $meta, $field )
61
+ {
62
+ $attributes = self::get_attributes( $field, $meta );
63
+ return sprintf(
64
+ '<input %s>
65
+ <a href="#" class="show-embed button">%s</a>
66
+ <span class="spinner"></span>
67
+ <div class="embed-code">%s</div>',
68
+ self::render_attributes( $attributes ),
69
+ $field['size'],
70
+ __( 'Preview', 'meta-box' ),
71
+ $meta ? self::get_embed( $meta ) : ''
72
+ );
73
+ }
 
 
74
 
75
+ /**
76
+ * Output the field value
77
+ * Display embed media
78
+ *
79
+ * @param array $field Field parameters
80
+ * @param array $args Additional arguments. Not used for these fields.
81
+ * @param int|null $post_id Post ID. null for current post. Optional.
82
+ *
83
+ * @return mixed Field value
84
+ */
85
+ static function the_value( $field, $args = array(), $post_id = null )
86
+ {
87
+ $value = self::get_value( $field, $args, $post_id );
88
+ if ( $field['clone'] )
89
  {
90
+ $output = '<ul>';
91
+ foreach ( $value as $subvalue )
92
  {
93
+ $output .= '<li>' . self::get_embed( $subvalue ) . '</li>';
 
 
 
 
 
94
  }
95
+ $output .= '</ul>';
96
+ }
97
+ else
98
+ {
99
+ $output = self::get_embed( $value );
100
  }
101
+ return $output;
102
  }
103
  }
inc/fields/password.php CHANGED
@@ -1,28 +1,34 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "text" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'text.php';
7
-
8
- if ( ! class_exists( 'RWMB_Password_Field' ) )
9
  {
10
- class RWMB_Password_Field extends RWMB_Text_Field
 
 
 
 
 
 
 
11
  {
12
- /**
13
- * Normalize parameters for field
14
- *
15
- * @param array $field
16
- *
17
- * @return array
18
- */
19
- static function normalize_field( $field )
20
- {
21
- $field = parent::normalize_field( $field );
22
-
23
- $field['attributes']['type'] = 'password';
24
 
25
- return $field;
26
- }
 
 
 
 
 
 
 
 
 
 
27
  }
28
  }
1
  <?php
2
+ /**
3
+ * Password field class.
4
+ */
5
+ class RWMB_Password_Field extends RWMB_Text_Field
 
 
 
6
  {
7
+ /**
8
+ * Get the attributes for a field
9
+ *
10
+ * @param array $field
11
+ * @param mixed $value
12
+ * @return array
13
+ */
14
+ static function get_attributes( $field, $value = null )
15
  {
16
+ $attributes = parent::get_attributes( $field, $value );
17
+ $attributes['type'] = 'password';
18
+ return $attributes;
19
+ }
 
 
 
 
 
 
 
 
20
 
21
+ /**
22
+ * Store secured password in the database.
23
+ * @param mixed $new
24
+ * @param mixed $old
25
+ * @param int $post_id
26
+ * @param array $field
27
+ * @return string
28
+ */
29
+ static function value( $new, $old, $post_id, $field )
30
+ {
31
+ $new = $new != $old ? wp_hash_password( $new ) : $new;
32
+ return $new;
33
  }
34
  }
inc/fields/plupload-image.php CHANGED
@@ -1,196 +1,162 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
- require_once RWMB_FIELDS_DIR . 'image.php';
5
- if ( ! class_exists( 'RWMB_Plupload_Image_Field' ) )
6
  {
7
- class RWMB_Plupload_Image_Field extends RWMB_Image_Field
 
 
 
8
  {
9
- /**
10
- * Add field actions
11
- *
12
- * @return void
13
- */
14
- static function add_actions()
15
- {
16
- parent::add_actions();
17
- add_action( 'wp_ajax_rwmb_plupload_image_upload', array( __CLASS__, 'handle_upload' ) );
18
- }
19
 
20
- /**
21
- * Upload
22
- * Ajax callback function
23
- *
24
- * @return string Error or (XML-)response
25
- */
26
- static function handle_upload()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  {
28
- global $wpdb;
29
- $post_id = isset( $_REQUEST['post_id'] ) ? intval( $_REQUEST['post_id'] ) : 0;
30
- $field_id = isset( $_REQUEST['field_id'] ) ? $_REQUEST['field_id'] : '';
31
-
32
- check_ajax_referer( "rwmb-upload-images_{$field_id}" );
33
-
34
- // You can use WP's wp_handle_upload() function:
35
- $file = $_FILES['async-upload'];
36
- $file_attr = wp_handle_upload( $file, array( 'test_form' => false ) );
37
- //Get next menu_order
38
- $meta = get_post_meta( $post_id, $field_id, false );
39
- if ( empty( $meta ) )
40
- {
41
- $next = 0;
42
- }
43
- else
44
- {
45
- $meta = implode( ',', (array) $meta );
46
- $max = $wpdb->get_var( "
47
- SELECT MAX(menu_order) FROM {$wpdb->posts}
48
- WHERE post_type = 'attachment'
49
- AND ID in ({$meta})
50
- " );
51
- $next = is_numeric( $max ) ? (int) $max + 1 : 0;
52
- }
53
-
54
- $attachment = array(
55
- 'guid' => $file_attr['url'],
56
- 'post_mime_type' => $file_attr['type'],
57
- 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $file['name'] ) ),
58
- 'post_content' => '',
59
- 'post_status' => 'inherit',
60
- 'menu_order' => $next,
61
- );
62
-
63
- // Adds file as attachment to WordPress
64
- $id = wp_insert_attachment( $attachment, $file_attr['file'], $post_id );
65
- if ( ! is_wp_error( $id ) )
66
- {
67
- wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file_attr['file'] ) );
68
-
69
- // Save file ID in meta field
70
- add_post_meta( $post_id, $field_id, $id, false );
71
- wp_send_json_success( self::img_html( $id ) );
72
- }
73
-
74
- exit;
75
  }
 
76
 
77
- /**
78
- * Enqueue scripts and styles
79
- *
80
- * @return void
81
- */
82
- static function admin_enqueue_scripts()
83
- {
84
- // Enqueue same scripts and styles as for file field
85
- parent::admin_enqueue_scripts();
86
- wp_enqueue_style( 'rwmb-plupload-image', RWMB_CSS_URL . 'plupload-image.css', array( 'wp-admin' ), RWMB_VER );
87
- wp_enqueue_script( 'rwmb-plupload-image', RWMB_JS_URL . 'plupload-image.js', array( 'jquery-ui-sortable', 'wp-ajax-response', 'plupload-all' ), RWMB_VER, true );
88
- wp_localize_script( 'rwmb-plupload-image', 'RWMB', array( 'url' => RWMB_URL ) );
89
- }
90
 
91
- /**
92
- * Get field HTML
93
- *
94
- * @param mixed $meta
95
- * @param array $field
96
- *
97
- * @return string
98
- */
99
- static function html( $meta, $field )
100
- {
101
- if ( ! is_array( $meta ) )
102
- $meta = ( array ) $meta;
103
-
104
- // Filter to change the drag & drop box background string
105
- $i18n_drop = apply_filters( 'rwmb_plupload_image_drop_string', _x( 'Drop images here', 'image upload', 'meta-box' ), $field );
106
- $i18n_or = apply_filters( 'rwmb_plupload_image_or_string', _x( 'or', 'image upload', 'meta-box' ), $field );
107
- $i18n_select = apply_filters( 'rwmb_plupload_image_select_string', _x( 'Select Files', 'image upload', 'meta-box' ), $field );
108
-
109
- // Uploaded images
110
-
111
- // Check for max_file_uploads
112
- $classes = array( 'rwmb-drag-drop', 'drag-drop', 'hide-if-no-js', 'new-files' );
113
- if ( ! empty( $field['max_file_uploads'] ) && count( $meta ) >= (int) $field['max_file_uploads'] )
114
- $classes[] = 'hidden';
115
-
116
- $html = self::get_uploaded_images( $meta, $field );
117
-
118
- // Show form upload
119
- $html .= sprintf(
120
- '<div id="%s-dragdrop" class="%s" data-upload_nonce="%s" data-js_options="%s">
121
- <div class = "drag-drop-inside">
122
- <p class="drag-drop-info">%s</p>
123
- <p>%s</p>
124
- <p class="drag-drop-buttons"><input id="%s-browse-button" type="button" value="%s" class="button" /></p>
125
- </div>
126
- </div>',
127
- $field['id'],
128
- implode( ' ', $classes ),
129
- wp_create_nonce( "rwmb-upload-images_{$field['id']}" ),
130
- esc_attr( wp_json_encode( $field['js_options'] ) ),
131
- $i18n_drop,
132
- $i18n_or,
133
- $field['id'],
134
- $i18n_select
135
- );
136
-
137
- return $html;
138
- }
139
 
140
- /**
141
- * Get field value
142
- * It's the combination of new (uploaded) images and saved images
143
- *
144
- * @param array $new
145
- * @param array $old
146
- * @param int $post_id
147
- * @param array $field
148
- *
149
- * @return array|mixed
150
- */
151
- static function value( $new, $old, $post_id, $field )
152
- {
153
- $new = (array) $new;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
- return array_unique( array_merge( $old, $new ) );
156
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
- /**
159
- * Normalize parameters for field
160
- *
161
- * @param array $field
162
- *
163
- * @return array
164
- */
165
- static function normalize_field( $field )
166
- {
167
- $field['js_options'] = array(
168
- 'runtimes' => 'html5,silverlight,flash,html4',
169
- 'file_data_name' => 'async-upload',
170
- //'container' => $field['id'] . '-container',
171
- 'browse_button' => $field['id'] . '-browse-button',
172
- 'drop_element' => $field['id'] . '-dragdrop',
173
- 'multiple_queues' => true,
174
- 'max_file_size' => wp_max_upload_size() . 'b',
175
- 'url' => admin_url( 'admin-ajax.php' ),
176
- 'flash_swf_url' => includes_url( 'js/plupload/plupload.flash.swf' ),
177
- 'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
178
- 'multipart' => true,
179
- 'urlstream_upload' => true,
180
- 'filters' => array(
181
- array(
182
- 'title' => _x( 'Allowed Image Files', 'image upload', 'meta-box' ),
183
- 'extensions' => 'jpg,jpeg,gif,png',
184
- ),
185
  ),
186
- 'multipart_params' => array(
187
- 'field_id' => $field['id'],
188
- 'action' => 'rwmb_plupload_image_upload',
189
- )
190
- );
191
- $field = parent::normalize_field( $field );
192
-
193
- return $field;
194
- }
195
  }
196
  }
1
  <?php
2
+ /**
3
+ * Image upload field which uses plupload library to drag and drop files to upload.
4
+ */
5
+ class RWMB_Plupload_Image_Field extends RWMB_Image_Field
6
  {
7
+ /**
8
+ * Add field actions.
9
+ */
10
+ static function add_actions()
11
  {
12
+ parent::add_actions();
13
+ add_action( 'wp_ajax_rwmb_plupload_image_upload', array( __CLASS__, 'handle_upload' ) );
14
+ }
 
 
 
 
 
 
 
15
 
16
+ /**
17
+ * Upload ajax callback function.
18
+ */
19
+ static function handle_upload()
20
+ {
21
+ $post_id = (int) filter_input( INPUT_POST, 'post_id', FILTER_SANITIZE_NUMBER_INT );
22
+ $field_id = (string) filter_input( INPUT_POST, 'field_id' );
23
+
24
+ check_ajax_referer( "rwmb-upload-images_{$field_id}" );
25
+
26
+ $file = $_FILES['async-upload'];
27
+ $file_attr = wp_handle_upload( $file, array( 'test_form' => false ) );
28
+ $attachment = array(
29
+ 'guid' => $file_attr['url'],
30
+ 'post_mime_type' => $file_attr['type'],
31
+ 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $file['name'] ) ),
32
+ 'post_content' => '',
33
+ 'post_status' => 'inherit',
34
+ );
35
+
36
+ // Adds file as attachment to WordPress
37
+ $attachment_id = wp_insert_attachment( $attachment, $file_attr['file'], $post_id );
38
+ if ( is_wp_error( $attachment_id ) )
39
  {
40
+ wp_send_json_error();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  }
42
+ wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file_attr['file'] ) );
43
 
44
+ // Save file ID in meta field
45
+ add_post_meta( $post_id, $field_id, $attachment_id, false );
46
+ wp_send_json_success( self::img_html( $attachment_id ) );
47
+ }
 
 
 
 
 
 
 
 
 
48
 
49
+ /**
50
+ * Enqueue scripts and styles.
51
+ */
52
+ static function admin_enqueue_scripts()
53
+ {
54
+ // Enqueue same scripts and styles as for file field
55
+ parent::admin_enqueue_scripts();
56
+ wp_enqueue_style( 'rwmb-plupload-image', RWMB_CSS_URL . 'plupload-image.css', array( 'wp-admin' ), RWMB_VER );
57
+ wp_enqueue_script( 'rwmb-plupload-image', RWMB_JS_URL . 'plupload-image.js', array( 'jquery-ui-sortable', 'wp-ajax-response', 'plupload-all' ), RWMB_VER, true );
58
+ wp_localize_script( 'rwmb-plupload-image', 'RWMB', array( 'url' => RWMB_URL ) );
59
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
+ /**
62
+ * Get field HTML.
63
+ *
64
+ * @param mixed $meta
65
+ * @param array $field
66
+ * @return string
67
+ */
68
+ static function html( $meta, $field )
69
+ {
70
+ if ( ! is_array( $meta ) )
71
+ $meta = ( array ) $meta;
72
+
73
+ // Filter to change the drag & drop box background string
74
+ $i18n_drop = apply_filters( 'rwmb_plupload_image_drop_string', _x( 'Drop images here', 'image upload', 'meta-box' ), $field );
75
+ $i18n_or = apply_filters( 'rwmb_plupload_image_or_string', _x( 'or', 'image upload', 'meta-box' ), $field );
76
+ $i18n_select = apply_filters( 'rwmb_plupload_image_select_string', _x( 'Select Files', 'image upload', 'meta-box' ), $field );
77
+
78
+ // Uploaded images
79
+
80
+ // Check for max_file_uploads
81
+ $classes = array( 'rwmb-drag-drop', 'drag-drop', 'hide-if-no-js', 'new-files' );
82
+ if ( ! empty( $field['max_file_uploads'] ) && count( $meta ) >= (int) $field['max_file_uploads'] )
83
+ $classes[] = 'hidden';
84
+
85
+ $html = self::get_uploaded_images( $meta, $field );
86
+
87
+ // Show form upload
88
+ $html .= sprintf(
89
+ '<div id="%s-dragdrop" class="%s" data-upload_nonce="%s" data-js_options="%s">
90
+ <div class = "drag-drop-inside">
91
+ <p class="drag-drop-info">%s</p>
92
+ <p>%s</p>
93
+ <p class="drag-drop-buttons"><input id="%s-browse-button" type="button" value="%s" class="button" /></p>
94
+ </div>
95
+ </div>',
96
+ $field['id'],
97
+ implode( ' ', $classes ),
98
+ wp_create_nonce( "rwmb-upload-images_{$field['id']}" ),
99
+ esc_attr( wp_json_encode( $field['js_options'] ) ),
100
+ $i18n_drop,
101
+ $i18n_or,
102
+ $field['id'],
103
+ $i18n_select
104
+ );
105
+
106
+ return $html;
107
+ }
108
 
109
+ /**
110
+ * Get field value.
111
+ * It's the combination of new (uploaded) images and saved images
112
+ *
113
+ * @param array $new
114
+ * @param array $old
115
+ * @param int $post_id
116
+ * @param array $field
117
+ *
118
+ * @return array
119
+ */
120
+ static function value( $new, $old, $post_id, $field )
121
+ {
122
+ $new = (array) $new;
123
+ return array_unique( array_merge( $old, $new ) );
124
+ }
125
 
126
+ /**
127
+ * Normalize parameters for field.
128
+ *
129
+ * @param array $field
130
+ * @return array
131
+ */
132
+ static function normalize( $field )
133
+ {
134
+ $field['js_options'] = array(
135
+ 'runtimes' => 'html5,silverlight,flash,html4',
136
+ 'file_data_name' => 'async-upload',
137
+ //'container' => $field['id'] . '-container',
138
+ 'browse_button' => $field['id'] . '-browse-button',
139
+ 'drop_element' => $field['id'] . '-dragdrop',
140
+ 'multiple_queues' => true,
141
+ 'max_file_size' => wp_max_upload_size() . 'b',
142
+ 'url' => admin_url( 'admin-ajax.php' ),
143
+ 'flash_swf_url' => includes_url( 'js/plupload/plupload.flash.swf' ),
144
+ 'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
145
+ 'multipart' => true,
146
+ 'urlstream_upload' => true,
147
+ 'filters' => array(
148
+ array(
149
+ 'title' => _x( 'Allowed Image Files', 'image upload', 'meta-box' ),
150
+ 'extensions' => 'jpg,jpeg,gif,png',
 
 
151
  ),
152
+ ),
153
+ 'multipart_params' => array(
154
+ 'field_id' => $field['id'],
155
+ 'action' => 'rwmb_plupload_image_upload',
156
+ ),
157
+ );
158
+ $field = parent::normalize( $field );
159
+
160
+ return $field;
161
  }
162
  }
inc/fields/post.php CHANGED
@@ -1,171 +1,137 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "select-advanced" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'select-advanced.php';
7
-
8
- if ( ! class_exists( 'RWMB_Post_Field' ) )
9
  {
10
- class RWMB_Post_Field extends RWMB_Select_Advanced_Field
 
 
 
 
 
 
 
11
  {
12
  /**
13
- * Enqueue scripts and styles
14
- *
15
- * @return void
16
  */
17
- static function admin_enqueue_scripts()
18
- {
19
- RWMB_Select_Field::admin_enqueue_scripts();
20
- RWMB_Select_Advanced_Field::admin_enqueue_scripts();
21
- }
 
22
 
23
  /**
24
- * Get field HTML
25
- *
26
- * @param mixed $meta
27
- * @param array $field
28
- *
29
- * @return string
30
  */
31
- static function html( $meta, $field )
32
  {
33
- $field['options'] = self::get_options( $field );
34
- switch ( $field['field_type'] )
35
  {
36
- case 'select':
37
- return RWMB_Select_Field::html( $meta, $field );
38
- case 'select_advanced':
39
- default:
40
- return RWMB_Select_Advanced_Field::html( $meta, $field );
41
  }
42
  }
43
 
44
  /**
45
- * Normalize parameters for field
46
- *
47
- * @param array $field
48
- *
49
- * @return array
50
  */
51
- static function normalize_field( $field )
52
  {
53
- $field = wp_parse_args( $field, array(
54
- 'post_type' => 'post',
55
- 'field_type' => 'select_advanced',
56
- 'parent' => false,
57
- 'query_args' => array(),
58
- ) );
59
-
60
- /**
61
- * Set default placeholder
62
- * - If multiple post types: show 'Select a post'
63
- * - If single post type: show 'Select a %post_type_name%'
64
- */
65
- if ( empty( $field['placeholder'] ) )
66
- {
67
- $label = __( 'Select a post', 'meta-box' );
68
- if ( is_string( $field['post_type'] ) && post_type_exists( $field['post_type'] ) )
69
- {
70
- $post_type_object = get_post_type_object( $field['post_type'] );
71
- $label = sprintf( __( 'Select a %s', 'meta-box' ), $post_type_object->labels->singular_name );
72
- }
73
- $field['placeholder'] = $label;
74
- }
75
-
76
- if ( $field['parent'] )
77
- {
78
- $field['multiple'] = false;
79
- $field['field_name'] = 'parent_id';
80
- }
81
-
82
- $field['query_args'] = wp_parse_args( $field['query_args'], array(
83
- 'post_type' => $field['post_type'],
84
- 'post_status' => 'publish',
85
- 'posts_per_page' => - 1,
86
- ) );
87
-
88
- switch ( $field['field_type'] )
89
- {
90
- case 'select':
91
- return RWMB_Select_Field::normalize_field( $field );
92
- break;
93
- case 'select_advanced':
94
- default:
95
- return RWMB_Select_Advanced_Field::normalize_field( $field );
96
- }
97
  }
98
 
99
  /**
100
- * Get meta value
101
- * If field is cloneable, value is saved as a single entry in DB
102
- * Otherwise value is saved as multiple entries (for backward compatibility)
103
- *
104
- * @see "save" method for better understanding
105
- *
106
- * @param $post_id
107
- * @param $saved
108
- * @param $field
109
- *
110
- * @return array
111
  */
112
- static function meta( $post_id, $saved, $field )
113
- {
114
- if ( isset( $field['parent'] ) && $field['parent'] )
115
- {
116
- $post = get_post( $post_id );
117
 
118
- return $post->post_parent;
119
- }
120
 
121
- return parent::meta( $post_id, $saved, $field );
122
- }
123
 
124
- /**
125
- * Get posts
126
- *
127
- * @param array $field
128
- *
129
- * @return array
130
- */
131
- static function get_options( $field )
132
- {
133
- $options = array();
134
- $query = new WP_Query( $field['query_args'] );
135
- if ( $query->have_posts() )
136
- {
137
- while ( $query->have_posts() )
138
- {
139
- $post = $query->next_post();
140
- $title = apply_filters( 'rwmb_post_field_title', $post->post_title, $post );
141
- $title = apply_filters( "rwmb_{$field['id']}_field_title", $title, $post );
142
- $options[$post->ID] = $title;
143
- }
144
- }
145
 
146
- return $options;
147
- }
 
 
 
 
 
 
 
 
 
 
 
148
 
149
- /**
150
- * Get post link to display in the frontend
151
- *
152
- * @param int $value Option value, e.g. post ID
153
- * @param int $index Array index
154
- * @param array $field Field parameter
155
- *
156
- * @return string
157
- */
158
- static function get_option_label( &$value, $index, $field )
 
 
 
 
 
 
159
  {
160
- $value = sprintf(
161
- '<a href="%s" title="%s">%s</a>',
162
- esc_url( get_permalink( $value ) ),
163
- the_title_attribute( array(
164
- 'post' => $value,
165
- 'echo' => false,
166
- ) ),
167
- get_the_title( $value )
168
- );
169
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  }
171
  }
1
  <?php
2
+ /**
3
+ * Post field class.
4
+ */
5
+ class RWMB_Post_Field extends RWMB_Object_Choice_Field
 
 
 
6
  {
7
+ /**
8
+ * Normalize parameters for field
9
+ *
10
+ * @param array $field
11
+ *
12
+ * @return array
13
+ */
14
+ static function normalize( $field )
15
  {
16
  /**
17
+ * Set default field args
 
 
18
  */
19
+ $field = wp_parse_args( $field, array(
20
+ 'post_type' => 'post',
21
+ 'field_type' => 'select',
22
+ 'parent' => false,
23
+ 'query_args' => array(),
24
+ ) );
25
 
26
  /**
27
+ * Set default placeholder
28
+ * - If multiple post types: show 'Select a post'
29
+ * - If single post type: show 'Select a %post_type_name%'
 
 
 
30
  */
31
+ if ( empty( $field['placeholder'] ) )
32
  {
33
+ $field['placeholder'] = __( 'Select a post', 'meta-box' );
34
+ if ( is_string( $field['post_type'] ) && post_type_exists( $field['post_type'] ) )
35
  {
36
+ $post_type_object = get_post_type_object( $field['post_type'] );
37
+ $field['placeholder'] = sprintf( __( 'Select a %s', 'meta-box' ), $post_type_object->labels->singular_name );
 
 
 
38
  }
39
  }
40
 
41
  /**
42
+ * Set parent option, which will change field name to `parent_id` to save as post parent
 
 
 
 
43
  */
44
+ if ( $field['parent'] )
45
  {
46
+ $field['multiple'] = false;
47
+ $field['field_name'] = 'parent_id';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  }
49
 
50
  /**
51
+ * Set default query args
 
 
 
 
 
 
 
 
 
 
52
  */
53
+ $field['query_args'] = wp_parse_args( $field['query_args'], array(
54
+ 'post_status' => 'publish',
55
+ 'posts_per_page' => - 1,
56
+ ) );
57
+ $field['query_args']['post_type'] = $field['post_type'];
58
 
 
 
59
 
60
+ $field = parent::normalize( $field );
 
61
 
62
+ return $field;
63
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ /**
66
+ * Get field names of object to be used by walker
67
+ *
68
+ * @return array
69
+ */
70
+ static function get_db_fields()
71
+ {
72
+ return array(
73
+ 'parent' => 'post_parent',
74
+ 'id' => 'ID',
75
+ 'label' => 'post_title',
76
+ );
77
+ }
78
 
79
+ /**
80
+ * Get meta value
81
+ * If field is cloneable, value is saved as a single entry in DB
82
+ * Otherwise value is saved as multiple entries (for backward compatibility)
83
+ *
84
+ * @see "save" method for better understanding
85
+ *
86
+ * @param $post_id
87
+ * @param $saved
88
+ * @param $field
89
+ *
90
+ * @return array
91
+ */
92
+ static function meta( $post_id, $saved, $field )
93
+ {
94
+ if ( isset( $field['parent'] ) && $field['parent'] )
95
  {
96
+ $post = get_post( $post_id );
97
+ return $post->post_parent;
 
 
 
 
 
 
 
98
  }
99
+
100
+ return parent::meta( $post_id, $saved, $field );
101
+ }
102
+
103
+ /**
104
+ * Get options for walker
105
+ *
106
+ * @param array $field
107
+ *
108
+ * @return array
109
+ */
110
+ static function get_options( $field )
111
+ {
112
+ $query = new WP_Query( $field['query_args'] );
113
+ return $query->have_posts() ? $query->posts : array();
114
+ }
115
+
116
+ /**
117
+ * Get post link to display in the frontend
118
+ *
119
+ * @param int $value Option value, e.g. post ID
120
+ * @param int $index Array index
121
+ * @param array $field Field parameter
122
+ *
123
+ * @return string
124
+ */
125
+ static function get_option_label( &$value, $index, $field )
126
+ {
127
+ $value = sprintf(
128
+ '<a href="%s" title="%s">%s</a>',
129
+ esc_url( get_permalink( $value ) ),
130
+ the_title_attribute( array(
131
+ 'post' => $value,
132
+ 'echo' => false,
133
+ ) ),
134
+ get_the_title( $value )
135
+ );
136
  }
137
  }
inc/fields/radio.php CHANGED
@@ -1,77 +1,69 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "input" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'input.php';
7
-
8
- if ( ! class_exists( 'RWMB_Radio_Field' ) )
9
  {
10
- class RWMB_Radio_Field extends RWMB_Input_Field
 
 
 
 
 
 
 
 
11
  {
12
- /**
13
- * Get field HTML
14
- *
15
- * @param mixed $meta
16
- * @param array $field
17
- *
18
- * @return string
19
- */
20
- static function html( $meta, $field )
21
- {
22
- $html = array();
23
- $tpl = '<label><input %s %s> %s</label>';
24
- $attributes = $field['attributes'];
25
-
26
- foreach ( $field['options'] as $value => $label )
27
- {
28
- $attributes['value'] = $value;
29
- $html[] = sprintf(
30
- $tpl,
31
- self::render_attributes( $attributes ),
32
- checked( $value, $meta, false ),
33
- $label
34
- );
35
- }
36
 
37
- return implode( ' ', $html );
38
- }
39
-
40
- /**
41
- * Normalize parameters for field
42
- *
43
- * @param array $field
44
- *
45
- * @return array
46
- */
47
- static function normalize_field( $field )
48
  {
49
- $field = parent::normalize_field( $field );
 
 
 
 
 
 
 
50
 
51
- $field['attributes']['list'] = false;
52
- $field['attributes']['id'] = false;
53
- $field['attributes']['type'] = 'radio';
54
 
55
- return $field;
56
- }
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
- /**
59
- * Output the field value
60
- * Display option name instead of option value
61
- *
62
- * @use self::meta()
63
- *
64
- * @param array $field Field parameters
65
- * @param array $args Additional arguments. Rarely used. See specific fields for details
66
- * @param int|null $post_id Post ID. null for current post. Optional.
67
- *
68
- * @return mixed Field value
69
- */
70
- static function the_value( $field, $args = array(), $post_id = null )
71
- {
72
- $value = parent::get_value( $field, $args, $post_id );
73
 
74
- return empty( $value ) ? '' : $field['options'][$value];
75
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  }
77
  }
1
  <?php
2
+ /**
3
+ * Radio field class.
4
+ */
5
+ class RWMB_Radio_Field extends RWMB_Input_Field
 
 
 
6
  {
7
+ /**
8
+ * Get field HTML
9
+ *
10
+ * @param mixed $meta
11
+ * @param array $field
12
+ *
13
+ * @return string
14
+ */
15
+ static function html( $meta, $field )
16
  {
17
+ $html = array();
18
+ $tpl = '<label><input %s %s> %s</label>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ foreach ( $field['options'] as $value => $label )
 
 
 
 
 
 
 
 
 
 
21
  {
22
+ $attributes = self::get_attributes( $field, $value );
23
+ $html[] = sprintf(
24
+ $tpl,
25
+ self::render_attributes( $attributes ),
26
+ checked( $value, $meta, false ),
27
+ $label
28
+ );
29
+ }
30
 
31
+ return implode( ' ', $html );
32
+ }
 
33
 
34
+ /**
35
+ * Get the attributes for a field
36
+ *
37
+ * @param array $field
38
+ * @param mixed $value
39
+ *
40
+ * @return array
41
+ */
42
+ static function get_attributes( $field, $value = null )
43
+ {
44
+ $attributes = parent::get_attributes( $field, $value );
45
+ $attributes['list'] = false;
46
+ $attributes['id'] = false;
47
+ $attributes['type'] = 'radio';
48
 
49
+ return $attributes;
50
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ /**
53
+ * Output the field value
54
+ * Display option name instead of option value
55
+ *
56
+ * @use self::meta()
57
+ *
58
+ * @param array $field Field parameters
59
+ * @param array $args Additional arguments. Rarely used. See specific fields for details
60
+ * @param int|null $post_id Post ID. null for current post. Optional.
61
+ *
62
+ * @return mixed Field value
63
+ */
64
+ static function the_value( $field, $args = array(), $post_id = null )
65
+ {
66
+ $value = parent::get_value( $field, $args, $post_id );
67
+ return empty( $value ) ? '' : $field['options'][$value];
68
  }
69
  }
inc/fields/range.php CHANGED
@@ -1,72 +1,78 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "number" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'number.php';
7
-
8
- if ( ! class_exists( 'RWMB_Range_Field' ) )
9
  {
10
- class RWMB_Range_Field extends RWMB_Number_Field
 
 
 
11
  {
12
- /**
13
- * Enqueue styles
14
- *
15
- * @return void
16
- */
17
- static function admin_enqueue_scripts()
18
- {
19
- wp_enqueue_style( 'rwmb-range', RWMB_CSS_URL . 'range.css', array(), RWMB_VER );
20
- }
21
 
22
- /**
23
- * Normalize parameters for field.
24
- *
25
- * @param array $field
26
- *
27
- * @return array
28
- */
29
- static function normalize_field( $field )
30
- {
31
- $field = wp_parse_args( $field, array(
32
- 'min' => 0,
33
- 'max' => 10,
34
- 'step' => 1,
35
- ) );
36
 
37
- $field = parent::normalize_field( $field );
38
 
39
- $field['attributes']['type'] = 'range';
 
40
 
41
- return $field;
42
- }
 
 
 
 
 
 
 
 
 
 
43
 
44
- /**
45
- * Ensure number in range.
46
- *
47
- * @param mixed $new
48
- * @param mixed $old
49
- * @param int $post_id
50
- * @param array $field
51
- *
52
- * @return int
53
- */
54
- static function value( $new, $old, $post_id, $field )
55
- {
56
- $new = intval( $new );
57
- $min = intval( $field['min'] );
58
- $max = intval( $field['max'] );
59
 
60
- if ( $new < $min )
61
- {
62
- return $min;
63
- }
64
- elseif ( $new > $max )
65
- {
66
- return $max;
67
- }
 
 
 
 
 
 
 
68
 
69
- return $new;
 
 
 
 
 
 
70
  }
 
 
71
  }
72
  }
1
  <?php
2
+ /**
3
+ * HTML5 range field class.
4
+ */
5
+ class RWMB_Range_Field extends RWMB_Number_Field
 
 
 
6
  {
7
+ /**
8
+ * Enqueue styles
9
+ */
10
+ static function admin_enqueue_scripts()
11
  {
12
+ wp_enqueue_style( 'rwmb-range', RWMB_CSS_URL . 'range.css', array(), RWMB_VER );
13
+ }
 
 
 
 
 
 
 
14
 
15
+ /**
16
+ * Normalize parameters for field.
17
+ *
18
+ * @param array $field
19
+ *
20
+ * @return array
21
+ */
22
+ static function normalize( $field )
23
+ {
24
+ $field = wp_parse_args( $field, array(
25
+ 'min' => 0,
26
+ 'max' => 10,
27
+ 'step' => 1,
28
+ ) );
29
 
30
+ $field = parent::normalize( $field );
31
 
32
+ return $field;
33
+ }
34
 
35
+ /**
36
+ * Get the attributes for a field
37
+ *
38
+ * @param array $field
39
+ * @param mixed $value
40
+ *
41
+ * @return array
42
+ */
43
+ static function get_attributes( $field, $value = null )
44
+ {
45
+ $attributes = parent::get_attributes( $field, $value );
46
+ $attributes['type'] = 'range';
47
 
48
+ return $attributes;
49
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
+ /**
52
+ * Ensure number in range.
53
+ *
54
+ * @param mixed $new
55
+ * @param mixed $old
56
+ * @param int $post_id
57
+ * @param array $field
58
+ *
59
+ * @return int
60
+ */
61
+ static function value( $new, $old, $post_id, $field )
62
+ {
63
+ $new = intval( $new );
64
+ $min = intval( $field['min'] );
65
+ $max = intval( $field['max'] );
66
 
67
+ if ( $new < $min )
68
+ {
69
+ return $min;
70
+ }
71
+ elseif ( $new > $max )
72
+ {
73
+ return $max;
74
  }
75
+
76
+ return $new;
77
  }
78
  }
inc/fields/select-advanced.php CHANGED
@@ -1,79 +1,81 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "select" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'select.php';
7
-
8
- if ( ! class_exists( 'RWMB_Select_Advanced_Field' ) )
9
  {
10
- class RWMB_Select_Advanced_Field extends RWMB_Select_Field
 
 
 
11
  {
12
- /**
13
- * Enqueue scripts and styles
14
- *
15
- * @return void
16
- */
17
- static function admin_enqueue_scripts()
18
- {
19
- wp_enqueue_style( 'select2', RWMB_CSS_URL . 'select2/select2.css', array(), '3.2' );
20
- wp_enqueue_style( 'rwmb-select-advanced', RWMB_CSS_URL . 'select-advanced.css', array(), RWMB_VER );
21
-
22
- wp_register_script( 'select2', RWMB_JS_URL . 'select2/select2.min.js', array(), '3.2', true );
23
- wp_enqueue_script( 'rwmb-select', RWMB_JS_URL . 'select.js', array(), RWMB_VER, true );
24
- wp_enqueue_script( 'rwmb-select-advanced', RWMB_JS_URL . 'select-advanced.js', array( 'select2', 'rwmb-select' ), RWMB_VER, true );
25
- }
26
 
27
- /**
28
- * Get field HTML
29
- *
30
- * @param mixed $meta
31
- * @param array $field
32
- *
33
- * @return string
34
- */
35
- static function html( $meta, $field )
36
- {
37
- $html = sprintf(
38
- '<select class="rwmb-select-advanced" name="%s" id="%s" size="%s"%s data-options="%s">',
39
- $field['field_name'],
40
- $field['id'],
41
- $field['size'],
42
- $field['multiple'] ? ' multiple' : '',
43
- esc_attr( wp_json_encode( $field['js_options'] ) )
44
- );
45
-
46
- $html .= self::options_html( $field, $meta );
47
 
48
- $html .= '</select>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
- $html .= self::get_select_all_html( $field['multiple'] );
 
 
 
 
 
 
 
 
 
 
 
51
 
52
- return $html;
53
- }
54
 
55
- /**
56
- * Normalize parameters for field
57
- *
58
- * @param array $field
59
- *
60
- * @return array
61
- */
62
- static function normalize_field( $field )
63
- {
64
- $field = parent::normalize_field( $field );
65
 
66
- $field = wp_parse_args( $field, array(
67
- 'js_options' => array(),
68
- ) );
69
 
70
- $field['js_options'] = wp_parse_args( $field['js_options'], array(
71
- 'allowClear' => true,
72
- 'width' => 'off',
73
- 'placeholder' => $field['placeholder'],
74
- ) );
 
 
 
 
 
 
 
 
75
 
76
- return $field;
77
- }
78
  }
79
  }
1
  <?php
2
+ /**
3
+ * Select advanced field which uses select2 library.
4
+ */
5
+ class RWMB_Select_Advanced_Field extends RWMB_Select_Field
 
 
 
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ */
10
+ static function admin_enqueue_scripts()
11
  {
12
+ wp_enqueue_style( 'select2', RWMB_CSS_URL . 'select2/select2.css', array(), '4.0.1' );
13
+ wp_enqueue_style( 'rwmb-select-advanced', RWMB_CSS_URL . 'select-advanced.css', array(), RWMB_VER );
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ wp_register_script( 'select2', RWMB_JS_URL . 'select2/select2.min.js', array(), '4.0.1', true );
16
+ wp_enqueue_script( 'rwmb-select', RWMB_JS_URL . 'select.js', array(), RWMB_VER, true );
17
+ wp_enqueue_script( 'rwmb-select-advanced', RWMB_JS_URL . 'select-advanced.js', array( 'select2', 'rwmb-select' ), RWMB_VER, true );
18
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ /**
21
+ * Get field HTML
22
+ *
23
+ * @param mixed $meta
24
+ * @param array $field
25
+ * @return string
26
+ */
27
+ static function html( $meta, $field )
28
+ {
29
+ $attributes = self::get_attributes( $field, $meta );
30
+ $html = sprintf(
31
+ '<select %s>',
32
+ self::render_attributes( $attributes )
33
+ );
34
+ $html .= '<option></option>';
35
+ $html .= self::options_html( $field, $meta );
36
+ $html .= '</select>';
37
+ $html .= self::get_select_all_html( $field['multiple'] );
38
+ return $html;
39
+ }
40
 
41
+ /**
42
+ * Normalize parameters for field
43
+ *
44
+ * @param array $field
45
+ * @return array
46
+ */
47
+ static function normalize( $field )
48
+ {
49
+ $field = wp_parse_args( $field, array(
50
+ 'js_options' => array(),
51
+ 'placeholder' => 'Select an item'
52
+ ) );
53
 
54
+ $field = parent::normalize( $field );
 
55
 
56
+ $field['js_options'] = wp_parse_args( $field['js_options'], array(
57
+ 'allowClear' => true,
58
+ 'width' => 'none',
59
+ 'placeholder' => $field['placeholder'],
60
+ ) );
 
 
 
 
 
61
 
62
+ return $field;
63
+ }
 
64
 
65
+ /**
66
+ * Get the attributes for a field
67
+ *
68
+ * @param array $field
69
+ * @param mixed $value
70
+ * @return array
71
+ */
72
+ static function get_attributes( $field, $value = null )
73
+ {
74
+ $attributes = parent::get_attributes( $field, $value );
75
+ $attributes = wp_parse_args( $attributes, array(
76
+ 'data-options' => wp_json_encode( $field['js_options'] ),
77
+ ) );
78
 
79
+ return $attributes;
 
80
  }
81
  }
inc/fields/select.php CHANGED
@@ -1,217 +1,193 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Select_Field' ) )
6
  {
7
- class RWMB_Select_Field extends RWMB_Field
 
 
 
8
  {
9
- /**
10
- * Enqueue scripts and styles
11
- *
12
- * @return void
13
- */
14
- static function admin_enqueue_scripts()
15
- {
16
- wp_enqueue_style( 'rwmb-select', RWMB_CSS_URL . 'select.css', array(), RWMB_VER );
17
- wp_enqueue_script( 'rwmb-select', RWMB_JS_URL . 'select.js', array(), RWMB_VER, true );
18
- }
19
 
20
- /**
21
- * Get field HTML
22
- *
23
- * @param mixed $meta
24
- * @param array $field
25
- *
26
- * @return string
27
- */
28
- static function html( $meta, $field )
29
- {
30
- $html = sprintf(
31
- '<select %s>',
32
- self::render_attributes( $field['attributes'] )
33
- );
 
34
 
35
- $html .= self::options_html( $field, $meta );
36
 
37
- $html .= '</select>';
38
 
39
- $html .= self::get_select_all_html( $field['multiple'] );
40
 
41
- return $html;
42
- }
43
 
44
- /**
45
- * Save meta value
46
- * If field is cloneable, value is saved as a single entry in DB
47
- * Otherwise value is saved as multiple entries (for backward compatibility)
48
- *
49
- * @param $new
50
- * @param $old
51
- * @param $post_id
52
- * @param $field
53
- *
54
- * @return void
55
- */
56
- static function save( $new, $old, $post_id, $field )
57
- {
58
- if ( ! $field['clone'] )
59
- {
60
- parent::save( $new, $old, $post_id, $field );
61
 
62
- return;
63
- }
 
 
 
 
 
 
 
 
 
 
 
64
 
65
- if ( empty( $new ) )
66
- delete_post_meta( $post_id, $field['id'] );
67
- else
68
- update_post_meta( $post_id, $field['id'], $new );
69
- }
70
 
71
- /**
72
- * Normalize parameters for field
73
- *
74
- * @param array $field
75
- *
76
- * @return array
77
- */
78
- static function normalize_field( $field )
79
- {
80
- if ( ! $field['clone'] && $field['multiple'] )
81
- $field['field_name'] .= '[]';
82
-
83
- $field = parent::normalize_field( $field );
84
- $field = wp_parse_args( $field, array(
85
- 'size' => $field['multiple'] ? 5 : 0,
86
- ) );
87
-
88
- $field['attributes'] = wp_parse_args( $field['attributes'], array(
89
- 'multiple' => $field['multiple'],
90
- 'size' => $field['size'],
91
- ) );
92
-
93
- return $field;
94
- }
95
 
96
- /**
97
- * Creates html for options
98
- *
99
- * @param array $field
100
- * @param mixed $meta
101
- *
102
- * @return array
103
- */
104
- static function options_html( $field, $meta )
105
- {
106
- $html = '';
107
- if ( $field['placeholder'] )
108
- {
109
- $show_placeholder = ( 'select' === $field['type'] ) // Normal select field
110
- || ( isset( $field['field_type'] ) && 'select' === $field['field_type'] ) // For 'post' field
111
- || ( isset( $field['display_type'] ) && 'select' === $field['display_type'] ); // For 'taxonomy' field
112
- $html = $show_placeholder ? "<option value=''>{$field['placeholder']}</option>" : '<option></option>';
113
- }
114
 
115
- $option = '<option value="%s"%s>%s</option>';
 
 
 
 
 
 
 
 
 
 
116
 
117
- foreach ( $field['options'] as $value => $label )
118
- {
119
- $html .= sprintf(
120
- $option,
121
- $value,
122
- selected( in_array( $value, (array) $meta ), true, false ),
123
- $label
124
- );
125
- }
126
 
127
- return $html;
 
 
 
 
 
 
 
128
  }
129
 
130
- /**
131
- * Output the field value
132
- * Display unordered list of option labels, not option values
133
- *
134
- * @param array $field Field parameters
135
- * @param array $args Additional arguments. Not used for these fields.
136
- * @param int|null $post_id Post ID. null for current post. Optional.
137
- *
138
- * @return string Link(s) to post
139
- */
140
- static function the_value( $field, $args = array(), $post_id = null )
141
- {
142
- $value = self::get_value( $field, $args, $post_id );
143
- if ( ! $value )
144
- return '';
145
 
146
- $function = array( RW_Meta_Box::get_class_name( $field ), 'get_option_label' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
- if ( $field['clone'] )
 
 
 
 
 
149
  {
150
- $output = '<ul>';
151
- if ( $field['multiple'] )
152
- {
153
- foreach ( $value as $subvalue )
154
- {
155
- $output .= '<li>';
156
- array_walk_recursive( $subvalue, $function, $field );
157
- $output .= '<ul><li>' . implode( '</li><li>', $subvalue ) . '</li></ul>';
158
- $output .= '</li>';
159
- }
160
- }
161
- else
162
  {
163
- array_walk_recursive( $value, $function, $field );
164
- $output = '<li>' . implode( '</li><li>', $value ) . '</li>';
 
 
165
  }
166
- $output .= '</ul>';
167
  }
168
  else
169
  {
170
- if ( $field['multiple'] )
171
- {
172
- array_walk_recursive( $value, $function, $field );
173
- $output = '<ul><li>' . implode( '</li><li>', $value ) . '</li></ul>';
174
- }
175
- else
176
- {
177
- call_user_func_array( $function, array( &$value, 0, $field ) );
178
- $output = $value;
179
- }
180
  }
181
-
182
- return $output;
183
  }
184
-
185
- /**
186
- * Get option label to display in the frontend
187
- *
188
- * @param int $value Option value
189
- * @param int $index Array index
190
- * @param array $field Field parameter
191
- *
192
- * @return string
193
- */
194
- static function get_option_label( &$value, $index, $field )
195
  {
196
- $value = $field['options'][$value];
 
 
 
 
 
 
 
 
 
197
  }
198
 
199
- /**
200
- * Get html for select all|none for multiple select
201
- *
202
- * @param $multiple
203
- *
204
- * @return string
205
- */
206
- static function get_select_all_html( $multiple )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  {
208
- if ( $multiple === true )
209
- {
210
- return '<div class="rwmb-select-all-none">
211
- ' . __( 'Select', 'meta-box' ) . ': <a data-type="all" href="#">' . __( 'All', 'meta-box' ) . '</a> | <a data-type="none" href="#">' . __( 'None', 'meta-box' ) . '</a>
212
- </div>';
213
- }
214
- return '';
215
  }
 
216
  }
217
  }
1
  <?php
2
+ /**
3
+ * Select field class.
4
+ */
5
+ class RWMB_Select_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ */
10
+ static function admin_enqueue_scripts()
11
  {
12
+ wp_enqueue_style( 'rwmb-select', RWMB_CSS_URL . 'select.css', array(), RWMB_VER );
13
+ wp_enqueue_script( 'rwmb-select', RWMB_JS_URL . 'select.js', array(), RWMB_VER, true );
14
+ }
 
 
 
 
 
 
 
15
 
16
+ /**
17
+ * Get field HTML
18
+ *
19
+ * @param mixed $meta
20
+ * @param array $field
21
+ *
22
+ * @return string
23
+ */
24
+ static function html( $meta, $field )
25
+ {
26
+ $attributes = call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'get_attributes' ), $field, $meta );
27
+ $html = sprintf(
28
+ '<select %s>',
29
+ self::render_attributes( $attributes )
30
+ );
31
 
32
+ $html .= $field['placeholder'] ? "<option value=''>{$field['placeholder']}</option>" : '<option></option>';
33
 
34
+ $html .= self::options_html( $field, $meta );
35
 
36
+ $html .= '</select>';
37
 
38
+ $html .= self::get_select_all_html( $field['multiple'] );
 
39
 
40
+ return $html;
41
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
+ /**
44
+ * Normalize parameters for field
45
+ *
46
+ * @param array $field
47
+ *
48
+ * @return array
49
+ */
50
+ static function normalize( $field )
51
+ {
52
+ $field = parent::normalize( $field );
53
+ $field = wp_parse_args( $field, array(
54
+ 'size' => $field['multiple'] ? 5 : 0,
55
+ ) );
56
 
57
+ $field['field_name'] .= ! $field['clone'] && $field['multiple'] ? '[]' : '';
58
+ return $field;
59
+ }
 
 
60
 
61
+ /**
62
+ * Get the attributes for a field
63
+ *
64
+ * @param array $field
65
+ * @param mixed $value
66
+ *
67
+ * @return array
68
+ */
69
+ static function get_attributes( $field, $value = null )
70
+ {
71
+ $attributes = parent::get_attributes( $field, $value );
72
+ $attributes = wp_parse_args( $attributes, array(
73
+ 'multiple' => $field['multiple'],
74
+ 'size' => $field['size'],
75
+ ) );
 
 
 
 
 
 
 
 
 
76
 
77
+ return $attributes;
78
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
+ /**
81
+ * Creates html for options
82
+ *
83
+ * @param array $field
84
+ * @param mixed $meta
85
+ *
86
+ * @return array
87
+ */
88
+ static function options_html( $field, $meta )
89
+ {
90
+ $html = '';
91
 
92
+ $option = '<option value="%s"%s>%s</option>';
 
 
 
 
 
 
 
 
93
 
94
+ foreach ( $field['options'] as $value => $label )
95
+ {
96
+ $html .= sprintf(
97
+ $option,
98
+ $value,
99
+ selected( in_array( (string) $value, (array) $meta, true ), true, false ),
100
+ $label
101
+ );
102
  }
103
 
104
+ return $html;
105
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
+ /**
108
+ * Output the field value
109
+ * Display unordered list of option labels, not option values
110
+ *
111
+ * @param array $field Field parameters
112
+ * @param array $args Additional arguments. Not used for these fields.
113
+ * @param int|null $post_id Post ID. null for current post. Optional.
114
+ *
115
+ * @return string Link(s) to post
116
+ */
117
+ static function the_value( $field, $args = array(), $post_id = null )
118
+ {
119
+ $value = self::get_value( $field, $args, $post_id );
120
+ if ( ! $value )
121
+ return '';
122
 
123
+ $function = array( RW_Meta_Box::get_class_name( $field ), 'get_option_label' );
124
+
125
+ if ( $field['clone'] )
126
+ {
127
+ $output = '<ul>';
128
+ if ( $field['multiple'] )
129
  {
130
+ foreach ( $value as $subvalue )
 
 
 
 
 
 
 
 
 
 
 
131
  {
132
+ $output .= '<li>';
133
+ array_walk_recursive( $subvalue, $function, $field );
134
+ $output .= '<ul><li>' . implode( '</li><li>', $subvalue ) . '</li></ul>';
135
+ $output .= '</li>';
136
  }
 
137
  }
138
  else
139
  {
140
+ array_walk_recursive( $value, $function, $field );
141
+ $output = '<li>' . implode( '</li><li>', $value ) . '</li>';
 
 
 
 
 
 
 
 
142
  }
143
+ $output .= '</ul>';
 
144
  }
145
+ else
 
 
 
 
 
 
 
 
 
 
146
  {
147
+ if ( $field['multiple'] )
148
+ {
149
+ array_walk_recursive( $value, $function, $field );
150
+ $output = '<ul><li>' . implode( '</li><li>', $value ) . '</li></ul>';
151
+ }
152
+ else
153
+ {
154
+ call_user_func_array( $function, array( &$value, 0, $field ) );
155
+ $output = $value;
156
+ }
157
  }
158
 
159
+ return $output;
160
+ }
161
+
162
+ /**
163
+ * Get option label to display in the frontend
164
+ *
165
+ * @param int $value Option value
166
+ * @param int $index Array index
167
+ * @param array $field Field parameter
168
+ *
169
+ * @return string
170
+ */
171
+ static function get_option_label( &$value, $index, $field )
172
+ {
173
+ $value = $field['options'][$value];
174
+ }
175
+
176
+ /**
177
+ * Get html for select all|none for multiple select
178
+ *
179
+ * @param $multiple
180
+ *
181
+ * @return string
182
+ */
183
+ static function get_select_all_html( $multiple )
184
+ {
185
+ if ( $multiple === true )
186
  {
187
+ return '<div class="rwmb-select-all-none">
188
+ ' . __( 'Select', 'meta-box' ) . ': <a data-type="all" href="#">' . __( 'All', 'meta-box' ) . '</a> | <a data-type="none" href="#">' . __( 'None', 'meta-box' ) . '</a>
189
+ </div>';
 
 
 
 
190
  }
191
+ return '';
192
  }
193
  }
inc/fields/slider.php CHANGED
@@ -1,68 +1,66 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Slider_Field' ) )
6
  {
7
- class RWMB_Slider_Field extends RWMB_Field
 
 
 
 
 
8
  {
9
- /**
10
- * Enqueue scripts and styles
11
- *
12
- * @return void
13
- */
14
- static function admin_enqueue_scripts()
15
- {
16
- $url = RWMB_CSS_URL . 'jqueryui';
17
- wp_enqueue_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
18
- wp_enqueue_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
19
- wp_enqueue_style( 'jquery-ui-slider', "{$url}/jquery.ui.slider.css", array(), '1.8.17' );
20
- wp_enqueue_style( 'rwmb-slider', RWMB_CSS_URL . 'slider.css' );
21
 
22
- wp_enqueue_script( 'rwmb-slider', RWMB_JS_URL . 'slider.js', array( 'jquery-ui-slider', 'jquery-ui-widget', 'jquery-ui-mouse', 'jquery-ui-core' ), RWMB_VER, true );
23
- }
24
 
25
- /**
26
- * Get div HTML
27
- *
28
- * @param mixed $meta
29
- * @param array $field
30
- *
31
- * @return string
32
- */
33
- static function html( $meta, $field )
34
- {
35
- return sprintf(
36
- '<div class="clearfix">
37
- <div class="rwmb-slider" id="%s" data-options="%s"></div>
38
- <span class="rwmb-slider-value-label">%s<span>%s</span>%s</span>
39
- <input type="hidden" name="%s" value="%s" class="rwmb-slider-value">
40
- </div>',
41
- $field['id'], esc_attr( wp_json_encode( $field['js_options'] ) ),
42
- $field['prefix'], $meta, $field['suffix'],
43
- $field['field_name'], $meta
44
- );
45
- }
46
 
47
- /**
48
- * Normalize parameters for field
49
- *
50
- * @param array $field
51
- *
52
- * @return array
53
- */
54
- static function normalize_field( $field )
55
- {
56
- $field = wp_parse_args( $field, array(
57
- 'prefix' => '',
58
- 'suffix' => '',
59
- 'js_options' => array(),
60
- ) );
61
- $field['js_options'] = wp_parse_args( $field['js_options'], array(
62
- 'range' => 'min', // range = 'min' will add a dark background to sliding part, better UI
63
- ) );
 
64
 
65
- return $field;
66
- }
67
  }
68
  }
1
  <?php
2
+ /**
3
+ * jQueryUI slider field class.
4
+ */
5
+ class RWMB_Slider_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ *
10
+ * @return void
11
+ */
12
+ static function admin_enqueue_scripts()
13
  {
14
+ $url = RWMB_CSS_URL . 'jqueryui';
15
+ wp_enqueue_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
16
+ wp_enqueue_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
17
+ wp_enqueue_style( 'jquery-ui-slider', "{$url}/jquery.ui.slider.css", array(), '1.8.17' );
18
+ wp_enqueue_style( 'rwmb-slider', RWMB_CSS_URL . 'slider.css' );
 
 
 
 
 
 
 
19
 
20
+ wp_enqueue_script( 'rwmb-slider', RWMB_JS_URL . 'slider.js', array( 'jquery-ui-slider', 'jquery-ui-widget', 'jquery-ui-mouse', 'jquery-ui-core' ), RWMB_VER, true );
21
+ }
22
 
23
+ /**
24
+ * Get div HTML
25
+ *
26
+ * @param mixed $meta
27
+ * @param array $field
28
+ *
29
+ * @return string
30
+ */
31
+ static function html( $meta, $field )
32
+ {
33
+ return sprintf(
34
+ '<div class="clearfix">
35
+ <div class="rwmb-slider" id="%s" data-options="%s"></div>
36
+ <span class="rwmb-slider-value-label">%s<span>%s</span>%s</span>
37
+ <input type="hidden" name="%s" value="%s" class="rwmb-slider-value">
38
+ </div>',
39
+ $field['id'], esc_attr( wp_json_encode( $field['js_options'] ) ),
40
+ $field['prefix'], $meta, $field['suffix'],
41
+ $field['field_name'], $meta
42
+ );
43
+ }
44
 
45
+ /**
46
+ * Normalize parameters for field
47
+ *
48
+ * @param array $field
49
+ *
50
+ * @return array
51
+ */
52
+ static function normalize( $field )
53
+ {
54
+ $field = parent::normalize( $field );
55
+ $field = wp_parse_args( $field, array(
56
+ 'prefix' => '',
57
+ 'suffix' => '',
58
+ 'js_options' => array(),
59
+ ) );
60
+ $field['js_options'] = wp_parse_args( $field['js_options'], array(
61
+ 'range' => 'min', // range = 'min' will add a dark background to sliding part, better UI
62
+ ) );
63
 
64
+ return $field;
 
65
  }
66
  }
inc/fields/taxonomy-advanced.php CHANGED
@@ -1,93 +1,89 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
- require_once RWMB_FIELDS_DIR . 'taxonomy.php';
5
-
6
- if ( ! class_exists( 'RWMB_Taxonomy_Advanced_Field' ) )
7
  {
8
- class RWMB_Taxonomy_Advanced_Field extends RWMB_Taxonomy_Field
 
 
 
 
 
 
 
 
 
 
 
 
9
  {
10
- /**
11
- * Get meta values to save
12
- * Save terms in custom field, no more by setting post terms
13
- * Save in form of comma-separated IDs
14
- *
15
- * @param mixed $new
16
- * @param mixed $old
17
- * @param int $post_id
18
- * @param array $field
19
- *
20
- * @return string
21
- */
22
- static function value( $new, $old, $post_id, $field )
23
- {
24
- return implode( ',', array_unique( $new ) );
25
- }
26
 
27
- /**
28
- * Save meta value
29
- *
30
- * @param mixed $new
31
- * @param mixed $old
32
- * @param int $post_id
33
- * @param array $field
34
- *
35
- * @return string
36
- */
37
- static function save( $new, $old, $post_id, $field )
38
- {
39
- if ( $new )
40
- update_post_meta( $post_id, $field['id'], $new );
41
- else
42
- delete_post_meta( $post_id, $field['id'] );
43
- }
44
 
45
- /**
46
- * Standard meta retrieval
47
- *
48
- * @param int $post_id
49
- * @param bool $saved
50
- * @param array $field
51
- *
52
- * @return array
53
- */
54
- static function meta( $post_id, $saved, $field )
55
- {
56
- $meta = get_post_meta( $post_id, $field['id'], true );
57
- $meta = wp_parse_id_list( $meta );
58
- return $meta;
59
- }
60
 
61
- /**
62
- * Get the field value
63
- * Return list of post term objects
64
- *
65
- * @param array $field Field parameters
66
- * @param array $args Additional arguments. Rarely used. See specific fields for details
67
- * @param int|null $post_id Post ID. null for current post. Optional.
68
- *
69
- * @return array List of post term objects
70
- */
71
- static function get_value( $field, $args = array(), $post_id = null )
72
- {
73
- if ( ! $post_id )
74
- $post_id = get_the_ID();
75
 
76
- $value = self::meta( $post_id, '', $field );
77
 
78
- // Allow to pass more arguments to "get_terms"
79
- $args = wp_parse_args( array(
80
- 'include' => $value,
81
- 'hide_empty' => false,
82
- ), $args );
83
- $value = get_terms( $field['options']['taxonomy'], $args );
84
 
85
- // Get single value if necessary
86
- if ( ! $field['clone'] && ! $field['multiple'] )
87
- {
88
- $value = reset( $value );
89
- }
90
- return $value;
91
  }
 
92
  }
93
  }
1
  <?php
2
+ /**
3
+ * Taxonomy advanced field class which saves terms' IDs in the post meta.
4
+ */
5
+ class RWMB_Taxonomy_Advanced_Field extends RWMB_Taxonomy_Field
 
6
  {
7
+ /**
8
+ * Get meta values to save
9
+ * Save terms in custom field, no more by setting post terms
10
+ * Save in form of comma-separated IDs
11
+ *
12
+ * @param mixed $new
13
+ * @param mixed $old
14
+ * @param int $post_id
15
+ * @param array $field
16
+ *
17
+ * @return string
18
+ */
19
+ static function value( $new, $old, $post_id, $field )
20
  {
21
+ return is_array( $new ) ? implode( ',', array_unique( $new ) ) : null;
22
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
+ /**
25
+ * Save meta value
26
+ *
27
+ * @param mixed $new
28
+ * @param mixed $old
29
+ * @param int $post_id
30
+ * @param array $field
31
+ *
32
+ * @return string
33
+ */
34
+ static function save( $new, $old, $post_id, $field )
35
+ {
36
+ if ( $new )
37
+ update_post_meta( $post_id, $field['id'], $new );
38
+ else
39
+ delete_post_meta( $post_id, $field['id'] );
40
+ }
41
 
42
+ /**
43
+ * Standard meta retrieval
44
+ *
45
+ * @param int $post_id
46
+ * @param bool $saved
47
+ * @param array $field
48
+ *
49
+ * @return array
50
+ */
51
+ static function meta( $post_id, $saved, $field )
52
+ {
53
+ $meta = get_post_meta( $post_id, $field['id'], true );
54
+ $meta = wp_parse_id_list( $meta );
55
+ return $meta;
56
+ }
57
 
58
+ /**
59
+ * Get the field value
60
+ * Return list of post term objects
61
+ *
62
+ * @param array $field Field parameters
63
+ * @param array $args Additional arguments. Rarely used. See specific fields for details
64
+ * @param int|null $post_id Post ID. null for current post. Optional.
65
+ *
66
+ * @return array List of post term objects
67
+ */
68
+ static function get_value( $field, $args = array(), $post_id = null )
69
+ {
70
+ if ( ! $post_id )
71
+ $post_id = get_the_ID();
72
 
73
+ $value = self::meta( $post_id, '', $field );
74
 
75
+ // Allow to pass more arguments to "get_terms"
76
+ $args = wp_parse_args( array(
77
+ 'include' => $value,
78
+ 'hide_empty' => false,
79
+ ), $args );
80
+ $value = get_terms( $field['options']['taxonomy'], $args );
81
 
82
+ // Get single value if necessary
83
+ if ( ! $field['clone'] && ! $field['multiple'] )
84
+ {
85
+ $value = reset( $value );
 
 
86
  }
87
+ return $value;
88
  }
89
  }
inc/fields/taxonomy.php CHANGED
@@ -1,324 +1,182 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
- require_once RWMB_FIELDS_DIR . 'select-advanced.php';
5
- require_once RWMB_FIELDS_DIR . 'checkbox-list.php';
6
-
7
- if ( ! class_exists( 'RWMB_Taxonomy_Field' ) )
8
  {
9
- class RWMB_Taxonomy_Field extends RWMB_Field
 
 
 
 
 
 
10
  {
11
  /**
12
- * Enqueue scripts and styles
13
- *
14
- * @return void
15
  */
16
- static function admin_enqueue_scripts()
17
- {
18
- RWMB_Select_Advanced_Field::admin_enqueue_scripts();
19
- wp_enqueue_style( 'rwmb-taxonomy', RWMB_CSS_URL . 'taxonomy.css', array(), RWMB_VER );
20
- wp_enqueue_script( 'rwmb-taxonomy', RWMB_JS_URL . 'taxonomy.js', array( 'rwmb-select-advanced' ), RWMB_VER, true );
21
- }
22
 
23
  /**
24
- * Add default value for 'taxonomy' field
25
- *
26
- * @param $field
27
- *
28
- * @return array
29
  */
30
- static function normalize_field( $field )
31
- {
32
- $default_args = array(
33
- 'hide_empty' => false,
34
- );
35
-
36
- // Set default args
37
- $field['options']['args'] = ! isset( $field['options']['args'] ) ? $default_args : wp_parse_args( $field['options']['args'], $default_args );
38
-
39
- $tax = get_taxonomy( $field['options']['taxonomy'] );
40
- $field['placeholder'] = empty( $field['placeholder'] ) ? sprintf( __( 'Select a %s', 'meta-box' ), $tax->labels->singular_name ) : $field['placeholder'];
41
-
42
- switch ( $field['options']['type'] )
43
- {
44
- case 'select_advanced':
45
- $field = RWMB_Select_Advanced_Field::normalize_field( $field );
46
- break;
47
- case 'checkbox_list':
48
- case 'checkbox_tree':
49
- $field = RWMB_Checkbox_List_Field::normalize_field( $field );
50
- break;
51
- case 'select':
52
- case 'select_tree':
53
- $field = RWMB_Select_Field::normalize_field( $field );
54
- break;
55
- default:
56
- $field['options']['type'] = 'select';
57
- $field = RWMB_Select_Field::normalize_field( $field );
58
- }
59
-
60
- if ( in_array( $field['options']['type'], array( 'checkbox_tree', 'select_tree' ) ) )
61
- {
62
- if ( isset( $field['options']['args']['parent'] ) )
63
- {
64
- $field['options']['parent'] = $field['options']['args']['parent'];
65
- unset( $field['options']['args']['parent'] );
66
- }
67
- else
68
- {
69
- $field['options']['parent'] = 0;
70
- }
71
- }
72
-
73
- $field['field_name'] = "{$field['id']}[]";
74
-
75
- return $field;
76
- }
77
 
78
  /**
79
- * Get field HTML
80
- *
81
- * @param $field
82
- * @param $meta
83
- *
84
- * @return string
85
  */
86
- static function html( $meta, $field )
87
- {
88
- $options = $field['options'];
89
- $terms = get_terms( $options['taxonomy'], $options['args'] );
90
-
91
- $field['options'] = self::get_options( $terms );
92
- $field['display_type'] = $options['type'];
93
-
94
- $html = '';
95
-
96
- switch ( $options['type'] )
97
- {
98
- case 'checkbox_list':
99
- $html = RWMB_Checkbox_List_Field::html( $meta, $field );
100
- break;
101
- case 'checkbox_tree':
102
- $elements = self::process_terms( $terms );
103
- $html .= self::walk_checkbox_tree( $meta, $field, $elements, $options['parent'], true );
104
- break;
105
- case 'select_tree':
106
- $elements = self::process_terms( $terms );
107
- $html .= self::walk_select_tree( $meta, $field, $elements, $options['parent'], true );
108
- break;
109
- case 'select_advanced':
110
- $html = RWMB_Select_Advanced_Field::html( $meta, $field );
111
- break;
112
- case 'select':
113
- default:
114
- $html = RWMB_Select_Field::html( $meta, $field );
115
- }
116
-
117
- return $html;
118
- }
119
-
120
- /**
121
- * Walker for displaying checkboxes in tree format
122
- *
123
- * @param $meta
124
- * @param $field
125
- * @param $elements
126
- * @param int $parent
127
- * @param bool $active
128
- *
129
- * @return string
130
- */
131
- static function walk_checkbox_tree( $meta, $field, $elements, $parent = 0, $active = false )
132
- {
133
- if ( ! isset( $elements[$parent] ) )
134
- return '';
135
- $terms = $elements[$parent];
136
- $field['options'] = self::get_options( $terms );
137
- $hidden = $active ? '' : 'hidden';
138
-
139
- $html = "<ul class = 'rw-taxonomy-tree {$hidden}'>";
140
- $li = '<li><label><input type="checkbox" name="%s" value="%s"%s> %s</label>';
141
- foreach ( $terms as $term )
142
- {
143
- $html .= sprintf(
144
- $li,
145
- $field['field_name'],
146
- $term->term_id,
147
- checked( in_array( $term->term_id, $meta ), true, false ),
148
- $term->name
149
- );
150
- $html .= self::walk_checkbox_tree( $meta, $field, $elements, $term->term_id, $active && in_array( $term->term_id, $meta ) ) . '</li>';
151
- }
152
- $html .= '</ul>';
153
-
154
- return $html;
155
- }
156
 
157
  /**
158
- * Walker for displaying select in tree format
159
- *
160
- * @param $meta
161
- * @param $field
162
- * @param $elements
163
- * @param int $parent
164
- * @param bool $active
165
- *
166
- * @return string
167
  */
168
- static function walk_select_tree( $meta, $field, $elements, $parent = 0, $active = false )
169
  {
170
- if ( ! isset( $elements[$parent] ) )
171
- return '';
172
- $meta = empty( $meta ) ? array() : ( ! is_array( $meta ) ? array() : $meta );
173
- $terms = $elements[$parent];
174
- $field['options'] = self::get_options( $terms );
175
-
176
- $classes = array( 'rw-taxonomy-tree' );
177
- $classes[] = $active ? 'active' : 'disabled';
178
- $classes[] = "rwmb-taxonomy-{$parent}";
179
-
180
- $html = '<div class="' . implode( ' ', $classes ) . '">';
181
- $html .= RWMB_Select_Field::html( $meta, $field );
182
- foreach ( $terms as $term )
183
  {
184
- $html .= self::walk_select_tree( $meta, $field, $elements, $term->term_id, $active && in_array( $term->term_id, $meta ) );
 
185
  }
186
- $html .= '</div>';
187
-
188
- return $html;
189
  }
190
 
191
  /**
192
- * Processes terms into indexed array for walker functions
193
- *
194
- * @param $terms
195
- *
196
- * @internal param $field
197
- * @return array
198
  */
199
- static function process_terms( $terms )
200
- {
201
- $elements = array();
202
- foreach ( $terms as $term )
203
- {
204
- $elements[$term->parent][] = $term;
205
- }
206
 
207
- return $elements;
208
- }
 
209
 
210
- /**
211
- * Get options for selects, checkbox list, etc via the terms
212
- *
213
- * @param array $terms Array of term objects
214
- *
215
- * @return array
216
- */
217
- static function get_options( $terms = array() )
218
- {
219
- $options = array();
220
- foreach ( $terms as $term )
221
- {
222
- $options[$term->term_id] = $term->name;
223
- }
224
 
225
- return $options;
226
- }
 
 
 
 
 
 
 
 
 
 
227
 
228
- /**
229
- * Save meta value
230
- *
231
- * @param mixed $new
232
- * @param mixed $old
233
- * @param int $post_id
234
- * @param array $field
235
- *
236
- * @return string
237
- */
238
- static function save( $new, $old, $post_id, $field )
239
- {
240
- $new = array_unique( array_map( 'intval', (array) $new ) );
241
- $new = empty( $new ) ? null : $new;
242
- wp_set_object_terms( $post_id, $new, $field['options']['taxonomy'] );
243
- }
244
 
245
- /**
246
- * Standard meta retrieval
247
- *
248
- * @param int $post_id
249
- * @param bool $saved
250
- * @param array $field
251
- *
252
- * @return array
253
- */
254
- static function meta( $post_id, $saved, $field )
255
- {
256
- $options = $field['options'];
 
 
257
 
258
- $meta = get_the_terms( $post_id, $options['taxonomy'] );
259
- $meta = is_array( $meta ) ? $meta : (array) $meta;
260
- $meta = wp_list_pluck( $meta, 'term_id' );
261
 
262
- return $meta;
263
- }
 
 
 
 
 
 
 
 
 
 
 
264
 
265
- /**
266
- * Get the field value
267
- * Return list of post term objects
268
- *
269
- * @param array $field Field parameters
270
- * @param array $args Additional arguments. Rarely used. See specific fields for details
271
- * @param int|null $post_id Post ID. null for current post. Optional.
272
- *
273
- * @return array List of post term objects
274
- */
275
- static function get_value( $field, $args = array(), $post_id = null )
276
  {
277
- if ( ! $post_id )
278
- $post_id = get_the_ID();
279
-
280
- $value = wp_get_post_terms( $post_id, $field['options']['taxonomy'] );
281
-
282
- // Get single value if necessary
283
- if ( ! $field['clone'] && ! $field['multiple'] )
284
- {
285
- $value = reset( $value );
286
- }
287
- return $value;
288
  }
 
 
289
 
290
- /**
291
- * Output the field value
292
- * Display unordered list of option labels, not option values
293
- *
294
- * @param array $field Field parameters
295
- * @param array $args Additional arguments. Not used for these fields.
296
- * @param int|null $post_id Post ID. null for current post. Optional.
297
- *
298
- * @return string Link(s) to post
299
- */
300
- static function the_value( $field, $args = array(), $post_id = null )
301
- {
302
- return RWMB_Select_Field::the_value( $field, $args, $post_id );
303
- }
304
 
305
- /**
306
- * Get post link to display in the frontend
307
- *
308
- * @param object $value Option value, e.g. term object
309
- * @param int $index Array index
310
- * @param array $field Field parameter
311
- *
312
- * @return string
313
- */
314
- static function get_option_label( &$value, $index, $field )
315
- {
316
- $value = sprintf(
317
- '<a href="%s" title="%s">%s</a>',
318
- esc_url( get_term_link( $value ) ),
319
- esc_attr( $value->name ),
320
- $value->name
321
- );
322
- }
323
  }
324
  }
1
  <?php
2
+ /**
3
+ * Taxonomy field class which set post terms when saving.
4
+ */
5
+ class RWMB_Taxonomy_Field extends RWMB_Object_Choice_Field
 
 
6
  {
7
+ /**
8
+ * Add default value for 'taxonomy' field
9
+ *
10
+ * @param $field
11
+ * @return array
12
+ */
13
+ static function normalize( $field )
14
  {
15
  /**
16
+ * Backwards compatibility with field args
 
 
17
  */
18
+ if ( isset( $field['options']['args'] ) )
19
+ $field['query_args'] = $field['options']['args'];
20
+ if ( isset( $field['options']['taxonomy'] ) )
21
+ $field['taxonomy'] = $field['options']['taxonomy'];
22
+ if ( isset( $field['options']['type'] ) )
23
+ $field['field_type'] = $field['options']['type'];
24
 
25
  /**
26
+ * Set default field args
 
 
 
 
27
  */
28
+ $field = wp_parse_args( $field, array(
29
+ 'taxonomy' => 'category',
30
+ 'field_type' => 'select',
31
+ 'query_args' => array(),
32
+ ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  /**
35
+ * Set default query args
 
 
 
 
 
36
  */
37
+ $field['query_args'] = wp_parse_args( $field['query_args'], array(
38
+ 'hide_empty' => false,
39
+ ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  /**
42
+ * Set default placeholder
43
+ * - If multiple taxonomies: show 'Select a term'
44
+ * - If single taxonomy: show 'Select a %taxonomy_name%'
 
 
 
 
 
 
45
  */
46
+ if ( empty( $field['placeholder'] ) )
47
  {
48
+ $field['placeholder'] = __( 'Select a term', 'meta-box' );
49
+ if ( is_string( $field['taxonomy'] ) && taxonomy_exists( $field['taxonomy'] ) )
 
 
 
 
 
 
 
 
 
 
 
50
  {
51
+ $taxonomy_object = get_taxonomy( $field['taxonomy'] );
52
+ $field['placeholder'] = sprintf( __( 'Select a %s', 'meta-box' ), $taxonomy_object->labels->singular_name );
53
  }
 
 
 
54
  }
55
 
56
  /**
57
+ * Prevent cloning for taxonomy field
 
 
 
 
 
58
  */
59
+ $field['clone'] = false;
 
 
 
 
 
 
60
 
61
+ $field = parent::normalize( $field );
62
+ return $field;
63
+ }
64
 
65
+ /**
66
+ * Get field names of object to be used by walker
67
+ *
68
+ * @return array
69
+ */
70
+ static function get_db_fields()
71
+ {
72
+ return array(
73
+ 'parent' => 'parent',
74
+ 'id' => 'term_id',
75
+ 'label' => 'name',
76
+ );
77
+ }
 
78
 
79
+ /**
80
+ * Get options for selects, checkbox list, etc via the terms
81
+ *
82
+ * @param array $field Field parameters
83
+ *
84
+ * @return array
85
+ */
86
+ static function get_options( $field )
87
+ {
88
+ $options = get_terms( $field['taxonomy'], $field['query_args'] );
89
+ return $options;
90
+ }
91
 
92
+ /**
93
+ * Save meta value
94
+ *
95
+ * @param mixed $new
96
+ * @param mixed $old
97
+ * @param int $post_id
98
+ * @param array $field
99
+ *
100
+ * @return string
101
+ */
102
+ static function save( $new, $old, $post_id, $field )
103
+ {
104
+ $new = array_unique( array_map( 'intval', (array) $new ) );
105
+ $new = empty( $new ) ? null : $new;
106
+ wp_set_object_terms( $post_id, $new, $field['taxonomy'] );
107
+ }
108
 
109
+ /**
110
+ * Standard meta retrieval
111
+ *
112
+ * @param int $post_id
113
+ * @param bool $saved
114
+ * @param array $field
115
+ *
116
+ * @return array
117
+ */
118
+ static function meta( $post_id, $saved, $field )
119
+ {
120
+ $meta = get_the_terms( $post_id, $field['taxonomy'] );
121
+ $meta = (array) $meta;
122
+ $meta = wp_list_pluck( $meta, 'term_id' );
123
 
124
+ return $meta;
125
+ }
 
126
 
127
+ /**
128
+ * Get the field value
129
+ * Return list of post term objects
130
+ *
131
+ * @param array $field Field parameters
132
+ * @param array $args Additional arguments. Rarely used. See specific fields for details
133
+ * @param int|null $post_id Post ID. null for current post. Optional.
134
+ *
135
+ * @return array List of post term objects
136
+ */
137
+ static function get_value( $field, $args = array(), $post_id = null )
138
+ {
139
+ $value = get_the_terms( $post_id, $field['taxonomy'] );
140
 
141
+ // Get single value if necessary
142
+ if ( ! $field['clone'] && ! $field['multiple'] )
 
 
 
 
 
 
 
 
 
143
  {
144
+ $value = reset( $value );
 
 
 
 
 
 
 
 
 
 
145
  }
146
+ return $value;
147
+ }
148
 
149
+ /**
150
+ * Output the field value
151
+ * Display unordered list of option labels, not option values
152
+ *
153
+ * @param array $field Field parameters
154
+ * @param array $args Additional arguments. Not used for these fields.
155
+ * @param int|null $post_id Post ID. null for current post. Optional.
156
+ *
157
+ * @return string Link(s) to post
158
+ */
159
+ static function the_value( $field, $args = array(), $post_id = null )
160
+ {
161
+ return RWMB_Select_Field::the_value( $field, $args, $post_id );
162
+ }
163
 
164
+ /**
165
+ * Get post link to display in the frontend
166
+ *
167
+ * @param object $value Option value, e.g. term object
168
+ * @param int $index Array index
169
+ * @param array $field Field parameter
170
+ *
171
+ * @return string
172
+ */
173
+ static function get_option_label( &$value, $index, $field )
174
+ {
175
+ $value = sprintf(
176
+ '<a href="%s" title="%s">%s</a>',
177
+ esc_url( get_term_link( $value ) ),
178
+ esc_attr( $value->name ),
179
+ $value->name
180
+ );
 
181
  }
182
  }
inc/fields/text-list.php CHANGED
@@ -1,94 +1,91 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Text_List_Field' ) )
6
  {
7
- class RWMB_Text_List_Field extends RWMB_Field_Multiple_Values
 
 
 
 
 
 
 
 
8
  {
9
- /**
10
- * Get field HTML
11
- *
12
- * @param mixed $meta
13
- * @param array $field
14
- *
15
- * @return string
16
- */
17
- static function html( $meta, $field )
18
  {
19
- $html = array();
20
- $input = '<label><input type="text" class="rwmb-text-list" name="%s" value="%s" placeholder="%s"> %s</label>';
 
 
 
 
 
 
 
21
 
22
- $i = 0;
23
- foreach ( $field['options'] as $placeholder => $label )
24
- {
25
- $html[] = sprintf(
26
- $input,
27
- $field['field_name'],
28
- isset( $meta[$i] ) ? esc_attr( $meta[$i] ) : '',
29
- $placeholder,
30
- $label
31
- );
32
- $i ++;
33
- }
34
 
35
- return implode( ' ', $html );
36
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
- /**
39
- * Output the field value
40
- * Display option name instead of option value
41
- *
42
- * @param array $field Field parameters
43
- * @param array $args Additional arguments. Not used for these fields.
44
- * @param int|null $post_id Post ID. null for current post. Optional.
45
- *
46
- * @return mixed Field value
47
- */
48
- static function the_value( $field, $args = array(), $post_id = null )
49
  {
50
- $value = self::get_value( $field, $args, $post_id );
51
- if ( ! $value )
52
- return '';
53
-
54
- $output = '<ul>';
55
- if ( $field['clone'] )
56
  {
57
- foreach ( $value as $subvalue )
58
- {
59
- $output .= '<li>';
60
- $output .= '<ul>';
61
 
62
- $i = 0;
63
- foreach ( $field['options'] as $placeholder => $label )
64
- {
65
- $output .= sprintf(
66
- '<li><label>%s</label>: %s</li>',
67
- $label,
68
- isset( $subvalue[$i] ) ? $subvalue[$i] : ''
69
- );
70
- $i ++;
71
- }
72
- $output .= '</ul>';
73
- $output .= '</li>';
74
- }
75
- }
76
- else
77
- {
78
  $i = 0;
79
  foreach ( $field['options'] as $placeholder => $label )
80
  {
81
  $output .= sprintf(
82
  '<li><label>%s</label>: %s</li>',
83
  $label,
84
- isset( $value[$i] ) ? $value[$i] : ''
85
  );
86
  $i ++;
87
  }
 
 
88
  }
89
- $output .= '</ul>';
90
-
91
- return $output;
92
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  }
94
  }
1
  <?php
2
+ /**
3
+ * Text list field class.
4
+ */
5
+ class RWMB_Text_List_Field extends RWMB_Multiple_Values_Field
6
  {
7
+ /**
8
+ * Get field HTML
9
+ *
10
+ * @param mixed $meta
11
+ * @param array $field
12
+ *
13
+ * @return string
14
+ */
15
+ static function html( $meta, $field )
16
  {
17
+ $html = array();
18
+ $input = '<label><input type="text" class="rwmb-text-list" name="%s" value="%s" placeholder="%s"> %s</label>';
19
+
20
+ $count = 0;
21
+ foreach ( $field['options'] as $placeholder => $label )
 
 
 
 
22
  {
23
+ $html[] = sprintf(
24
+ $input,
25
+ $field['field_name'],
26
+ isset( $meta[$count] ) ? esc_attr( $meta[$count] ) : '',
27
+ $placeholder,
28
+ $label
29
+ );
30
+ $count ++;
31
+ }
32
 
33
+ return implode( ' ', $html );
34
+ }
 
 
 
 
 
 
 
 
 
 
35
 
36
+ /**
37
+ * Output the field value
38
+ * Display option name instead of option value
39
+ *
40
+ * @param array $field Field parameters
41
+ * @param array $args Additional arguments. Not used for these fields.
42
+ * @param int|null $post_id Post ID. null for current post. Optional.
43
+ *
44
+ * @return mixed Field value
45
+ */
46
+ static function the_value( $field, $args = array(), $post_id = null )
47
+ {
48
+ $value = self::get_value( $field, $args, $post_id );
49
+ if ( ! $value )
50
+ return '';
51
 
52
+ $output = '<ul>';
53
+ if ( $field['clone'] )
 
 
 
 
 
 
 
 
 
54
  {
55
+ foreach ( $value as $subvalue )
 
 
 
 
 
56
  {
57
+ $output .= '<li>';
58
+ $output .= '<ul>';
 
 
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  $i = 0;
61
  foreach ( $field['options'] as $placeholder => $label )
62
  {
63
  $output .= sprintf(
64
  '<li><label>%s</label>: %s</li>',
65
  $label,
66
+ isset( $subvalue[$i] ) ? $subvalue[$i] : ''
67
  );
68
  $i ++;
69
  }
70
+ $output .= '</ul>';
71
+ $output .= '</li>';
72
  }
 
 
 
73
  }
74
+ else
75
+ {
76
+ $i = 0;
77
+ foreach ( $field['options'] as $placeholder => $label )
78
+ {
79
+ $output .= sprintf(
80
+ '<li><label>%s</label>: %s</li>',
81
+ $label,
82
+ isset( $value[$i] ) ? $value[$i] : ''
83
+ );
84
+ $i ++;
85
+ }
86
+ }
87
+ $output .= '</ul>';
88
+
89
+ return $output;
90
  }
91
  }
inc/fields/text.php CHANGED
@@ -1,42 +1,48 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "input" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'input.php';
7
-
8
- if ( ! class_exists( 'RWMB_Text_Field' ) )
9
  {
10
- class RWMB_Text_Field extends RWMB_Input_Field
 
 
 
 
 
 
11
  {
12
- /**
13
- * Normalize parameters for field
14
- *
15
- * @param array $field
16
- *
17
- * @return array
18
- */
19
- static function normalize_field( $field )
20
- {
21
- $field = parent::normalize_field( $field );
22
 
23
- $field = wp_parse_args( $field, array(
24
- 'size' => 30,
25
- 'maxlength' => false,
26
- 'pattern' => false,
27
- 'placeholder' => '',
28
- ) );
29
 
30
- $field['attributes'] = wp_parse_args( $field['attributes'], array(
31
- 'size' => $field['size'],
32
- 'maxlength' => $field['maxlength'],
33
- 'pattern' => $field['pattern'],
34
- 'placeholder' => $field['placeholder'],
35
- ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- $field['attributes']['type'] = 'text';
38
 
39
- return $field;
40
- }
41
  }
42
  }
1
  <?php
2
+ /**
3
+ * Text field class.
4
+ */
5
+ class RWMB_Text_Field extends RWMB_Input_Field
 
 
 
6
  {
7
+ /**
8
+ * Normalize parameters for field
9
+ *
10
+ * @param array $field
11
+ * @return array
12
+ */
13
+ static function normalize( $field )
14
  {
15
+ $field = parent::normalize( $field );
 
 
 
 
 
 
 
 
 
16
 
17
+ $field = wp_parse_args( $field, array(
18
+ 'size' => 30,
19
+ 'maxlength' => false,
20
+ 'pattern' => false,
21
+ ) );
 
22
 
23
+ return $field;
24
+ }
25
+
26
+ /**
27
+ * Get the attributes for a field
28
+ *
29
+ * @param array $field
30
+ * @param mixed $value
31
+ *
32
+ * @return array
33
+ */
34
+ static function get_attributes( $field, $value = null )
35
+ {
36
+ $attributes = parent::get_attributes( $field, $value );
37
+ $attributes = wp_parse_args( $attributes, array(
38
+ 'size' => $field['size'],
39
+ 'maxlength' => $field['maxlength'],
40
+ 'pattern' => $field['pattern'],
41
+ 'placeholder' => $field['placeholder'],
42
+ ) );
43
 
44
+ $attributes['type'] = 'text';
45
 
46
+ return $attributes;
 
47
  }
48
  }
inc/fields/textarea.php CHANGED
@@ -1,71 +1,79 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Textarea_Field' ) )
6
  {
7
- class RWMB_Textarea_Field extends RWMB_Field
 
 
 
 
 
 
 
 
8
  {
9
- /**
10
- * Get field HTML
11
- *
12
- * @param mixed $meta
13
- * @param array $field
14
- *
15
- * @return string
16
- */
17
- static function html( $meta, $field )
18
- {
19
- $attributes = $field['attributes'];
20
- return sprintf(
21
- '<textarea %s>%s</textarea>',
22
- self::render_attributes( $attributes ),
23
- $meta
24
- );
25
- }
26
 
27
- /**
28
- * Escape meta for field output
29
- *
30
- * @param mixed $meta
31
- *
32
- * @return mixed
33
- */
34
- static function esc_meta( $meta )
35
- {
36
- return is_array( $meta ) ? array_map( 'esc_textarea', $meta ) : esc_textarea( $meta );
37
- }
38
 
39
- /**
40
- * Normalize parameters for field
41
- *
42
- * @param array $field
43
- *
44
- * @return array
45
- */
46
- static function normalize_field( $field )
47
- {
48
- $field = parent::normalize_field( $field );
49
- $field = wp_parse_args( $field, array(
50
- 'cols' => 60,
51
- 'rows' => 3,
52
- 'maxlength' => false,
53
- 'wrap' => false,
54
- 'readonly' => false,
55
- 'placeholder' => '',
56
- ) );
57
-
58
- $field['attributes'] = wp_parse_args( $field['attributes'], array(
59
- 'cols' => $field['cols'],
60
- 'rows' => $field['rows'],
61
- 'maxlength' => $field['maxlength'],
62
- 'wrap' => $field['wrap'],
63
- 'readonly' => $field['readonly'],
64
- 'placeholder' => $field['placeholder'],
65
- ) );
66
- $field['attributes']['class'] .= ' large-text';
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
- return $field;
69
- }
70
  }
71
  }
1
  <?php
2
+ /**
3
+ * Textarea field class.
4
+ */
5
+ class RWMB_Textarea_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Get field HTML
9
+ *
10
+ * @param mixed $meta
11
+ * @param array $field
12
+ *
13
+ * @return string
14
+ */
15
+ static function html( $meta, $field )
16
  {
17
+ $attributes = self::get_attributes( $field, $meta );
18
+ return sprintf(
19
+ '<textarea %s>%s</textarea>',
20
+ self::render_attributes( $attributes ),
21
+ $meta
22
+ );
23
+ }
 
 
 
 
 
 
 
 
 
 
24
 
25
+ /**
26
+ * Escape meta for field output
27
+ *
28
+ * @param mixed $meta
29
+ * @return mixed
30
+ */
31
+ static function esc_meta( $meta )
32
+ {
33
+ return is_array( $meta ) ? array_map( 'esc_textarea', $meta ) : esc_textarea( $meta );
34
+ }
 
35
 
36
+ /**
37
+ * Normalize parameters for field
38
+ *
39
+ * @param array $field
40
+ * @return array
41
+ */
42
+ static function normalize( $field )
43
+ {
44
+ $field = parent::normalize( $field );
45
+ $field = wp_parse_args( $field, array(
46
+ 'cols' => 60,
47
+ 'rows' => 3,
48
+ 'maxlength' => false,
49
+ 'wrap' => false,
50
+ 'readonly' => false,
51
+ ) );
52
+
53
+ return $field;
54
+ }
55
+
56
+ /**
57
+ * Get the attributes for a field
58
+ *
59
+ * @param array $field
60
+ * @param mixed $value
61
+ *
62
+ * @return array
63
+ */
64
+ static function get_attributes( $field, $value = null )
65
+ {
66
+ $attributes = parent::get_attributes( $field, $value );
67
+ $attributes = wp_parse_args( $attributes, array(
68
+ 'cols' => $field['cols'],
69
+ 'rows' => $field['rows'],
70
+ 'maxlength' => $field['maxlength'],
71
+ 'wrap' => $field['wrap'],
72
+ 'readonly' => $field['readonly'],
73
+ 'placeholder' => $field['placeholder'],
74
+ ) );
75
+ $attributes['class'] .= ' large-text';
76
 
77
+ return $attributes;
 
78
  }
79
  }
inc/fields/thickbox-image.php CHANGED
@@ -1,61 +1,59 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Thickbox_Image_Field' ) )
 
6
  {
7
- class RWMB_Thickbox_Image_Field extends RWMB_Image_Field
 
 
 
 
 
8
  {
9
- /**
10
- * Enqueue scripts and styles
11
- *
12
- * @return void
13
- */
14
- static function admin_enqueue_scripts()
15
- {
16
- parent::admin_enqueue_scripts();
17
 
18
- add_thickbox();
19
- wp_enqueue_script( 'media-upload' );
20
 
21
- wp_enqueue_script( 'rwmb-thickbox-image', RWMB_JS_URL . 'thickbox-image.js', array( 'jquery' ), RWMB_VER, true );
22
- }
23
 
24
- /**
25
- * Get field HTML
26
- *
27
- * @param mixed $meta
28
- * @param array $field
29
- *
30
- * @return string
31
- */
32
- static function html( $meta, $field )
33
- {
34
- $i18n_title = apply_filters( 'rwmb_thickbox_image_upload_string', _x( 'Upload Images', 'image upload', 'meta-box' ), $field );
35
 
36
- // Uploaded images
37
- $html = self::get_uploaded_images( $meta, $field );
38
 
39
- // Show form upload
40
- $html .= "<a href='#' class='button rwmb-thickbox-upload' data-field_id='{$field['id']}'>{$i18n_title}</a>";
41
 
42
- return $html;
43
- }
44
 
45
- /**
46
- * Get field value
47
- * It's the combination of new (uploaded) images and saved images
48
- *
49
- * @param array $new
50
- * @param array $old
51
- * @param int $post_id
52
- * @param array $field
53
- *
54
- * @return array|mixed
55
- */
56
- static function value( $new, $old, $post_id, $field )
57
- {
58
- return array_unique( array_merge( $old, $new ) );
59
- }
60
  }
61
  }
1
  <?php
2
+ /**
3
+ * Image upload field which uses thickbox library to upload.
4
+ * @deprecated
5
+ */
6
+ class RWMB_Thickbox_Image_Field extends RWMB_Image_Field
7
  {
8
+ /**
9
+ * Enqueue scripts and styles
10
+ *
11
+ * @return void
12
+ */
13
+ static function admin_enqueue_scripts()
14
  {
15
+ parent::admin_enqueue_scripts();
 
 
 
 
 
 
 
16
 
17
+ add_thickbox();
18
+ wp_enqueue_script( 'media-upload' );
19
 
20
+ wp_enqueue_script( 'rwmb-thickbox-image', RWMB_JS_URL . 'thickbox-image.js', array( 'jquery' ), RWMB_VER, true );
21
+ }
22
 
23
+ /**
24
+ * Get field HTML
25
+ *
26
+ * @param mixed $meta
27
+ * @param array $field
28
+ *
29
+ * @return string
30
+ */
31
+ static function html( $meta, $field )
32
+ {
33
+ $i18n_title = apply_filters( 'rwmb_thickbox_image_upload_string', _x( 'Upload Images', 'image upload', 'meta-box' ), $field );
34
 
35
+ // Uploaded images
36
+ $html = self::get_uploaded_images( $meta, $field );
37
 
38
+ // Show form upload
39
+ $html .= "<a href='#' class='button rwmb-thickbox-upload' data-field_id='{$field['id']}'>{$i18n_title}</a>";
40
 
41
+ return $html;
42
+ }
43
 
44
+ /**
45
+ * Get field value
46
+ * It's the combination of new (uploaded) images and saved images
47
+ *
48
+ * @param array $new
49
+ * @param array $old
50
+ * @param int $post_id
51
+ * @param array $field
52
+ *
53
+ * @return array
54
+ */
55
+ static function value( $new, $old, $post_id, $field )
56
+ {
57
+ return array_unique( array_merge( $old, $new ) );
 
58
  }
59
  }
inc/fields/time.php CHANGED
@@ -1,76 +1,97 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "text" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'text.php';
7
-
8
- if ( ! class_exists( 'RWMB_Time_Field' ) )
9
  {
10
- class RWMB_Time_Field extends RWMB_Text_Field
 
 
 
11
  {
12
- /**
13
- * Enqueue scripts and styles
14
- *
15
- * @return void
16
- */
17
- static function admin_enqueue_scripts()
18
- {
19
- $url = RWMB_CSS_URL . 'jqueryui';
20
- wp_register_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
21
- wp_register_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
22
- wp_register_style( 'jquery-ui-datepicker', "{$url}/jquery.ui.datepicker.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
23
- wp_register_style( 'jquery-ui-slider', "{$url}/jquery.ui.slider.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
24
- wp_enqueue_style( 'jquery-ui-timepicker', "{$url}/jquery-ui-timepicker-addon.min.css", array( 'jquery-ui-datepicker', 'jquery-ui-slider' ), '1.5.0' );
25
-
26
- $url = RWMB_JS_URL . 'jqueryui';
27
- wp_register_script( 'jquery-ui-timepicker', "{$url}/jquery-ui-timepicker-addon.min.js", array( 'jquery-ui-datepicker', 'jquery-ui-slider' ), '1.5.0', true );
28
 
29
- /**
30
- * Localization
31
- * Use 1 minified JS file which contains all languages for simpilicity (in version < 4.4.2 we use separated JS files).
32
- * The language is set in Javascript
33
- *
34
- * Note: we use full locale (de-DE) and fallback to short locale (de)
35
- */
36
- $locale = str_replace( '_', '-', get_locale() );
37
- $locale_short = substr( $locale, 0, 2 );
38
- wp_register_script( 'jquery-ui-timepicker-i18n', "{$url}/jquery-ui-timepicker-addon-i18n.min.js", array( 'jquery-ui-timepicker' ), '1.5.0', true );
39
-
40
- wp_enqueue_script( 'rwmb-time', RWMB_JS_URL . 'time.js', array( 'jquery-ui-timepicker-i18n' ), RWMB_VER, true );
41
- wp_localize_script( 'rwmb-time', 'RWMB_Timepicker', array(
42
- 'locale' => $locale,
43
- 'localeShort' => $locale_short,
44
- ) );
45
- }
46
 
47
  /**
48
- * Normalize parameters for field
49
- *
50
- * @param array $field
51
  *
52
- * @return array
53
  */
54
- static function normalize_field( $field )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  {
56
- $field = wp_parse_args( $field, array(
57
- 'js_options' => array(),
58
- ) );
 
59
 
60
- // Deprecate 'format', but keep it for backward compatible
61
- // Use 'js_options' instead
62
- $field['js_options'] = wp_parse_args( $field['js_options'], array(
63
- 'showButtonPanel' => true,
64
- 'timeFormat' => empty( $field['format'] ) ? 'HH:mm' : $field['format'],
65
- ) );
 
 
 
 
 
 
66
 
67
- $field = parent::normalize_field( $field );
 
 
 
 
 
68
 
69
- $field['attributes'] = wp_parse_args( $field['attributes'], array(
70
- 'data-options' => wp_json_encode( $field['js_options'] ),
71
- ) );
72
 
73
- return $field;
74
- }
 
 
 
 
 
 
 
 
 
 
 
 
75
  }
76
  }
1
  <?php
2
+ /**
3
+ * Time field class.
4
+ */
5
+ class RWMB_Time_Field extends RWMB_Text_Field
 
 
 
6
  {
7
+ /**
8
+ * Enqueue scripts and styles
9
+ */
10
+ static function admin_enqueue_scripts()
11
  {
12
+ $url = RWMB_CSS_URL . 'jqueryui';
13
+ wp_register_style( 'jquery-ui-core', "{$url}/jquery.ui.core.css", array(), '1.8.17' );
14
+ wp_register_style( 'jquery-ui-theme', "{$url}/jquery.ui.theme.css", array(), '1.8.17' );
15
+ wp_register_style( 'jquery-ui-datepicker', "{$url}/jquery.ui.datepicker.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
16
+ wp_register_style( 'wp-datepicker', RWMB_CSS_URL . 'datepicker.css', array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
17
+ wp_register_style( 'jquery-ui-slider', "{$url}/jquery.ui.slider.css", array( 'jquery-ui-core', 'jquery-ui-theme' ), '1.8.17' );
18
+ wp_enqueue_style( 'jquery-ui-timepicker', "{$url}/jquery-ui-timepicker-addon.min.css", array( 'jquery-ui-datepicker', 'jquery-ui-slider', 'wp-datepicker' ), '1.5.0' );
 
 
 
 
 
 
 
 
 
19
 
20
+ $url = RWMB_JS_URL . 'jqueryui';
21
+ wp_register_script( 'jquery-ui-timepicker', "{$url}/jquery-ui-timepicker-addon.min.js", array( 'jquery-ui-datepicker', 'jquery-ui-slider' ), '1.5.0', true );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  /**
24
+ * Localization
25
+ * Use 1 minified JS file which contains all languages for simpilicity (in version < 4.4.2 we use separated JS files).
26
+ * The language is set in Javascript
27
  *
28
+ * Note: we use full locale (de-DE) and fallback to short locale (de)
29
  */
30
+ $locale = str_replace( '_', '-', get_locale() );
31
+ $locale_short = substr( $locale, 0, 2 );
32
+ wp_register_script( 'jquery-ui-timepicker-i18n', "{$url}/jquery-ui-timepicker-addon-i18n.min.js", array( 'jquery-ui-timepicker' ), '1.5.0', true );
33
+
34
+ wp_enqueue_script( 'rwmb-time', RWMB_JS_URL . 'time.js', array( 'jquery-ui-timepicker-i18n' ), RWMB_VER, true );
35
+ wp_localize_script( 'rwmb-time', 'RWMB_Timepicker', array(
36
+ 'locale' => $locale,
37
+ 'localeShort' => $locale_short,
38
+ ) );
39
+ }
40
+
41
+ /**
42
+ * Get field HTML
43
+ *
44
+ * @param mixed $meta
45
+ * @param array $field
46
+ * @return string
47
+ */
48
+ static function html( $meta, $field )
49
+ {
50
+ $output = parent::html( $meta, $field );
51
+ if ( $field['inline'] )
52
  {
53
+ $output .= '<div class="rwmb-time-inline"></div>';
54
+ }
55
+ return $output;
56
+ }
57
 
58
+ /**
59
+ * Normalize parameters for field
60
+ *
61
+ * @param array $field
62
+ * @return array
63
+ */
64
+ static function normalize( $field )
65
+ {
66
+ $field = wp_parse_args( $field, array(
67
+ 'js_options' => array(),
68
+ 'inline' => false,
69
+ ) );
70
 
71
+ // Deprecate 'format', but keep it for backward compatible
72
+ // Use 'js_options' instead
73
+ $field['js_options'] = wp_parse_args( $field['js_options'], array(
74
+ 'showButtonPanel' => true,
75
+ 'timeFormat' => empty( $field['format'] ) ? 'HH:mm' : $field['format'],
76
+ ) );
77
 
78
+ $field = parent::normalize( $field );
79
+ return $field;
80
+ }
81
 
82
+ /**
83
+ * Get the attributes for a field
84
+ *
85
+ * @param array $field
86
+ * @param mixed $value
87
+ * @return array
88
+ */
89
+ static function get_attributes( $field, $value = null )
90
+ {
91
+ $attributes = parent::get_attributes( $field, $value );
92
+ $attributes = wp_parse_args( $attributes, array(
93
+ 'data-options' => wp_json_encode( $field['js_options'] ),
94
+ ) );
95
+ return $attributes;
96
  }
97
  }
inc/fields/url.php CHANGED
@@ -1,43 +1,37 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "text" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'text.php';
7
-
8
- if ( ! class_exists( 'RWMB_URL_Field' ) )
9
  {
10
- class RWMB_URL_Field extends RWMB_Text_Field
 
 
 
 
 
 
 
 
11
  {
12
- /**
13
- * Normalize parameters for field
14
- *
15
- * @param array $field
16
- *
17
- * @return array
18
- */
19
- static function normalize_field( $field )
20
- {
21
- $field = parent::normalize_field( $field );
22
-
23
- $field['attributes']['type'] = 'url';
24
 
25
- return $field;
26
- }
27
 
28
- /**
29
- * Sanitize url
30
- *
31
- * @param mixed $new
32
- * @param mixed $old
33
- * @param int $post_id
34
- * @param array $field
35
- *
36
- * @return string
37
- */
38
- static function value( $new, $old, $post_id, $field )
39
- {
40
- return is_array( $new ) ? array_map( 'esc_url', $new ) : esc_url( $new );
41
- }
42
  }
43
  }
1
  <?php
2
+ /**
3
+ * HTML5 URL field class.
4
+ */
5
+ class RWMB_URL_Field extends RWMB_Text_Field
 
 
 
6
  {
7
+ /**
8
+ * Get the attributes for a field
9
+ *
10
+ * @param array $field
11
+ * @param mixed $value
12
+ *
13
+ * @return array
14
+ */
15
+ static function get_attributes( $field, $value = null )
16
  {
17
+ $attributes = parent::get_attributes( $field, $value );
18
+ $attributes['type'] = 'url';
 
 
 
 
 
 
 
 
 
 
19
 
20
+ return $attributes;
21
+ }
22
 
23
+ /**
24
+ * Sanitize url
25
+ *
26
+ * @param mixed $new
27
+ * @param mixed $old
28
+ * @param int $post_id
29
+ * @param array $field
30
+ *
31
+ * @return string
32
+ */
33
+ static function value( $new, $old, $post_id, $field )
34
+ {
35
+ return is_array( $new ) ? array_map( 'esc_url_raw', $new ) : esc_url_raw( $new );
 
36
  }
37
  }
inc/fields/user.php CHANGED
@@ -1,103 +1,94 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- // Make sure "select" field is loaded
6
- require_once RWMB_FIELDS_DIR . 'select-advanced.php';
7
-
8
- if ( ! class_exists( 'RWMB_User_Field' ) )
9
  {
10
- class RWMB_User_Field extends RWMB_Select_Advanced_Field
 
 
 
 
 
 
 
11
  {
12
  /**
13
- * Get field HTML
14
- *
15
- * @param mixed $meta
16
- * @param array $field
17
- *
18
- * @return string
19
  */
20
- static function html( $meta, $field )
21
- {
22
- $field['options'] = self::get_options( $field );
23
- switch ( $field['field_type'] )
24
- {
25
- case 'select':
26
- return RWMB_Select_Field::html( $meta, $field );
27
- break;
28
- case 'select_advanced':
29
- default:
30
- return RWMB_Select_Advanced_Field::html( $meta, $field );
31
- }
32
- }
33
 
34
  /**
35
- * Normalize parameters for field
36
- *
37
- * @param array $field
38
- *
39
- * @return array
40
  */
41
- static function normalize_field( $field )
42
- {
43
- $field = wp_parse_args( $field, array(
44
- 'field_type' => 'select_advanced',
45
- 'parent' => false,
46
- 'query_args' => array(),
47
- ) );
48
-
49
- $field['std'] = empty( $field['std'] ) ? __( 'Select an user', 'meta-box' ) : $field['std'];
50
-
51
- $field['query_args'] = wp_parse_args( $field['query_args'], array(
52
- 'orderby' => 'display_name',
53
- 'order' => 'asc',
54
- 'role' => '',
55
- 'fields' => 'all',
56
- ) );
57
-
58
- switch ( $field['field_type'] )
59
- {
60
- case 'select':
61
- return RWMB_Select_Field::normalize_field( $field );
62
- break;
63
- case 'select_advanced':
64
- default:
65
- return RWMB_Select_Advanced_Field::normalize_field( $field );
66
- }
67
- }
68
 
69
  /**
70
- * Get users
71
- *
72
- * @param array $field
73
- *
74
- * @return array
75
  */
76
- static function get_options( $field )
77
- {
78
- $results = get_users( $field['query_args'] );
79
- $options = array();
80
- foreach ( $results as $result )
81
- {
82
- $options[$result->ID] = $result->display_name;
83
- }
84
 
85
- return $options;
86
- }
 
 
87
 
88
  /**
89
- * Get option label to display in the frontend
90
- *
91
- * @param int $value Option value
92
- * @param int $index Array index
93
- * @param array $field Field parameter
94
- *
95
- * @return string
96
  */
97
- static function get_option_label( &$value, $index, $field )
98
- {
99
- $user = get_userdata( $value );
100
- $value = '<a href="' . get_author_posts_url( $value ) . '">' . $user->display_name . '</a>';
101
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  }
103
  }
1
  <?php
2
+ /**
3
+ * User field class.
4
+ */
5
+ class RWMB_User_Field extends RWMB_Object_Choice_Field
 
 
 
6
  {
7
+ /**
8
+ * Normalize parameters for field
9
+ *
10
+ * @param array $field
11
+ *
12
+ * @return array
13
+ */
14
+ static function normalize( $field )
15
  {
16
  /**
17
+ * Set default field args
 
 
 
 
 
18
  */
19
+ $field = wp_parse_args( $field, array(
20
+ 'field_type' => 'select',
21
+ 'query_args' => array(),
22
+ ) );
 
 
 
 
 
 
 
 
 
23
 
24
  /**
25
+ * Prevent select tree for user since it's not hierarchical
 
 
 
 
26
  */
27
+ $field['field_type'] = 'select_tree' === $field['field_type'] ? 'select' : $field['field_type'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  /**
30
+ * Set to always flat
 
 
 
 
31
  */
32
+ $field['flatten'] = true;
 
 
 
 
 
 
 
33
 
34
+ /**
35
+ * Set default placeholder
36
+ */
37
+ $field['placeholder'] = empty( $field['placeholder'] ) ? __( 'Select an user', 'meta-box' ) : $field['placeholder'];
38
 
39
  /**
40
+ * Set default query args
 
 
 
 
 
 
41
  */
42
+ $field['query_args'] = wp_parse_args( $field['query_args'], array(
43
+ 'orderby' => 'display_name',
44
+ 'order' => 'asc',
45
+ 'role' => '',
46
+ 'fields' => 'all',
47
+ ) );
48
+ $field = parent::normalize( $field );
49
+
50
+ return $field;
51
+ }
52
+
53
+ /**
54
+ * Get users
55
+ *
56
+ * @param array $field
57
+ *
58
+ * @return array
59
+ */
60
+ static function get_options( $field )
61
+ {
62
+ $options = get_users( $field['query_args'] );
63
+ return $options;
64
+ }
65
+
66
+ /**
67
+ * Get field names of object to be used by walker
68
+ *
69
+ * @return array
70
+ */
71
+ static function get_db_fields()
72
+ {
73
+ return array(
74
+ 'parent' => 'parent',
75
+ 'id' => 'ID',
76
+ 'label' => 'display_name',
77
+ );
78
+ }
79
+
80
+ /**
81
+ * Get option label to display in the frontend
82
+ *
83
+ * @param int $value Option value
84
+ * @param int $index Array index
85
+ * @param array $field Field parameter
86
+ *
87
+ * @return string
88
+ */
89
+ static function get_option_label( &$value, $index, $field )
90
+ {
91
+ $user = get_userdata( $value );
92
+ $value = '<a href="' . get_author_posts_url( $value ) . '">' . $user->display_name . '</a>';
93
  }
94
  }
inc/fields/wysiwyg.php CHANGED
@@ -1,120 +1,118 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
-
5
- if ( ! class_exists( 'RWMB_Wysiwyg_Field' ) )
6
  {
7
- class RWMB_Wysiwyg_Field extends RWMB_Field
 
 
 
 
 
 
 
 
 
8
  {
 
 
9
 
10
- static $cloneable_editors = array();
11
-
12
- /**
13
- * Enqueue scripts and styles
14
- *
15
- * @return void
16
- */
17
- static function admin_enqueue_scripts()
 
 
 
 
18
  {
19
- wp_enqueue_style( 'rwmb-meta-box-wysiwyg', RWMB_CSS_URL . 'wysiwyg.css', array(), RWMB_VER );
20
  }
21
-
22
- /**
23
- * Change field value on save
24
- *
25
- * @param mixed $new
26
- * @param mixed $old
27
- * @param int $post_id
28
- * @param array $field
29
- *
30
- * @return string
31
- */
32
- static function value( $new, $old, $post_id, $field )
33
  {
34
- if ( $field['raw'] )
35
- {
36
- $meta = $new;
37
- }
38
- else if ( $field['clone'] )
39
- {
40
- $meta = array_map( 'wpautop', $new );
41
- }
42
- else
43
- {
44
- $meta = wpautop( $new );
45
- }
46
-
47
- return $meta;
48
  }
49
-
50
- /**
51
- * Get field HTML
52
- *
53
- * @param mixed $meta
54
- * @param array $field
55
- *
56
- * @return string
57
- */
58
- static function html( $meta, $field )
59
  {
60
- // Using output buffering because wp_editor() echos directly
61
- ob_start();
62
 
63
- $field['options']['textarea_name'] = $field['field_name'];
 
64
 
65
- // Use new wp_editor() since WP 3.3
66
- wp_editor( $meta, $field['id'], $field['options'] );
 
 
 
 
 
 
 
 
 
67
 
68
- $editor = ob_get_clean();
69
- if ( $field['clone'] )
70
- {
71
- self::$cloneable_editors[$field['id']] = $editor;
72
- add_action( 'admin_print_footer_scripts', array( __CLASS__, 'footer_scripts' ), 51 );
73
- }
74
 
75
- return $editor;
76
- }
77
 
78
- /**
79
- * Escape meta for field output
80
- *
81
- * @param mixed $meta
82
- *
83
- * @return mixed
84
- */
85
- static function esc_meta( $meta )
86
  {
87
- return $meta;
 
88
  }
89
 
90
- /**
91
- * Normalize parameters for field
92
- *
93
- * @param array $field
94
- *
95
- * @return array
96
- */
97
- static function normalize_field( $field )
98
- {
99
- $field = wp_parse_args( $field, array(
100
- 'raw' => false,
101
- 'options' => array(),
102
- ) );
103
 
104
- $field['options'] = wp_parse_args( $field['options'], array(
105
- 'editor_class' => 'rwmb-wysiwyg',
106
- 'dfw' => true, // Use default WordPress full screen UI
107
- ) );
 
 
 
 
 
 
108
 
109
- // Keep the filter to be compatible with previous versions
110
- $field['options'] = apply_filters( 'rwmb_wysiwyg_settings', $field['options'] );
 
 
 
 
 
 
 
 
 
 
 
111
 
112
- return $field;
113
- }
 
 
114
 
115
- static function footer_scripts()
116
- {
117
- echo '<script> var rwmb_cloneable_editors = ' , wp_json_encode( self::$cloneable_editors ) , ';</script>';
118
- }
 
 
 
 
 
 
 
 
119
  }
120
  }
1
  <?php
2
+ /**
3
+ * WYSIWYG (editor) field class.
4
+ */
5
+ class RWMB_Wysiwyg_Field extends RWMB_Field
6
  {
7
+ /**
8
+ * Array of cloneable editors.
9
+ * @var array
10
+ */
11
+ static $cloneable_editors = array();
12
+
13
+ /**
14
+ * Enqueue scripts and styles.
15
+ */
16
+ static function admin_enqueue_scripts()
17
  {
18
+ wp_enqueue_style( 'rwmb-meta-box-wysiwyg', RWMB_CSS_URL . 'wysiwyg.css', array(), RWMB_VER );
19
+ }
20
 
21
+ /**
22
+ * Change field value on save
23
+ *
24
+ * @param mixed $new
25
+ * @param mixed $old
26
+ * @param int $post_id
27
+ * @param array $field
28
+ * @return string
29
+ */
30
+ static function value( $new, $old, $post_id, $field )
31
+ {
32
+ if ( $field['raw'] )
33
  {
34
+ $meta = $new;
35
  }
36
+ elseif ( $field['clone'] )
 
 
 
 
 
 
 
 
 
 
 
37
  {
38
+ $meta = array_map( 'wpautop', $new );
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  }
40
+ else
 
 
 
 
 
 
 
 
 
41
  {
42
+ $meta = wpautop( $new );
43
+ }
44
 
45
+ return $meta;
46
+ }
47
 
48
+ /**
49
+ * Get field HTML
50
+ *
51
+ * @param mixed $meta
52
+ * @param array $field
53
+ * @return string
54
+ */
55
+ static function html( $meta, $field )
56
+ {
57
+ // Using output buffering because wp_editor() echos directly
58
+ ob_start();
59
 
60
+ $field['options']['textarea_name'] = $field['field_name'];
 
 
 
 
 
61
 
62
+ // Use new wp_editor() since WP 3.3
63
+ wp_editor( $meta, $field['id'], $field['options'] );
64
 
65
+ $editor = ob_get_clean();
66
+ if ( $field['clone'] )
 
 
 
 
 
 
67
  {
68
+ self::$cloneable_editors[$field['id']] = $editor;
69
+ add_action( 'admin_print_footer_scripts', array( __CLASS__, 'footer_scripts' ), 51 );
70
  }
71
 
72
+ return $editor;
73
+ }
 
 
 
 
 
 
 
 
 
 
 
74
 
75
+ /**
76
+ * Escape meta for field output
77
+ *
78
+ * @param mixed $meta
79
+ * @return mixed
80
+ */
81
+ static function esc_meta( $meta )
82
+ {
83
+ return $meta;
84
+ }
85
 
86
+ /**
87
+ * Normalize parameters for field
88
+ *
89
+ * @param array $field
90
+ * @return array
91
+ */
92
+ static function normalize( $field )
93
+ {
94
+ $field = parent::normalize( $field );
95
+ $field = wp_parse_args( $field, array(
96
+ 'raw' => false,
97
+ 'options' => array(),
98
+ ) );
99
 
100
+ $field['options'] = wp_parse_args( $field['options'], array(
101
+ 'editor_class' => 'rwmb-wysiwyg',
102
+ 'dfw' => true, // Use default WordPress full screen UI
103
+ ) );
104
 
105
+ // Keep the filter to be compatible with previous versions
106
+ $field['options'] = apply_filters( 'rwmb_wysiwyg_settings', $field['options'] );
107
+
108
+ return $field;
109
+ }
110
+
111
+ /**
112
+ * Display list of editors' IDs in the footer for clone.
113
+ */
114
+ static function footer_scripts()
115
+ {
116
+ echo '<script>var rwmb_cloneable_editors = ', wp_json_encode( self::$cloneable_editors ), ';</script>';
117
  }
118
  }
inc/functions.php ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin public functions.
4
+ */
5
+
6
+ /**
7
+ * Get post meta
8
+ *
9
+ * @param string $key Meta key. Required.
10
+ * @param int|null $post_id Post ID. null for current post. Optional
11
+ * @param array $args Array of arguments. Optional.
12
+ *
13
+ * @return mixed
14
+ */
15
+ function rwmb_meta( $key, $args = array(), $post_id = null )
16
+ {
17
+ return RWMB_Helper::meta( $key, $args, $post_id );
18
+ }
19
+
20
+ /**
21
+ * Get value of custom field.
22
+ * This is used to replace old version of rwmb_meta key.
23
+ *
24
+ * @param string $field_id Field ID. Required.
25
+ * @param array $args Additional arguments. Rarely used. See specific fields for details
26
+ * @param int|null $post_id Post ID. null for current post. Optional.
27
+ *
28
+ * @return mixed false if field doesn't exist. Field value otherwise.
29
+ */
30
+ function rwmb_get_field( $field_id, $args = array(), $post_id = null )
31
+ {
32
+ $field = RWMB_Helper::find_field( $field_id );
33
+
34
+ // Get field value
35
+ $value = $field ? call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'get_value' ), $field, $args, $post_id ) : false;
36
+
37
+ /**
38
+ * Allow developers to change the returned value of field
39
+ *
40
+ * @param mixed $value Field value
41
+ * @param array $field Field parameter
42
+ * @param array $args Additional arguments. Rarely used. See specific fields for details
43
+ * @param int|null $post_id Post ID. null for current post. Optional.
44
+ */
45
+ $value = apply_filters( 'rwmb_get_field', $value, $field, $args, $post_id );
46
+
47
+ return $value;
48
+ }
49
+
50
+ /**
51
+ * Display the value of a field
52
+ *
53
+ * @param string $field_id Field ID. Required.
54
+ * @param array $args Additional arguments. Rarely used. See specific fields for details
55
+ * @param int|null $post_id Post ID. null for current post. Optional.
56
+ * @param bool $echo Display field meta value? Default `true` which works in almost all cases. We use `false` for the [rwmb_meta] shortcode
57
+ *
58
+ * @return string
59
+ */
60
+ function rwmb_the_field( $field_id, $args = array(), $post_id = null, $echo = true )
61
+ {
62
+ // Find field
63
+ $field = RWMB_Helper::find_field( $field_id );
64
+
65
+ if ( ! $field )
66
+ return '';
67
+
68
+ $output = call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'the_value' ), $field, $args, $post_id );
69
+
70
+ /**
71
+ * Allow developers to change the returned value of field
72
+ *
73
+ * @param mixed $value Field HTML output
74
+ * @param array $field Field parameter
75
+ * @param array $args Additional arguments. Rarely used. See specific fields for details
76
+ * @param int|null $post_id Post ID. null for current post. Optional.
77
+ */
78
+ $output = apply_filters( 'rwmb_the_field', $output, $field, $args, $post_id );
79
+
80
+ if ( $echo )
81
+ echo $output;
82
+
83
+ return $output;
84
+ }
85
+
86
+ /**
87
+ * Shortcode to display meta value
88
+ *
89
+ * @param array $atts Shortcode attributes, same as meta() function, but has more "meta_key" parameter
90
+ *
91
+ * @see meta() function below
92
+ *
93
+ * @return string
94
+ */
95
+ function rwmb_meta_shortcode( $atts )
96
+ {
97
+ $atts = wp_parse_args( $atts, array(
98
+ 'post_id' => get_the_ID(),
99
+ ) );
100
+ if ( empty( $atts['meta_key'] ) )
101
+ return '';
102
+
103
+ $field_id = $atts['meta_key'];
104
+ $post_id = $atts['post_id'];
105
+ unset( $atts['meta_key'], $atts['post_id'] );
106
+
107
+ return rwmb_the_field( $field_id, $atts, $post_id, false );
108
+ }
109
+
110
+ add_shortcode( 'rwmb_meta', 'rwmb_meta_shortcode' );
inc/helper.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The helper class.
4
+ */
5
+
6
+ /**
7
+ * Wrapper class for helper functions.
8
+ */
9
+ class RWMB_Helper
10
+ {
11
+ /**
12
+ * Find field by field ID.
13
+ * This function finds field in meta boxes registered by 'rwmb_meta_boxes' filter.
14
+ *
15
+ * @param string $field_id Field ID
16
+ * @return array|false Field params (array) if success. False otherwise.
17
+ */
18
+ static function find_field( $field_id )
19
+ {
20
+ $meta_boxes = RWMB_Core::get_meta_boxes();
21
+ foreach ( $meta_boxes as $meta_box )
22
+ {
23
+ $meta_box = RW_Meta_Box::normalize( $meta_box );
24
+ foreach ( $meta_box['fields'] as $field )
25
+ {
26
+ if ( $field_id == $field['id'] )
27
+ {
28
+ return $field;
29
+ }
30
+ }
31
+ }
32
+ return false;
33
+ }
34
+
35
+ /**
36
+ * Get post meta.
37
+ *
38
+ * @param string $key Meta key. Required.
39
+ * @param int|null $post_id Post ID. null for current post. Optional
40
+ * @param array $args Array of arguments. Optional.
41
+ * @return mixed
42
+ */
43
+ static function meta( $key, $args = array(), $post_id = null )
44
+ {
45
+ $args = wp_parse_args( $args, array(
46
+ 'type' => 'text',
47
+ ) );
48
+ $meta = in_array( $args['type'], array( 'oembed', 'map' ) ) ?
49
+ rwmb_the_field( $key, $args, $post_id, false ) :
50
+ rwmb_get_field( $key, $args, $post_id );
51
+ return apply_filters( 'rwmb_meta', $meta, $key, $args, $post_id );
52
+ }
53
+ }
inc/helpers.php DELETED
@@ -1,271 +0,0 @@
1
- <?php
2
- /**
3
- * This file contains all helpers/public functions
4
- * that can be used both on the back-end or front-end
5
- */
6
-
7
- // Prevent loading this file directly
8
- defined( 'ABSPATH' ) || exit;
9
-
10
- if ( ! class_exists( 'RWMB_Helper' ) )
11
- {
12
- /**
13
- * Wrapper class for helper functions
14
- */
15
- class RWMB_Helper
16
- {
17
- /**
18
- * Find field by field ID
19
- * This function finds field in meta boxes registered by 'rwmb_meta_boxes' filter
20
- * Note: if users use old code to add meta boxes, this function might not work properly
21
- *
22
- * @param string $field_id Field ID
23
- *
24
- * @return array|false Field params (array) if success. False otherwise.
25
- */
26
- static function find_field( $field_id )
27
- {
28
- // Get all meta boxes registered with 'rwmb_meta_boxes' hook
29
- $meta_boxes = apply_filters( 'rwmb_meta_boxes', array() );
30
-
31
- // Find field
32
- foreach ( $meta_boxes as $meta_box )
33
- {
34
- $meta_box = RW_Meta_Box::normalize( $meta_box );
35
- foreach ( $meta_box['fields'] as $field )
36
- {
37
- if ( $field_id == $field['id'] )
38
- {
39
- return $field;
40
- }
41
- }
42
- }
43
-
44
- return false;
45
- }
46
-
47
- /**
48
- * Get post meta
49
- *
50
- * @param string $key Meta key. Required.
51
- * @param int|null $post_id Post ID. null for current post. Optional
52
- * @param array $args Array of arguments. Optional.
53
- *
54
- * @return mixed
55
- */
56
- static function meta( $key, $args = array(), $post_id = null )
57
- {
58
- $post_id = empty( $post_id ) ? get_the_ID() : $post_id;
59
- $args = wp_parse_args( $args, array(
60
- 'type' => 'text',
61
- 'multiple' => false,
62
- ) );
63
-
64
- // Always set 'multiple' true for following field types
65
- if ( in_array( $args['type'], array( 'checkbox_list', 'file', 'file_advanced', 'image', 'image_advanced', 'plupload_image', 'thickbox_image' ) ) )
66
- {
67
- $args['multiple'] = true;
68
- }
69
-
70
- $meta = get_post_meta( $post_id, $key, ! $args['multiple'] );
71
-
72
- // Get uploaded files info
73
- if ( in_array( $args['type'], array( 'file', 'file_advanced' ) ) )
74
- {
75
- if ( is_array( $meta ) && ! empty( $meta ) )
76
- {
77
- $files = array();
78
- foreach ( $meta as $id )
79
- {
80
- // Get only info of existing attachments
81
- if ( get_attached_file( $id ) )
82
- {
83
- $files[$id] = RWMB_File_Field::file_info( $id );
84
- }
85
- }
86
- $meta = $files;
87
- }
88
- }
89
- // Get uploaded images info
90
- elseif ( in_array( $args['type'], array( 'image', 'plupload_image', 'thickbox_image', 'image_advanced' ) ) )
91
- {
92
- if ( is_array( $meta ) && ! empty( $meta ) )
93
- {
94
- $images = array();
95
- foreach ( $meta as $id )
96
- {
97
- // Get only info of existing attachments
98
- if ( get_attached_file( $id ) )
99
- {
100
- $images[$id] = RWMB_Image_Field::file_info( $id, $args );
101
- }
102
- }
103
- $meta = $images;
104
- }
105
- }
106
- // Get terms
107
- elseif ( 'taxonomy_advanced' == $args['type'] )
108
- {
109
- if ( ! empty( $args['taxonomy'] ) )
110
- {
111
- $term_ids = array_map( 'intval', array_filter( explode( ',', $meta . ',' ) ) );
112
- // Allow to pass more arguments to "get_terms"
113
- $func_args = wp_parse_args( array(
114
- 'include' => $term_ids,
115
- 'hide_empty' => false,
116
- ), $args );
117
- unset( $func_args['type'], $func_args['taxonomy'], $func_args['multiple'] );
118
- $meta = get_terms( $args['taxonomy'], $func_args );
119
- }
120
- else
121
- {
122
- $meta = array();
123
- }
124
- }
125
- // Get post terms
126
- elseif ( 'taxonomy' == $args['type'] )
127
- {
128
- $meta = empty( $args['taxonomy'] ) ? array() : get_the_terms( $post_id, $args['taxonomy'] );
129
- }
130
- // Get map
131
- elseif ( 'map' == $args['type'] )
132
- {
133
- $field = array(
134
- 'id' => $key,
135
- 'multiple' => false,
136
- 'clone' => false,
137
- );
138
- $meta = RWMB_Map_Field::the_value( $field, $args, $post_id );
139
- }
140
- // Display oembed content
141
- elseif ( 'oembed' == $args['type'] )
142
- {
143
- $field = array(
144
- 'id' => $key,
145
- 'clone' => isset( $args['clone'] ) ? $args['clone'] : false,
146
- 'multiple' => isset( $args['multiple'] ) ? $args['multiple'] : false,
147
- );
148
- $meta = RWMB_OEmbed_Field::the_value( $field, $args, $post_id );
149
- }
150
- return apply_filters( 'rwmb_meta', $meta, $key, $args, $post_id );
151
- }
152
- }
153
- }
154
-
155
- if ( ! function_exists( 'rwmb_meta' ) )
156
- {
157
- /**
158
- * Get post meta
159
- *
160
- * @param string $key Meta key. Required.
161
- * @param int|null $post_id Post ID. null for current post. Optional
162
- * @param array $args Array of arguments. Optional.
163
- *
164
- * @return mixed
165
- */
166
- function rwmb_meta( $key, $args = array(), $post_id = null )
167
- {
168
- return RWMB_Helper::meta( $key, $args, $post_id );
169
- }
170
- }
171
-
172
- if ( ! function_exists( 'rwmb_get_field' ) )
173
- {
174
- /**
175
- * Get value of custom field.
176
- * This is used to replace old version of rwmb_meta key.
177
- *
178
- * @param string $field_id Field ID. Required.
179
- * @param array $args Additional arguments. Rarely used. See specific fields for details
180
- * @param int|null $post_id Post ID. null for current post. Optional.
181
- *
182
- * @return mixed false if field doesn't exist. Field value otherwise.
183
- */
184
- function rwmb_get_field( $field_id, $args = array(), $post_id = null )
185
- {
186
- $field = RWMB_Helper::find_field( $field_id );
187
-
188
- // Get field value
189
- $value = $field ? call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'get_value' ), $field, $args, $post_id ) : false;
190
-
191
- /**
192
- * Allow developers to change the returned value of field
193
- *
194
- * @param mixed $value Field value
195
- * @param array $field Field parameter
196
- * @param array $args Additional arguments. Rarely used. See specific fields for details
197
- * @param int|null $post_id Post ID. null for current post. Optional.
198
- */
199
- $value = apply_filters( 'rwmb_get_field', $value, $field, $args, $post_id );
200
-
201
- return $value;
202
- }
203
- }
204
-
205
- if ( ! function_exists( 'rwmb_the_field' ) )
206
- {
207
- /**
208
- * Display the value of a field
209
- *
210
- * @param string $field_id Field ID. Required.
211
- * @param array $args Additional arguments. Rarely used. See specific fields for details
212
- * @param int|null $post_id Post ID. null for current post. Optional.
213
- * @param bool $echo Display field meta value? Default `true` which works in almost all cases. We use `false` for the [rwmb_meta] shortcode
214
- *
215
- * @return string
216
- */
217
- function rwmb_the_field( $field_id, $args = array(), $post_id = null, $echo = true )
218
- {
219
- // Find field
220
- $field = RWMB_Helper::find_field( $field_id );
221
-
222
- if ( ! $field )
223
- return '';
224
-
225
- $output = call_user_func( array( RW_Meta_Box::get_class_name( $field ), 'the_value' ), $field, $args, $post_id );
226
-
227
- /**
228
- * Allow developers to change the returned value of field
229
- *
230
- * @param mixed $value Field HTML output
231
- * @param array $field Field parameter
232
- * @param array $args Additional arguments. Rarely used. See specific fields for details
233
- * @param int|null $post_id Post ID. null for current post. Optional.
234
- */
235
- $output = apply_filters( 'rwmb_the_field', $output, $field, $args, $post_id );
236
-
237
- if ( $echo )
238
- echo $output;
239
-
240
- return $output;
241
- }
242
- }
243
-
244
- if ( ! function_exists( 'rwmb_meta_shortcode' ) )
245
- {
246
- /**
247
- * Shortcode to display meta value
248
- *
249
- * @param $atts Array of shortcode attributes, same as meta() function, but has more "meta_key" parameter
250
- *
251
- * @see meta() function below
252
- *
253
- * @return string
254
- */
255
- function rwmb_meta_shortcode( $atts )
256
- {
257
- $atts = wp_parse_args( $atts, array(
258
- 'post_id' => get_the_ID(),
259
- ) );
260
- if ( empty( $atts['meta_key'] ) )
261
- return '';
262
-
263
- $field_id = $atts['meta_key'];
264
- $post_id = $atts['post_id'];
265
- unset( $atts['meta_key'], $atts['post_id'] );
266
-
267
- return rwmb_the_field( $field_id, $atts, $post_id, false );
268
- }
269
-
270
- add_shortcode( 'rwmb_meta', 'rwmb_meta_shortcode' );
271
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/init.php DELETED
@@ -1,48 +0,0 @@
1
- <?php
2
- add_action( 'admin_init', 'rwmb_register_meta_boxes' );
3
-
4
- /**
5
- * Register meta boxes via a filter
6
- * Advantages:
7
- * - prevents incorrect hook
8
- * - prevents duplicated global variables
9
- * - allows users to remove/hide registered meta boxes
10
- * - no need to check for class existences
11
- *
12
- * @return void
13
- */
14
- function rwmb_register_meta_boxes()
15
- {
16
- $meta_boxes = apply_filters( 'rwmb_meta_boxes', array() );
17
-
18
- // Prevent errors showing if invalid value is returned from the filter above
19
- if ( empty( $meta_boxes ) || ! is_array( $meta_boxes ) )
20
- return;
21
-
22
- foreach ( $meta_boxes as $meta_box )
23
- {
24
- new RW_Meta_Box( $meta_box );
25
- }
26
- }
27
-
28
- add_action( 'edit_page_form', 'rwmb_fix_page_template' );
29
-
30
- /**
31
- * WordPress will prevent post data saving if a page template has been selected that does not exist
32
- * This is especially a problem when switching to our theme, and old page templates are in the post data
33
- * Unset the page template if the page does not exist to allow the post to save
34
- *
35
- * @param WP_Post $post
36
- *
37
- * @return void
38
- * @since 4.3.10
39
- */
40
- function rwmb_fix_page_template( WP_Post $post )
41
- {
42
- $template = get_post_meta( $post->ID, '_wp_page_template', true );
43
- $page_templates = wp_get_theme()->get_page_templates();
44
-
45
- // If the template doesn't exists, remove the data to allow WordPress to save
46
- if ( ! isset( $page_templates[$template] ) )
47
- delete_post_meta( $post->ID, '_wp_page_template' );
48
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/loader.php ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Load plugin's files with check for installing it as a standalone plugin or
4
+ * a module of a theme / plugin. If standalone plugin is already installed, it
5
+ * will take higher priority.
6
+ * @package Meta Box
7
+ */
8
+
9
+ /**
10
+ * Plugin loader class.
11
+ * @package Meta Box
12
+ */
13
+ class RWMB_Loader
14
+ {
15
+ /**
16
+ * Class constructor.
17
+ */
18
+ public function __construct()
19
+ {
20
+ $this->constants();
21
+ spl_autoload_register( array( $this, 'autoload' ) );
22
+ $this->init();
23
+ }
24
+
25
+ /**
26
+ * Define plugin constants.
27
+ */
28
+ public function constants()
29
+ {
30
+ // Script version, used to add version for scripts and styles
31
+ define( 'RWMB_VER', '4.8.0' );
32
+
33
+ list( $path, $url ) = self::get_path();
34
+
35
+ // Plugin URLs, for fast enqueuing scripts and styles
36
+ define( 'RWMB_URL', $url );
37
+ define( 'RWMB_JS_URL', trailingslashit( RWMB_URL . 'js' ) );
38
+ define( 'RWMB_CSS_URL', trailingslashit( RWMB_URL . 'css' ) );
39
+
40
+ // Plugin paths, for including files
41
+ define( 'RWMB_DIR', $path );
42
+ define( 'RWMB_INC_DIR', trailingslashit( RWMB_DIR . 'inc' ) );
43
+ define( 'RWMB_FIELDS_DIR', trailingslashit( RWMB_INC_DIR . 'fields' ) );
44
+ }
45
+
46
+ /**
47
+ * Get plugin base path and URL.
48
+ * The method is static and can be used in extensions.
49
+ * @link http://www.deluxeblogtips.com/2013/07/get-url-of-php-file-in-wordpress.html
50
+ * @param string $base Base folder path
51
+ * @return array Path and URL.
52
+ */
53
+ static public function get_path( $base = '' )
54
+ {
55
+ // Plugin base path
56
+ $path = $base ? $base : dirname( dirname( __FILE__ ) );
57
+
58
+ // Check if plugin is a symbolic link (only when it's installed as a standalone plugin).
59
+ if ( false === strpos( $path, ABSPATH ) )
60
+ {
61
+ if ( ! function_exists( 'is_plugin_active' ) )
62
+ {
63
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
64
+ }
65
+ $basename = basename( $path );
66
+ if ( is_plugin_active( "$basename/$basename.php" ) )
67
+ {
68
+ $path = trailingslashit( WP_PLUGIN_DIR ) . $basename;
69
+ }
70
+ }
71
+
72
+ $path = trailingslashit( wp_normalize_path( $path ) );
73
+
74
+ // Get plugin base URL
75
+ $content_url = untrailingslashit( dirname( dirname( get_stylesheet_directory_uri() ) ) );
76
+ $content_dir = untrailingslashit( WP_CONTENT_DIR );
77
+ $content_dir = wp_normalize_path( $content_dir );
78
+ $url = str_replace( $content_dir, $content_url, $path );
79
+
80
+ return array( $path, $url );
81
+ }
82
+
83
+ /**
84
+ * Autoload fields' classes.
85
+ * @param string $class Class name
86
+ */
87
+ public function autoload( $class )
88
+ {
89
+ // Only load plugin's classes
90
+ if ( 'RW_Meta_Box' != $class && 0 !== strpos( $class, 'RWMB_' ) )
91
+ {
92
+ return;
93
+ }
94
+
95
+ // Get file name
96
+ $file = 'meta-box';
97
+ if ( 'RW_Meta_Box' != $class )
98
+ {
99
+ // Remove prefix 'RWMB_'
100
+ $file = substr( $class, 5 );
101
+
102
+ // Optional '_Field'
103
+ $file = preg_replace( '/_Field$/', '', $file );
104
+ }
105
+
106
+ $file = strtolower( str_replace( '_', '-', $file ) ) . '.php';
107
+
108
+ $dirs = array( RWMB_INC_DIR, RWMB_FIELDS_DIR, trailingslashit( RWMB_INC_DIR . 'walkers' ) );
109
+ foreach ( $dirs as $dir )
110
+ {
111
+ if ( file_exists( $dir . $file ) )
112
+ {
113
+ require $dir . $file;
114
+ return;
115
+ }
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Initialize plugin.
121
+ */
122
+ public function init()
123
+ {
124
+ // Plugin core
125
+ new RWMB_Core;
126
+
127
+ // Validation module
128
+ new RWMB_Validation;
129
+
130
+ // Public functions
131
+ require RWMB_INC_DIR . 'functions.php';
132
+ }
133
+ }
inc/meta-box.php CHANGED
@@ -1,469 +1,423 @@
1
  <?php
2
- // Prevent loading this file directly
3
- defined( 'ABSPATH' ) || exit;
4
 
5
- // Meta Box Class
6
- if ( ! class_exists( 'RW_Meta_Box' ) )
 
 
 
 
 
 
 
7
  {
8
  /**
9
- * A class to rapid develop meta boxes for custom & built in content types
10
- * Piggybacks on WordPress
11
- *
12
- * @author Rilwis
13
- * @author Co-Authors @see https://github.com/rilwis/meta-box
14
- * @license GNU GPL2+
15
- * @package RW Meta Box
16
  */
17
- class RW_Meta_Box
18
- {
19
- /**
20
- * @var array Meta box information
21
- */
22
- public $meta_box;
23
 
24
- /**
25
- * @var array Fields information
26
- */
27
- public $fields;
28
 
29
- /**
30
- * @var array Contains all field types of current meta box
31
- */
32
- public $types;
33
 
34
- /**
35
- * @var bool Used to prevent duplicated calls like revisions, manual hook to wp_insert_post, etc.
36
- */
37
- public $saved = false;
38
 
39
- /**
40
- * Create meta box based on given data
41
- *
42
- * @see demo/demo.php file for details
43
- *
44
- * @param array $meta_box Meta box definition
45
- *
46
- * @return RW_Meta_Box
47
- */
48
- function __construct( $meta_box )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  {
50
- // Run script only in admin area
51
- if ( ! is_admin() )
52
- return;
53
-
54
- // Assign meta box values to local variables and add it's missed values
55
- $this->meta_box = self::normalize( $meta_box );
56
- $this->fields = &$this->meta_box['fields'];
57
-
58
- // Allow users to show/hide meta box
59
- // 1st action applies to all meta boxes
60
- // 2nd action applies to only current meta box
61
- $show = true;
62
- $show = apply_filters( 'rwmb_show', $show, $this->meta_box );
63
- $show = apply_filters( "rwmb_show_{$this->meta_box['id']}", $show, $this->meta_box );
64
- if ( ! $show )
65
- return;
66
-
67
- // Enqueue common styles and scripts
68
- add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
69
-
70
- // Add additional actions for fields
71
- $fields = self::get_fields( $this->fields );
72
- foreach ( $fields as $field )
73
- {
74
- call_user_func( array( self::get_class_name( $field ), 'add_actions' ) );
75
- }
76
-
77
- // Add meta box
78
- add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
79
-
80
- // Hide meta box if it's set 'default_hidden'
81
- add_filter( 'default_hidden_meta_boxes', array( $this, 'hide' ), 10, 2 );
82
-
83
- // Save post meta
84
- foreach ( $this->meta_box['post_types'] as $post_type )
85
- {
86
- if ( 'attachment' === $post_type )
87
- {
88
- // Attachment uses other hooks
89
- // @see wp_update_post(), wp_insert_attachment()
90
- add_action( 'edit_attachment', array( $this, 'save_post' ) );
91
- add_action( 'add_attachment', array( $this, 'save_post' ) );
92
- }
93
- else
94
- {
95
- add_action( "save_post_{$post_type}", array( $this, 'save_post' ) );
96
- }
97
- }
98
  }
99
 
100
- /**
101
- * Enqueue common styles
102
- *
103
- * @return void
104
- */
105
- function admin_enqueue_scripts()
106
- {
107
- if ( ! $this->is_edit_screen() )
108
- return;
109
 
110
- wp_enqueue_style( 'rwmb', RWMB_CSS_URL . 'style.css', array(), RWMB_VER );
 
111
 
112
- // Load clone script conditionally
113
- $fields = self::get_fields( $this->fields );
114
- foreach ( $fields as $field )
 
115
  {
116
- if ( $field['clone'] )
117
- {
118
- wp_enqueue_script( 'rwmb-clone', RWMB_JS_URL . 'clone.js', array( 'jquery' ), RWMB_VER, true );
119
- break;
120
- }
121
  }
122
-
123
- // Enqueue scripts and styles for fields
124
- foreach ( $fields as $field )
125
  {
126
- call_user_func( array( self::get_class_name( $field ), 'admin_enqueue_scripts' ) );
127
  }
 
 
128
 
129
- // Auto save
130
- if ( $this->meta_box['autosave'] )
131
- wp_enqueue_script( 'rwmb-autosave', RWMB_JS_URL . 'autosave.js', array( 'jquery' ), RWMB_VER, true );
 
 
 
 
 
 
132
 
133
- /**
134
- * Allow developers to enqueue more scripts and styles
135
- *
136
- * @param RW_Meta_Box $object Meta Box object
137
- */
138
- do_action( 'rwmb_enqueue_scripts', $this );
139
- }
140
 
141
- /**
142
- * Get all fields of a meta box, recursively
143
- *
144
- * @param array $fields
145
- *
146
- * @return array
147
- */
148
- static function get_fields( $fields )
149
  {
150
- $all_fields = array();
151
- foreach ( $fields as $field )
152
  {
153
- $all_fields[] = $field;
154
- if ( isset( $field['fields'] ) )
155
- $all_fields = array_merge( $all_fields, self::get_fields( $field['fields'] ) );
156
  }
 
157
 
158
- return $all_fields;
 
 
 
159
  }
160
 
161
- /**************************************************
162
- * SHOW META BOX
163
- **************************************************/
164
 
165
  /**
166
- * Add meta box for multiple post types
167
  *
168
- * @return void
169
  */
170
- function add_meta_boxes()
 
 
 
 
 
 
 
 
 
 
 
 
 
171
  {
172
- foreach ( $this->meta_box['post_types'] as $post_type )
173
- {
174
- add_meta_box(
175
- $this->meta_box['id'],
176
- $this->meta_box['title'],
177
- array( $this, 'show' ),
178
- $post_type,
179
- $this->meta_box['context'],
180
- $this->meta_box['priority']
181
- );
182
- }
183
  }
184
 
185
- /**
186
- * Hide meta box if it's set 'default_hidden'
187
- *
188
- * @param array $hidden Array of default hidden meta boxes
189
- * @param object $screen Current screen information
190
- *
191
- * @return array
192
- */
193
- function hide( $hidden, $screen )
194
- {
195
- if ( $this->is_edit_screen( $screen ) && $this->meta_box['default_hidden'] )
196
- {
197
- $hidden[] = $this->meta_box['id'];
198
- }
199
 
200
- return $hidden;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  }
 
202
 
203
- /**
204
- * Callback function to show fields in meta box
205
- *
206
- * @return void
207
- */
208
- function show()
 
 
 
 
 
209
  {
210
- $saved = $this->is_saved();
 
211
 
212
- // Container
213
- printf(
214
- '<div class="rwmb-meta-box" data-autosave="%s">',
215
- $this->meta_box['autosave'] ? 'true' : 'false'
216
- );
217
 
218
- wp_nonce_field( "rwmb-save-{$this->meta_box['id']}", "nonce_{$this->meta_box['id']}" );
 
 
 
 
 
 
 
219
 
220
- // Allow users to add custom code before meta box content
221
- // 1st action applies to all meta boxes
222
- // 2nd action applies to only current meta box
223
- do_action( 'rwmb_before', $this );
224
- do_action( "rwmb_before_{$this->meta_box['id']}", $this );
225
 
226
- foreach ( $this->fields as $field )
227
- {
228
- call_user_func( array( self::get_class_name( $field ), 'show' ), $field, $saved );
229
- }
230
 
231
- // Allow users to add custom code after meta box content
232
- // 1st action applies to all meta boxes
233
- // 2nd action applies to only current meta box
234
- do_action( 'rwmb_after', $this );
235
- do_action( "rwmb_after_{$this->meta_box['id']}", $this );
236
 
237
- // End container
238
- echo '</div>';
 
239
  }
240
 
241
- /**************************************************
242
- * SAVE META BOX
243
- **************************************************/
 
 
244
 
245
- /**
246
- * Save data from meta box
247
- *
248
- * @param int $post_id Post ID
249
- *
250
- * @return void
251
- */
252
- function save_post( $post_id )
253
- {
254
- // Check if this function is called to prevent duplicated calls like revisions, manual hook to wp_insert_post, etc.
255
- if ( true === $this->saved )
256
- return;
257
- $this->saved = true;
258
-
259
- // Check whether form is submitted properly
260
- $id = $this->meta_box['id'];
261
- $nonce = isset( $_POST["nonce_{$id}"] ) ? sanitize_key( $_POST["nonce_{$id}"] ) : '';
262
- if ( empty( $_POST["nonce_{$id}"] ) || ! wp_verify_nonce( $nonce, "rwmb-save-{$id}" ) )
263
- return;
264
-
265
- // Autosave
266
- if ( defined( 'DOING_AUTOSAVE' ) && ! $this->meta_box['autosave'] )
267
- return;
268
-
269
- // Make sure meta is added to the post, not a revision
270
- if ( $the_post = wp_is_post_revision( $post_id ) )
271
- $post_id = $the_post;
272
-
273
- // Before save action
274
- do_action( 'rwmb_before_save_post', $post_id );
275
- do_action( "rwmb_{$this->meta_box['id']}_before_save_post", $post_id );
276
-
277
- foreach ( $this->fields as $field )
278
- {
279
- $name = $field['id'];
280
- $single = $field['clone'] || ! $field['multiple'];
281
- $old = get_post_meta( $post_id, $name, $single );
282
- $new = isset( $_POST[$name] ) ? $_POST[$name] : ( $single ? '' : array() );
283
-
284
- // Allow field class change the value
285
- $new = call_user_func( array( self::get_class_name( $field ), 'value' ), $new, $old, $post_id, $field );
286
-
287
- // Use filter to change field value
288
- // 1st filter applies to all fields with the same type
289
- // 2nd filter applies to current field only
290
- $new = apply_filters( "rwmb_{$field['type']}_value", $new, $field, $old );
291
- $new = apply_filters( "rwmb_{$name}_value", $new, $field, $old );
292
-
293
- // Call defined method to save meta value, if there's no methods, call common one
294
- call_user_func( array( self::get_class_name( $field ), 'save' ), $new, $old, $post_id, $field );
295
- }
296
 
297
- // After save action
298
- do_action( 'rwmb_after_save_post', $post_id );
299
- do_action( "rwmb_{$this->meta_box['id']}_after_save_post", $post_id );
300
- }
301
 
302
- /**************************************************
303
- * HELPER FUNCTIONS
304
- **************************************************/
 
 
 
 
 
 
 
 
305
 
306
- /**
307
- * Normalize parameters for meta box
308
- *
309
- * @param array $meta_box Meta box definition
310
- *
311
- * @return array $meta_box Normalized meta box
312
- */
313
- static function normalize( $meta_box )
314
- {
315
- // Set default values for meta box
316
- $meta_box = wp_parse_args( $meta_box, array(
317
- 'id' => sanitize_title( $meta_box['title'] ),
318
- 'context' => 'normal',
319
- 'priority' => 'high',
320
- 'post_types' => 'post',
321
- 'autosave' => false,
322
- 'default_hidden' => false,
323
- ) );
324
-
325
- /**
326
- * Use 'post_types' for better understanding and fallback to 'pages' for previous versions
327
- *
328
- * @since 4.4.1
329
- */
330
- if ( ! empty( $meta_box['pages'] ) )
331
- {
332
- $meta_box['post_types'] = $meta_box['pages'];
333
- }
334
 
335
- // Allow to set 'post_types' param by string
336
- if ( is_string( $meta_box['post_types'] ) )
337
- {
338
- $meta_box['post_types'] = array( $meta_box['post_types'] );
339
- }
340
 
341
- // Set default values for fields
342
- $meta_box['fields'] = self::normalize_fields( $meta_box['fields'] );
 
343
 
344
- // Allow to add default values for meta box
345
- $meta_box = apply_filters( 'rwmb_normalize_meta_box', $meta_box );
346
- $meta_box = apply_filters( "rwmb_normalize_{$meta_box['id']}_meta_box", $meta_box );
347
 
348
- return $meta_box;
 
 
 
 
 
 
 
 
 
 
 
 
349
  }
350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  /**
352
- * Normalize an array of fields
353
  *
354
- * @param array $fields Array of fields
355
- *
356
- * @return array $fields Normalized fields
357
  */
358
- static function normalize_fields( $fields )
359
  {
360
- foreach ( $fields as $k => $field )
361
- {
362
- $field = wp_parse_args( $field, array(
363
- 'id' => '',
364
- 'name' => '',
365
- 'multiple' => false,
366
- 'std' => '',
367
- 'desc' => '',
368
- 'format' => '',
369
- 'before' => '',
370
- 'after' => '',
371
- 'field_name' => isset( $field['id'] ) ? $field['id'] : '',
372
- 'required' => false,
373
- 'placeholder' => '',
374
-
375
- 'clone' => false,
376
- 'max_clone' => 0,
377
- 'sort_clone' => false,
378
- ) );
379
-
380
- $class = self::get_class_name( $field );
381
-
382
- // Make sure field has correct 'type', ignore warning error when users forget to set field type or set incorrect one
383
- if ( false === $class )
384
- {
385
- unset( $fields[$k] );
386
- continue;
387
- }
388
-
389
- // Allow field class add/change default field values
390
- $field = call_user_func( array( $class, 'normalize_field' ), $field );
391
-
392
- if ( isset( $field['fields'] ) )
393
- $field['fields'] = self::normalize_fields( $field['fields'] );
394
-
395
- // Allow to add default values for fields
396
- $field = apply_filters( 'rwmb_normalize_field', $field );
397
- $field = apply_filters( "rwmb_normalize_{$field['type']}_field", $field );
398
- $field = apply_filters( "rwmb_normalize_{$field['id']}_field", $field );
399
-
400
- $fields[$k] = $field;
401
- }
402
-
403
- return $fields;
404
  }
405
 
406
- /**
407
- * Get field class name
408
- *
409
- * @param array $field Field array
410
- *
411
- * @return bool|string Field class name OR false on failure
412
- */
413
- static function get_class_name( $field )
414
  {
415
- // Convert underscores to whitespace so ucwords works as expected. Otherwise: plupload_image -> Plupload_image instead of Plupload_Image
416
- $type = str_replace( '_', ' ', $field['type'] );
417
 
418
- // Uppercase first words
419
- $class = 'RWMB_' . ucwords( $type ) . '_Field';
420
 
421
- // Relace whitespace with underscores
422
- $class = str_replace( ' ', '_', $class );
 
423
 
424
- return class_exists( $class ) ? $class : false;
425
- }
426
 
427
- /**
428
- * Check if meta box is saved before.
429
- * This helps saving empty value in meta fields (for text box, check box, etc.) and set the correct
430
- * default values.
431
- *
432
- * @return bool
433
- */
434
- public function is_saved()
 
 
435
  {
436
- $post = get_post();
437
 
438
- foreach ( $this->fields as $field )
 
439
  {
440
- $value = get_post_meta( $post->ID, $field['id'], ! $field['multiple'] );
441
- if (
442
- ( ! $field['multiple'] && '' !== $value )
443
- || ( $field['multiple'] && array() !== $value )
444
- )
445
- {
446
- return true;
447
- }
448
  }
449
 
450
- return false;
 
 
 
 
 
 
 
 
 
 
 
451
  }
452
 
453
- /**
454
- * Check if we're on the right edit screen.
455
- *
456
- * @param WP_Screen $screen Screen object. Optional. Use current screen object by default.
457
- *
458
- * @return bool
459
- */
460
- function is_edit_screen( $screen = null )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
  {
462
- if ( ! ( $screen instanceof WP_Screen ) )
 
 
 
 
463
  {
464
- $screen = get_current_screen();
465
  }
466
- return 'post' == $screen->base && in_array( $screen->post_type, $this->meta_box['post_types'] );
467
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  }
469
  }
1
  <?php
 
 
2
 
3
+ /**
4
+ * A class to rapid develop meta boxes for custom & built in content types
5
+ * Piggybacks on WordPress
6
+ *
7
+ * @author Tran Ngoc Tuan Anh <rilwis@gmail.com>
8
+ * @license GNU GPL2+
9
+ * @package Meta Box
10
+ */
11
+ class RW_Meta_Box
12
  {
13
  /**
14
+ * @var array Meta box information
 
 
 
 
 
 
15
  */
16
+ public $meta_box;
 
 
 
 
 
17
 
18
+ /**
19
+ * @var array Fields information
20
+ */
21
+ public $fields;
22
 
23
+ /**
24
+ * @var array Contains all field types of current meta box
25
+ */
26
+ public $types;
27
 
28
+ /**
29
+ * @var bool Used to prevent duplicated calls like revisions, manual hook to wp_insert_post, etc.
30
+ */
31
+ public $saved = false;
32
 
33
+ /**
34
+ * Create meta box based on given data
35
+ * @param array $meta_box Meta box definition
36
+ */
37
+ function __construct( $meta_box )
38
+ {
39
+ // Run script only in admin area
40
+ if ( ! is_admin() )
41
+ return;
42
+
43
+ // Assign meta box values to local variables and add it's missed values
44
+ $this->meta_box = self::normalize( $meta_box );
45
+ $this->fields = &$this->meta_box['fields'];
46
+
47
+ // Allow users to show/hide meta box
48
+ // 1st action applies to all meta boxes
49
+ // 2nd action applies to only current meta box
50
+ $show = true;
51
+ $show = apply_filters( 'rwmb_show', $show, $this->meta_box );
52
+ $show = apply_filters( "rwmb_show_{$this->meta_box['id']}", $show, $this->meta_box );
53
+ if ( ! $show )
54
+ return;
55
+
56
+ // Enqueue common styles and scripts
57
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
58
+
59
+ // Add additional actions for fields
60
+ $fields = self::get_fields( $this->fields );
61
+ foreach ( $fields as $field )
62
  {
63
+ call_user_func( array( self::get_class_name( $field ), 'add_actions' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  }
65
 
66
+ // Add meta box
67
+ add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
 
 
 
 
 
 
 
68
 
69
+ // Hide meta box if it's set 'default_hidden'
70
+ add_filter( 'default_hidden_meta_boxes', array( $this, 'hide' ), 10, 2 );
71
 
72
+ // Save post meta
73
+ foreach ( $this->meta_box['post_types'] as $post_type )
74
+ {
75
+ if ( 'attachment' === $post_type )
76
  {
77
+ // Attachment uses other hooks
78
+ // @see wp_update_post(), wp_insert_attachment()
79
+ add_action( 'edit_attachment', array( $this, 'save_post' ) );
80
+ add_action( 'add_attachment', array( $this, 'save_post' ) );
 
81
  }
82
+ else
 
 
83
  {
84
+ add_action( "save_post_{$post_type}", array( $this, 'save_post' ) );
85
  }
86
+ }
87
+ }
88
 
89
+ /**
90
+ * Enqueue common styles
91
+ *
92
+ * @return void
93
+ */
94
+ function admin_enqueue_scripts()
95
+ {
96
+ if ( ! $this->is_edit_screen() )
97
+ return;
98
 
99
+ wp_enqueue_style( 'rwmb', RWMB_CSS_URL . 'style.css', array(), RWMB_VER );
 
 
 
 
 
 
100
 
101
+ // Load clone script conditionally
102
+ $fields = self::get_fields( $this->fields );
103
+ foreach ( $fields as $field )
 
 
 
 
 
104
  {
105
+ if ( $field['clone'] )
 
106
  {
107
+ wp_enqueue_script( 'rwmb-clone', RWMB_JS_URL . 'clone.js', array( 'jquery-ui-sortable' ), RWMB_VER, true );
108
+ break;
 
109
  }
110
+ }
111
 
112
+ // Enqueue scripts and styles for fields
113
+ foreach ( $fields as $field )
114
+ {
115
+ call_user_func( array( self::get_class_name( $field ), 'admin_enqueue_scripts' ) );
116
  }
117
 
118
+ // Auto save
119
+ if ( $this->meta_box['autosave'] )
120
+ wp_enqueue_script( 'rwmb-autosave', RWMB_JS_URL . 'autosave.js', array( 'jquery' ), RWMB_VER, true );
121
 
122
  /**
123
+ * Allow developers to enqueue more scripts and styles
124
  *
125
+ * @param RW_Meta_Box $object Meta Box object
126
  */
127
+ do_action( 'rwmb_enqueue_scripts', $this );
128
+ }
129
+
130
+ /**
131
+ * Get all fields of a meta box, recursively
132
+ *
133
+ * @param array $fields
134
+ *
135
+ * @return array
136
+ */
137
+ static function get_fields( $fields )
138
+ {
139
+ $all_fields = array();
140
+ foreach ( $fields as $field )
141
  {
142
+ $all_fields[] = $field;
143
+ if ( isset( $field['fields'] ) )
144
+ $all_fields = array_merge( $all_fields, self::get_fields( $field['fields'] ) );
 
 
 
 
 
 
 
 
145
  }
146
 
147
+ return $all_fields;
148
+ }
149
+
150
+ /**************************************************
151
+ * SHOW META BOX
152
+ **************************************************/
 
 
 
 
 
 
 
 
153
 
154
+ /**
155
+ * Add meta box for multiple post types
156
+ *
157
+ * @return void
158
+ */
159
+ function add_meta_boxes()
160
+ {
161
+ foreach ( $this->meta_box['post_types'] as $post_type )
162
+ {
163
+ add_meta_box(
164
+ $this->meta_box['id'],
165
+ $this->meta_box['title'],
166
+ array( $this, 'show' ),
167
+ $post_type,
168
+ $this->meta_box['context'],
169
+ $this->meta_box['priority']
170
+ );
171
  }
172
+ }
173
 
174
+ /**
175
+ * Hide meta box if it's set 'default_hidden'
176
+ *
177
+ * @param array $hidden Array of default hidden meta boxes
178
+ * @param object $screen Current screen information
179
+ *
180
+ * @return array
181
+ */
182
+ function hide( $hidden, $screen )
183
+ {
184
+ if ( $this->is_edit_screen( $screen ) && $this->meta_box['default_hidden'] )
185
  {
186
+ $hidden[] = $this->meta_box['id'];
187
+ }
188
 
189
+ return $hidden;
190
+ }
 
 
 
191
 
192
+ /**
193
+ * Callback function to show fields in meta box
194
+ *
195
+ * @return void
196
+ */
197
+ function show()
198
+ {
199
+ $saved = $this->is_saved();
200
 
201
+ // Container
202
+ printf(
203
+ '<div class="rwmb-meta-box" data-autosave="%s">',
204
+ $this->meta_box['autosave'] ? 'true' : 'false'
205
+ );
206
 
207
+ wp_nonce_field( "rwmb-save-{$this->meta_box['id']}", "nonce_{$this->meta_box['id']}" );
 
 
 
208
 
209
+ // Allow users to add custom code before meta box content
210
+ // 1st action applies to all meta boxes
211
+ // 2nd action applies to only current meta box
212
+ do_action( 'rwmb_before', $this );
213
+ do_action( "rwmb_before_{$this->meta_box['id']}", $this );
214
 
215
+ foreach ( $this->fields as $field )
216
+ {
217
+ call_user_func( array( self::get_class_name( $field ), 'show' ), $field, $saved );
218
  }
219
 
220
+ // Allow users to add custom code after meta box content
221
+ // 1st action applies to all meta boxes
222
+ // 2nd action applies to only current meta box
223
+ do_action( 'rwmb_after', $this );
224
+ do_action( "rwmb_after_{$this->meta_box['id']}", $this );
225
 
226
+ // End container
227
+ echo '</div>';
228
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
 
230
+ /**************************************************
231
+ * SAVE META BOX
232
+ **************************************************/
 
233
 
234
+ /**
235
+ * Save data from meta box
236
+ *
237
+ * @param int $post_id Post ID
238
+ */
239
+ function save_post( $post_id )
240
+ {
241
+ // Check if this function is called to prevent duplicated calls like revisions, manual hook to wp_insert_post, etc.
242
+ if ( true === $this->saved )
243
+ return;
244
+ $this->saved = true;
245
 
246
+ // Check whether form is submitted properly
247
+ $nonce = (string) filter_input( INPUT_POST, "nonce_{$this->meta_box['id']}" );
248
+ if ( ! wp_verify_nonce( $nonce, "rwmb-save-{$this->meta_box['id']}" ) )
249
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
 
251
+ // Autosave
252
+ if ( defined( 'DOING_AUTOSAVE' ) && ! $this->meta_box['autosave'] )
253
+ return;
 
 
254
 
255
+ // Make sure meta is added to the post, not a revision
256
+ if ( $the_post = wp_is_post_revision( $post_id ) )
257
+ $post_id = $the_post;
258
 
259
+ // Before save action
260
+ do_action( 'rwmb_before_save_post', $post_id );
261
+ do_action( "rwmb_{$this->meta_box['id']}_before_save_post", $post_id );
262
 
263
+ foreach ( $this->fields as $field )
264
+ {
265
+ $name = $field['id'];
266
+ $single = $field['clone'] || ! $field['multiple'];
267
+ $old = get_post_meta( $post_id, $name, $single );
268
+ $new = isset( $_POST[$name] ) ? $_POST[$name] : ( $single ? '' : array() );
269
+
270
+ // Allow field class change the value
271
+ $new = call_user_func( array( self::get_class_name( $field ), 'value' ), $new, $old, $post_id, $field );
272
+ $new = RWMB_Core::filter( 'value', $new, $field, $old );
273
+
274
+ // Call defined method to save meta value, if there's no methods, call common one
275
+ call_user_func( array( self::get_class_name( $field ), 'save' ), $new, $old, $post_id, $field );
276
  }
277
 
278
+ // After save action
279
+ do_action( 'rwmb_after_save_post', $post_id );
280
+ do_action( "rwmb_{$this->meta_box['id']}_after_save_post", $post_id );
281
+ }
282
+
283
+ /**************************************************
284
+ * HELPER FUNCTIONS
285
+ **************************************************/
286
+
287
+ /**
288
+ * Normalize parameters for meta box
289
+ *
290
+ * @param array $meta_box Meta box definition
291
+ *
292
+ * @return array $meta_box Normalized meta box
293
+ */
294
+ static function normalize( $meta_box )
295
+ {
296
+ // Set default values for meta box
297
+ $meta_box = wp_parse_args( $meta_box, array(
298
+ 'id' => sanitize_title( $meta_box['title'] ),
299
+ 'context' => 'normal',
300
+ 'priority' => 'high',
301
+ 'post_types' => 'post',
302
+ 'autosave' => false,
303
+ 'default_hidden' => false,
304
+ ) );
305
+
306
  /**
307
+ * Use 'post_types' for better understanding and fallback to 'pages' for previous versions
308
  *
309
+ * @since 4.4.1
 
 
310
  */
311
+ if ( ! empty( $meta_box['pages'] ) )
312
  {
313
+ $meta_box['post_types'] = $meta_box['pages'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
  }
315
 
316
+ // Allow to set 'post_types' param by string
317
+ if ( is_string( $meta_box['post_types'] ) )
 
 
 
 
 
 
318
  {
319
+ $meta_box['post_types'] = array( $meta_box['post_types'] );
320
+ }
321
 
322
+ // Set default values for fields
323
+ $meta_box['fields'] = self::normalize_fields( $meta_box['fields'] );
324
 
325
+ // Allow to add default values for meta box
326
+ $meta_box = apply_filters( 'rwmb_normalize_meta_box', $meta_box );
327
+ $meta_box = apply_filters( "rwmb_normalize_{$meta_box['id']}_meta_box", $meta_box );
328
 
329
+ return $meta_box;
330
+ }
331
 
332
+ /**
333
+ * Normalize an array of fields
334
+ *
335
+ * @param array $fields Array of fields
336
+ *
337
+ * @return array $fields Normalized fields
338
+ */
339
+ static function normalize_fields( $fields )
340
+ {
341
+ foreach ( $fields as $k => $field )
342
  {
343
+ $class = self::get_class_name( $field );
344
 
345
+ // Make sure field has correct 'type', ignore warning error when users forget to set field type or set incorrect one
346
+ if ( false === $class )
347
  {
348
+ unset( $fields[$k] );
349
+ continue;
 
 
 
 
 
 
350
  }
351
 
352
+ // Allow field class add/change default field values
353
+ $field = call_user_func( array( $class, 'normalize' ), $field );
354
+
355
+ if ( isset( $field['fields'] ) )
356
+ $field['fields'] = self::normalize_fields( $field['fields'] );
357
+
358
+ // Allow to add default values for fields
359
+ $field = apply_filters( 'rwmb_normalize_field', $field );
360
+ $field = apply_filters( "rwmb_normalize_{$field['type']}_field", $field );
361
+ $field = apply_filters( "rwmb_normalize_{$field['id']}_field", $field );
362
+
363
+ $fields[$k] = $field;
364
  }
365
 
366
+ return $fields;
367
+ }
368
+
369
+ /**
370
+ * Get field class name
371
+ *
372
+ * @param array $field Field array
373
+ * @return string Field class name
374
+ */
375
+ static function get_class_name( $field )
376
+ {
377
+ $type = str_replace( array( '-', '_' ), ' ', $field['type'] );
378
+ $class = 'RWMB_' . ucwords( $type ) . '_Field';
379
+ $class = str_replace( ' ', '_', $class );
380
+ return $class;
381
+ }
382
+
383
+ /**
384
+ * Check if meta box is saved before.
385
+ * This helps saving empty value in meta fields (for text box, check box, etc.) and set the correct default values.
386
+ *
387
+ * @return bool
388
+ */
389
+ public function is_saved()
390
+ {
391
+ $post = get_post();
392
+
393
+ foreach ( $this->fields as $field )
394
  {
395
+ $value = get_post_meta( $post->ID, $field['id'], ! $field['multiple'] );
396
+ if (
397
+ ( ! $field['multiple'] && '' !== $value )
398
+ || ( $field['multiple'] && array() !== $value )
399
+ )
400
  {
401
+ return true;
402
  }
 
403
  }
404
+
405
+ return false;
406
+ }
407
+
408
+ /**
409
+ * Check if we're on the right edit screen.
410
+ *
411
+ * @param WP_Screen $screen Screen object. Optional. Use current screen object by default.
412
+ *
413
+ * @return bool
414
+ */
415
+ function is_edit_screen( $screen = null )
416
+ {
417
+ if ( ! ( $screen instanceof WP_Screen ) )
418
+ {
419
+ $screen = get_current_screen();
420
+ }
421
+ return 'post' == $screen->base && in_array( $screen->post_type, $this->meta_box['post_types'] );
422
  }
423
  }
inc/validation.php CHANGED
@@ -1,41 +1,40 @@
1
  <?php
2
  /**
3
- * Validation module
4
  * @package Meta Box
5
  */
6
 
7
  /**
8
- * Validation class
9
  */
10
  class RWMB_Validation
11
  {
12
  /**
13
- * Add hooks when module is loaded
14
  */
15
- public static function load()
16
  {
17
- add_action( 'rwmb_after', array( __CLASS__, 'rules' ) );
18
- add_action( 'rwmb_enqueue_scripts', array( __CLASS__, 'scripts' ) );
19
  }
20
 
21
  /**
22
- * Output validation rules of each meta box
23
- * The rules are outputted in [data-rules] attribute of an hidden div and will be converted into JSON by JS
24
  * @param RW_Meta_Box $object Meta Box object
25
  */
26
- public static function rules( RW_Meta_Box $object )
27
  {
28
  if ( ! empty( $object->meta_box['validation'] ) )
29
  {
30
- // Use script tag with type="text/html" to prevent browser to render
31
- echo '<script type="text/html" class="rwmb-validation-rules hidden" data-rules="' . esc_attr( json_encode( $object->meta_box['validation'] ) ) . '"></script>';
32
  }
33
  }
34
 
35
  /**
36
- * Enqueue scripts for validation
37
  */
38
- public static function scripts()
39
  {
40
  wp_enqueue_script( 'jquery-validate', RWMB_JS_URL . 'jquery.validate.min.js', array( 'jquery' ), RWMB_VER, true );
41
  wp_enqueue_script( 'rwmb-validate', RWMB_JS_URL . 'validate.js', array( 'jquery-validate' ), RWMB_VER, true );
@@ -44,5 +43,3 @@ class RWMB_Validation
44
  ) );
45
  }
46
  }
47
-
48
- RWMB_Validation::load();
1
  <?php
2
  /**
3
+ * Validation module.
4
  * @package Meta Box
5
  */
6
 
7
  /**
8
+ * Validation class.
9
  */
10
  class RWMB_Validation
11
  {
12
  /**
13
+ * Add hooks when module is loaded.
14
  */
15
+ public function __construct()
16
  {
17
+ add_action( 'rwmb_after', array( $this, 'rules' ) );
18
+ add_action( 'rwmb_enqueue_scripts', array( $this, 'scripts' ) );
19
  }
20
 
21
  /**
22
+ * Output validation rules of each meta box.
23
+ * The rules are outputted in [data-rules] attribute of an hidden <script> and will be converted into JSON by JS.
24
  * @param RW_Meta_Box $object Meta Box object
25
  */
26
+ public function rules( RW_Meta_Box $object )
27
  {
28
  if ( ! empty( $object->meta_box['validation'] ) )
29
  {
30
+ echo '<script type="text/html" class="rwmb-validation-rules" data-rules="' . esc_attr( json_encode( $object->meta_box['validation'] ) ) . '"></script>';
 
31
  }
32
  }
33
 
34
  /**
35
+ * Enqueue scripts for validation.
36
  */
37
+ public function scripts()
38
  {
39
  wp_enqueue_script( 'jquery-validate', RWMB_JS_URL . 'jquery.validate.min.js', array( 'jquery' ), RWMB_VER, true );
40
  wp_enqueue_script( 'rwmb-validate', RWMB_JS_URL . 'validate.js', array( 'jquery-validate' ), RWMB_VER, true );
43
  ) );
44
  }
45
  }
 
 
inc/walkers/choice-list-walker.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Choice List Walker
4
+ * For checkbox and radio list fields
5
+ */
6
+ class RWMB_Choice_List_Walker extends RWMB_Walker
7
+ {
8
+ /**
9
+ * @see Walker::start_lvl()
10
+ *
11
+ * @param string $output Passed by reference. Used to append additional content.
12
+ * @param int $depth Depth of item.
13
+ * @param array $args
14
+ */
15
+ public function start_lvl( &$output, $depth = 0, $args = array() )
16
+ {
17
+ $output .= "<ul class='rwmb-choice-list'>";
18
+ }
19
+
20
+ /**
21
+ * @see Walker::end_lvl()
22
+ *
23
+ * @param string $output Passed by reference. Used to append additional content.
24
+ * @param int $depth Depth of item.
25
+ * @param array $args
26
+ */
27
+ public function end_lvl( &$output, $depth = 0, $args = array() )
28
+ {
29
+ $output .= "</ul>";
30
+ }
31
+
32
+ /**
33
+ * @see Walker::start_el()
34
+ *
35
+ * @param string $output Passed by reference. Used to append additional content.
36
+ * @param object $object Item data object.
37
+ * @param int $depth Depth of item.
38
+ * @param int $current_object_id Item ID.
39
+ * @param array $args
40
+ */
41
+ public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 )
42
+ {
43
+ $label = $this->db_fields['label'];
44
+ $id = $this->db_fields['id'];
45
+ $meta = $this->meta;
46
+ $field = $this->field;
47
+ $field_class = RW_Meta_Box::get_class_name( $field );
48
+ $attributes = call_user_func( array( $field_class, 'get_attributes' ), $field, $object->$id );
49
+
50
+ $output .= sprintf(
51
+ '<li><label><input %s %s>%s</label>',
52
+ RWMB_Field::render_attributes( $attributes ),
53
+ checked( in_array( $object->$id, $meta ), 1, false ),
54
+ $object->$label
55
+ );
56
+ }
57
+
58
+ /**
59
+ * @see Walker::end_el()
60
+ *
61
+ * @param string $output Passed by reference. Used to append additional content.
62
+ * @param object $page Page data object. Not used.
63
+ * @param int $depth Depth of page. Not Used.
64
+ * @param array $args
65
+ */
66
+ public function end_el( &$output, $page, $depth = 0, $args = array() )
67
+ {
68
+ $output .= "</li>";
69
+ }
70
+ }
inc/walkers/select-tree-walker.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Select Tree Walker for cascading select fields.
4
+ * @uses RWMB_Select_Walker
5
+ */
6
+ class RWMB_Select_Tree_Walker
7
+ {
8
+ /**
9
+ * Field data.
10
+ * @var string
11
+ */
12
+ public $field;
13
+
14
+ /**
15
+ * Field meta value.
16
+ * @var array
17
+ */
18
+ public $meta = array();
19
+
20
+ function __construct( $db_fields, $field, $meta )
21
+ {
22
+ $this->db_fields = wp_parse_args( (array) $db_fields, array(
23
+ 'parent' => '',
24
+ 'id' => '',
25
+ 'label' => '',
26
+ ) );
27
+ $this->field = $field;
28
+ $this->meta = (array) $meta;
29
+ }
30
+
31
+ function walk( $options )
32
+ {
33
+ $parent = $this->db_fields['parent'];
34
+ $children = array();
35
+
36
+ foreach ( $options as $o )
37
+ {
38
+ $children[$o->$parent][] = $o;
39
+ }
40
+ $top_level = isset( $children[0] ) ? 0 : $options[0]->$parent;
41
+ return $this->display_level( $children, $top_level, true );
42
+ }
43
+
44
+ function display_level( $options, $parent_id = 0, $active = false )
45
+ {
46
+ $id = $this->db_fields['id'];
47
+ $field = $this->field;
48
+ $meta = $this->meta;
49
+ $walker = new RWMB_Select_Walker( $this->db_fields, $this->field, $this->meta );
50
+ $field_class = RW_Meta_Box::get_class_name( $field );
51
+ $attributes = call_user_func( array( $field_class, 'get_attributes' ), $field, $meta );
52
+
53
+ $children = $options[$parent_id];
54
+ $output = sprintf(
55
+ '<div class="rwmb-select-tree %s" data-parent-id="%s"><select %s>',
56
+ $active ? '' : 'hidden',
57
+ $parent_id,
58
+ RWMB_Field::render_attributes( $attributes )
59
+ );
60
+ $output .= isset( $field['placeholder'] ) ? "<option value=''>{$field['placeholder']}</option>" : '<option></option>';
61
+ $output .= $walker->walk( $children, - 1 );
62
+ $output .= '</select>';
63
+
64
+ foreach ( $children as $c )
65
+ {
66
+ if ( isset( $options[$c->$id] ) )
67
+ {
68
+ $output .= $this->display_level( $options, $c->$id, in_array( $c->$id, $meta ) && $active );
69
+ }
70
+ }
71
+
72
+ $output .= '</div>';
73
+ return $output;
74
+ }
75
+ }
inc/walkers/select-walker.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Select Walker
4
+ * For generating Select fields
5
+ */
6
+ class RWMB_Select_Walker extends RWMB_Walker
7
+ {
8
+ /**
9
+ * @see Walker::start_el()
10
+ *
11
+ * @param string $output Passed by reference. Used to append additional content.
12
+ * @param object $object Item
13
+ * @param int $depth Depth of Item.
14
+ * @param int $current_object_id Item id.
15
+ * @param array $args
16
+ */
17
+ public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 )
18
+ {
19
+ $label = $this->db_fields['label'];
20
+ $id = $this->db_fields['id'];
21
+ $meta = $this->meta;
22
+ $indent = str_repeat( "&nbsp;", $depth * 4 );
23
+
24
+ $output .= sprintf(
25
+ '<option value="%s" %s>%s%s</option>',
26
+ $object->$id,
27
+ selected( in_array( $object->$id, $meta ), 1, false ),
28
+ $indent,
29
+ $object->$label
30
+ );
31
+ }
32
+ }
inc/walkers/walker.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Base Walker
4
+ * Walkers must inherit this class and overwrite methods with its own.
5
+ */
6
+ abstract class RWMB_Walker extends Walker
7
+ {
8
+ /**
9
+ * Field data.
10
+ *
11
+ * @access public
12
+ * @var array
13
+ */
14
+ public $field;
15
+
16
+ /**
17
+ * Meta data.
18
+ *
19
+ * @access public
20
+ * @var array
21
+ */
22
+ public $meta = array();
23
+
24
+ function __construct( $db_fields, $field, $meta )
25
+ {
26
+ $this->db_fields = wp_parse_args( (array) $db_fields, array(
27
+ 'parent' => '',
28
+ 'id' => '',
29
+ 'label' => '',
30
+ ) );
31
+ $this->field = $field;
32
+ $this->meta = (array) $meta;
33
+ }
34
+ }
js/autocomplete.js CHANGED
@@ -9,26 +9,19 @@ jQuery( function ( $ )
9
  function updateAutocomplete( e )
10
  {
11
  var $this = $( this ),
12
- $result = $this.next(),
13
- name = $this.data( 'name' );
 
14
 
15
  // If the function is called on cloning, then change the field name and clear all results
16
  // @see clone.js
17
  if ( e.hasOwnProperty( 'type' ) && 'clone' == e.type )
18
  {
19
- name = name.replace( /\[(\d+)\]/, function ( match, p1 )
20
- {
21
- return '[' + ( parseInt( p1, 10 ) + 1 ) + ']';
22
- } );
23
-
24
- // Update the "data-name" attribute for further cloning
25
- $this.attr( 'data-name', name );
26
-
27
  // Clear all results
28
  $result.html( '' );
29
  }
30
 
31
- $this.removeClass( 'ui-autocomplete-input' ).attr( 'id', '' )
32
  .autocomplete( {
33
  minLength: 0,
34
  source : $this.data( 'options' ),
@@ -43,14 +36,14 @@ jQuery( function ( $ )
43
  );
44
 
45
  // Reinitialize value
46
- this.value = '';
47
 
48
  return false;
49
  }
50
  } );
51
  }
52
 
53
- $( '.rwmb-autocomplete-wrapper input[type="text"]' ).each( updateAutocomplete );
54
  $( '.rwmb-input' ).on( 'clone', ':input.rwmb-autocomplete', updateAutocomplete );
55
 
56
  // Handle remove action
@@ -59,4 +52,4 @@ jQuery( function ( $ )
59
  // remove result
60
  $( this ).parent().remove();
61
  } );
62
- } );
9
  function updateAutocomplete( e )
10
  {
11
  var $this = $( this ),
12
+ $search = $this.siblings( '.rwmb-autocomplete-search'),
13
+ $result = $this.siblings( '.rwmb-autocomplete-results' ),
14
+ name = $this.attr( 'name' );
15
 
16
  // If the function is called on cloning, then change the field name and clear all results
17
  // @see clone.js
18
  if ( e.hasOwnProperty( 'type' ) && 'clone' == e.type )
19
  {
 
 
 
 
 
 
 
 
20
  // Clear all results
21
  $result.html( '' );
22
  }
23
 
24
+ $search.removeClass( 'ui-autocomplete-input' )
25
  .autocomplete( {
26
  minLength: 0,
27
  source : $this.data( 'options' ),
36
  );
37
 
38
  // Reinitialize value
39
+ $search.val( '' );
40
 
41
  return false;
42
  }
43
  } );
44
  }
45
 
46
+ $( '.rwmb-autocomplete-wrapper input[type="hidden"]' ).each( updateAutocomplete );
47
  $( '.rwmb-input' ).on( 'clone', ':input.rwmb-autocomplete', updateAutocomplete );
48
 
49
  // Handle remove action
52
  // remove result
53
  $( this ).parent().remove();
54
  } );
55
+ } );
js/clone.js CHANGED
@@ -6,25 +6,12 @@ jQuery( function ( $ )
6
 
7
  // Object holds all methods related to fields' index when clone
8
  var cloneIndex = {
9
- /**
10
- * Reset index for fields in .rwmb-clone
11
- * Must be done when add/remove or sort clone
12
- * @param $container A div container which has all fields
13
- */
14
- reset : function ( $container )
15
- {
16
- var index = 0;
17
- $container.find( '.rwmb-clone' ).each( function ()
18
- {
19
- cloneIndex.set( $( this ), index++ );
20
- } );
21
- },
22
  /**
23
  * Set index for fields in a .rwmb-clone
24
  * @param $clone .rwmb-clone element
25
  * @param index Index value
26
  */
27
- set : function ( $clone, index )
28
  {
29
  $clone.find( ':input[class|="rwmb"]' ).each( function ()
30
  {
@@ -38,7 +25,7 @@ jQuery( function ( $ )
38
  }
39
 
40
  // ID attribute
41
- var id = $field.attr( 'id' );
42
  if ( id )
43
  {
44
  $field.attr( 'id', cloneIndex.replace( index, id, '_' ) );
@@ -53,6 +40,7 @@ jQuery( function ( $ )
53
  $address.attr( 'value', cloneIndex.replace( index, value, '_' ) );
54
  }
55
  },
 
56
  /**
57
  * Replace an attribute of a field with updated index
58
  * @param index New index value
@@ -62,7 +50,7 @@ jQuery( function ( $ )
62
  * @param alternative Check if attribute does not contain any integer, will reset the attribute?
63
  * @return string
64
  */
65
- replace : function ( index, value, before, after, alternative )
66
  {
67
  before = before || '';
68
  after = after || '';
@@ -73,6 +61,7 @@ jQuery( function ( $ )
73
 
74
  return regex.test( value ) ? value.replace( regex, newValue ) : (alternative ? value + newValue : value );
75
  },
 
76
  /**
77
  * Helper function to escape string in regular expression
78
  * @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
@@ -82,6 +71,18 @@ jQuery( function ( $ )
82
  escapeRegex: function ( string )
83
  {
84
  return string.replace( /[.*+?^${}()|[\]\\]/g, "\\$&" );
 
 
 
 
 
 
 
 
 
 
 
 
85
  }
86
  };
87
 
@@ -94,16 +95,23 @@ jQuery( function ( $ )
94
  {
95
  var $last = $container.children( '.rwmb-clone:last' ),
96
  $clone = $last.clone(),
97
- $input = $clone.find( ':input[class|="rwmb"]' );
 
98
 
 
99
  $input.each( function ()
100
  {
101
  var $field = $( this );
102
- if ( $field.attr( 'type' ) === 'radio' || $field.attr( 'type' ) === 'checkbox' )
103
  {
104
  // Reset 'checked' attribute
105
  $field.prop( 'checked', false );
106
  }
 
 
 
 
 
107
  else
108
  {
109
  // Reset value
@@ -111,14 +119,13 @@ jQuery( function ( $ )
111
  }
112
  } );
113
 
 
114
  $clone.insertAfter( $last );
115
- cloneIndex.reset( $container );
116
-
117
- // Toggle remove buttons
118
- toggleRemoveButtons( $input );
119
 
120
  // Trigger custom clone event
121
- $input.trigger( 'clone' );
122
  }
123
 
124
  /**
@@ -131,7 +138,7 @@ jQuery( function ( $ )
131
  function toggleRemoveButtons( $container )
132
  {
133
  var $button = $container.find( '.remove-clone' );
134
- $button[$button.length < 2 ? 'hide' : 'show']();
135
  }
136
 
137
  /**
@@ -148,7 +155,7 @@ jQuery( function ( $ )
148
  maxClone = parseInt( $container.data( 'max-clone' ) ),
149
  numClone = $container.find( '.rwmb-clone' ).length;
150
 
151
- $button[isNaN( maxClone ) || (maxClone && numClone < maxClone) ? 'show' : 'hide']();
152
  }
153
 
154
  /**
@@ -243,19 +250,16 @@ jQuery( function ( $ )
243
  //Trigger custom clone event
244
  textarea.trigger( 'clone' );
245
  }
246
-
247
  }
248
 
249
- $( '#poststuff' )
250
- // Add clones
251
  .on( 'click', '.add-clone', function ( e )
252
  {
253
  e.preventDefault();
254
 
255
  var $container = $( this ).closest( '.rwmb-input' );
256
 
257
- cloneIndex.reset( $container );
258
-
259
  if ( $( this ).closest( '.rwmb-field' ).hasClass( 'rwmb-wysiwyg-wrapper' ) )
260
  {
261
  cloneWYSIWYG( $container );
@@ -283,7 +287,6 @@ jQuery( function ( $ )
283
  }
284
 
285
  $this.parent().trigger( 'remove' ).remove();
286
- cloneIndex.reset( $container );
287
  toggleRemoveButtons( $container );
288
  toggleAddButton( $container )
289
  } );
@@ -291,23 +294,20 @@ jQuery( function ( $ )
291
  $( '.rwmb-input' ).each( function ()
292
  {
293
  var $container = $( this );
294
- cloneIndex.reset( $container );
295
  toggleRemoveButtons( $container );
296
  toggleAddButton( $container );
297
 
298
- $container.sortable( {
299
- handle : '.rwmb-clone-icon',
300
- placeholder: ' rwmb-clone rwmb-clone-placeholder',
301
- items : '.rwmb-clone',
302
- start : function ( event, ui )
303
- {
304
- // Make the placeholder has the same height as dragged item
305
- ui.placeholder.height( ui.item.height() );
306
- },
307
- update : function ()
308
- {
309
- cloneIndex.reset( $container );
310
- }
311
- } );
312
  } );
313
  } );
6
 
7
  // Object holds all methods related to fields' index when clone
8
  var cloneIndex = {
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  /**
10
  * Set index for fields in a .rwmb-clone
11
  * @param $clone .rwmb-clone element
12
  * @param index Index value
13
  */
14
+ set: function ( $clone, index )
15
  {
16
  $clone.find( ':input[class|="rwmb"]' ).each( function ()
17
  {
25
  }
26
 
27
  // ID attribute
28
+ var id = this.id;
29
  if ( id )
30
  {
31
  $field.attr( 'id', cloneIndex.replace( index, id, '_' ) );
40
  $address.attr( 'value', cloneIndex.replace( index, value, '_' ) );
41
  }
42
  },
43
+
44
  /**
45
  * Replace an attribute of a field with updated index
46
  * @param index New index value
50
  * @param alternative Check if attribute does not contain any integer, will reset the attribute?
51
  * @return string
52
  */
53
+ replace: function ( index, value, before, after, alternative )
54
  {
55
  before = before || '';
56
  after = after || '';
61
 
62
  return regex.test( value ) ? value.replace( regex, newValue ) : (alternative ? value + newValue : value );
63
  },
64
+
65
  /**
66
  * Helper function to escape string in regular expression
67
  * @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
71
  escapeRegex: function ( string )
72
  {
73
  return string.replace( /[.*+?^${}()|[\]\\]/g, "\\$&" );
74
+ },
75
+
76
+ /**
77
+ * Helper function to create next index for clones
78
+ * @param $container .rwmb-input container
79
+ * @return integer
80
+ */
81
+ nextIndex: function ( $container )
82
+ {
83
+ var nextIndex = $container.data( 'next-index' );
84
+ $container.data( 'next-index', nextIndex + 1 );
85
+ return nextIndex;
86
  }
87
  };
88
 
95
  {
96
  var $last = $container.children( '.rwmb-clone:last' ),
97
  $clone = $last.clone(),
98
+ $input = $clone.find( ':input[class|="rwmb"]' ),
99
+ nextIndex = cloneIndex.nextIndex( $container );
100
 
101
+ // Reset value for fields
102
  $input.each( function ()
103
  {
104
  var $field = $( this );
105
+ if ( $field.is( ':radio' ) || $field.is( ':checkbox' ) )
106
  {
107
  // Reset 'checked' attribute
108
  $field.prop( 'checked', false );
109
  }
110
+ else if ( $field.is( 'select' ) )
111
+ {
112
+ // Reset select to first
113
+ $field.prop( 'selectedIndex', 0 )
114
+ }
115
  else
116
  {
117
  // Reset value
119
  }
120
  } );
121
 
122
+ // Insert Clone
123
  $clone.insertAfter( $last );
124
+ // Set fields index. Must run before trigger clone event.
125
+ cloneIndex.set( $clone, nextIndex );
 
 
126
 
127
  // Trigger custom clone event
128
+ $input.trigger( 'clone', nextIndex );
129
  }
130
 
131
  /**
138
  function toggleRemoveButtons( $container )
139
  {
140
  var $button = $container.find( '.remove-clone' );
141
+ $button.toggle( $button.length > 1 );
142
  }
143
 
144
  /**
155
  maxClone = parseInt( $container.data( 'max-clone' ) ),
156
  numClone = $container.find( '.rwmb-clone' ).length;
157
 
158
+ $button.toggle( isNaN( maxClone ) || ( maxClone && numClone < maxClone ) );
159
  }
160
 
161
  /**
250
  //Trigger custom clone event
251
  textarea.trigger( 'clone' );
252
  }
 
253
  }
254
 
255
+ $( '#wpbody-content' )
256
+ // Add clones
257
  .on( 'click', '.add-clone', function ( e )
258
  {
259
  e.preventDefault();
260
 
261
  var $container = $( this ).closest( '.rwmb-input' );
262
 
 
 
263
  if ( $( this ).closest( '.rwmb-field' ).hasClass( 'rwmb-wysiwyg-wrapper' ) )
264
  {
265
  cloneWYSIWYG( $container );
287
  }
288
 
289
  $this.parent().trigger( 'remove' ).remove();
 
290
  toggleRemoveButtons( $container );
291
  toggleAddButton( $container )
292
  } );
294
  $( '.rwmb-input' ).each( function ()
295
  {
296
  var $container = $( this );
 
297
  toggleRemoveButtons( $container );
298
  toggleAddButton( $container );
299
 
300
+ $container
301
+ .data( 'next-index', $container.children( '.rwmb-clone' ).length )
302
+ .sortable( {
303
+ handle : '.rwmb-clone-icon',
304
+ placeholder: ' rwmb-clone rwmb-clone-placeholder',
305
+ items : '.rwmb-clone',
306
+ start : function ( event, ui )
307
+ {
308
+ // Make the placeholder has the same height as dragged item
309
+ ui.placeholder.height( ui.item.height() );
310
+ }
311
+ } );
 
 
312
  } );
313
  } );
js/color.js CHANGED
@@ -3,13 +3,25 @@ jQuery( function ( $ )
3
  'use strict';
4
 
5
  /**
6
- * Show color pickers
7
- * @return void
8
  */
9
- function initColorPicker()
10
  {
11
  var $this = $( this ),
12
- $container = $this.closest( '.rwmb-color-clone' );
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  // Clone doesn't have input for color picker, we have to add the input and remove the color picker container
15
  if ( $container.length > 0 )
@@ -17,16 +29,10 @@ jQuery( function ( $ )
17
  $this.appendTo( $container ).siblings( '.wp-picker-container' ).remove();
18
  }
19
 
20
- // Make sure the value is displayed
21
- if ( !$this.val() )
22
- {
23
- $this.val( '#' );
24
- }
25
-
26
  // Show color picker
27
- $this.wpColorPicker( $this.data( 'options' ) );
28
  }
29
 
30
- $( ':input.rwmb-color' ).each( initColorPicker );
31
- $( '.rwmb-input' ).on( 'clone', 'input.rwmb-color', initColorPicker );
32
  } );
3
  'use strict';
4
 
5
  /**
6
+ * Update color picker element
7
+ * Used for static & dynamic added elements (when clone)
8
  */
9
+ function update()
10
  {
11
  var $this = $( this ),
12
+ $container = $this.closest( '.rwmb-color-clone' ),
13
+ data = $.extend(
14
+ {
15
+ change: function()
16
+ {
17
+ $( this ).trigger( 'color:change' );
18
+ },
19
+ clear: function()
20
+ {
21
+ $( this ).trigger( 'color:clear' );
22
+ }
23
+ },
24
+ $this.data( 'options' ) );
25
 
26
  // Clone doesn't have input for color picker, we have to add the input and remove the color picker container
27
  if ( $container.length > 0 )
29
  $this.appendTo( $container ).siblings( '.wp-picker-container' ).remove();
30
  }
31
 
 
 
 
 
 
 
32
  // Show color picker
33
+ $this.wpColorPicker( data );
34
  }
35
 
36
+ $( ':input.rwmb-color' ).each( update );
37
+ $( '.rwmb-input' ).on( 'clone', 'input.rwmb-color', update );
38
  } );
js/date.js CHANGED
@@ -12,7 +12,7 @@ jQuery( function ( $ )
12
  options = $this.data( 'options' );
13
 
14
  $this.siblings( '.ui-datepicker-append' ).remove(); // Remove appended text
15
- $this.removeClass( 'hasDatepicker' ).attr( 'id', '' ).datepicker( options );
16
  }
17
 
18
  $( ':input.rwmb-date' ).each( update );
12
  options = $this.data( 'options' );
13
 
14
  $this.siblings( '.ui-datepicker-append' ).remove(); // Remove appended text
15
+ $this.removeClass( 'hasDatepicker' ).datepicker( options );
16
  }
17
 
18
  $( ':input.rwmb-date' ).each( update );
js/datetime.js CHANGED
@@ -12,7 +12,7 @@ jQuery( function ( $ )
12
  options = $this.data( 'options' );
13
 
14
  $this.siblings( '.ui-datepicker-append' ).remove(); // Remove appended text
15
- $this.removeClass( 'hasDatepicker' ).attr( 'id', '' ).datetimepicker( options );
16
 
17
  }
18
 
12
  options = $this.data( 'options' );
13
 
14
  $this.siblings( '.ui-datepicker-append' ).remove(); // Remove appended text
15
+ $this.removeClass( 'hasDatepicker' ).datetimepicker( options );
16
 
17
  }
18
 
js/media.js CHANGED
@@ -8,8 +8,8 @@ jQuery( function ( $ )
8
  MediaField, MediaList, MediaItem, ImageField, ImageList, ImageItem, MediaButton, MediaStatus, UploadButton;
9
 
10
  MediaList = views.MediaList = Backbone.View.extend( {
11
- tagName : 'ul',
12
- className : 'rwmb-media-list',
13
  createItemView: function ( options )
14
  {
15
  return new MediaItem( options );
@@ -49,26 +49,7 @@ jQuery( function ( $ )
49
  } );
50
 
51
  //Sort media using sortable
52
- this.$el.sortable( {
53
- stop : function ( event, ui )
54
- {
55
- that.$el.children().each( function ()
56
- {
57
- var cid = $( this ).data( 'cid' );
58
-
59
- if ( cid )
60
- {
61
- var model = that.collection.get( cid );
62
- if ( model )
63
- {
64
- that.collection.remove( model );
65
- that.collection.add( model );
66
- }
67
- }
68
- } );
69
- },
70
- delay: 150
71
- } );
72
 
73
  this.render();
74
  }
@@ -82,25 +63,13 @@ jQuery( function ( $ )
82
  } );
83
 
84
  MediaField = views.MediaField = Backbone.View.extend( {
85
- events: {
86
- destroy: function ()
87
- {
88
- if ( this.forceDelete )
89
- {
90
- _.each( _.clone( this.collection.models ), function ( model )
91
- {
92
- model.destroy();
93
- } );
94
- }
95
- }
96
- },
97
-
98
  initialize: function ( options )
99
  {
100
  var that = this;
101
- this.input = $( options.input );
102
- this.values = this.input.val().split( ',' );
103
- this.props = this.$el.data();
 
104
 
105
  //Create collection
106
  this.collection = new wp.media.model.Attachments();
@@ -108,18 +77,11 @@ jQuery( function ( $ )
108
  //Render
109
  this.render();
110
 
111
- //Update input
112
- this.listenTo( this.collection, 'add remove reset', _.debounce( function ()
113
- {
114
- var ids = that.collection.pluck( 'id' );
115
- that.input.val( ids.join( ',' ) );
116
- that.input.trigger( 'change' );
117
- }, 500 ) );
118
-
119
  //Limit max files
120
  this.listenTo( this.collection, 'add', function ( item, collection )
121
  {
122
- if ( this.props.maxFiles > 0 && this.collection.length > this.props.maxFiles )
 
123
  {
124
  this.collection.pop();
125
  }
@@ -133,11 +95,23 @@ jQuery( function ( $ )
133
  include: this.values,
134
  orderby: 'post__in',
135
  order : 'ASC',
136
- type : this.props.mimeType,
137
- perPage: this.props.maxFiles || -1
138
  } );
139
  this.collection.more();
140
  }
 
 
 
 
 
 
 
 
 
 
 
 
141
  },
142
 
143
  render: function ()
@@ -175,7 +149,7 @@ jQuery( function ( $ )
175
  {
176
  var data = {
177
  items : this.collection.length,
178
- maxFiles: this.props.maxFiles
179
  };
180
  this.$el.html( this.template( data ) );
181
  }
@@ -203,7 +177,7 @@ jQuery( function ( $ )
203
  title : 'Select Media',
204
  editing : true,
205
  library : {
206
- type: this.props.mimeType
207
  }
208
  } );
209
 
@@ -227,7 +201,8 @@ jQuery( function ( $ )
227
  this.props = options.props;
228
  this.listenTo( this.collection, 'add remove reset', function ()
229
  {
230
- if ( this.props.maxFiles > 0 && this.collection.length >= this.props.maxFiles )
 
231
  {
232
  this.$el.hide();
233
  }
@@ -241,24 +216,6 @@ jQuery( function ( $ )
241
  }
242
  } );
243
 
244
- UploadButton = views.UploadButton = Backbone.View.extend( {
245
- initialize: function ( options )
246
- {
247
- this.props = options.props;
248
- this.listenTo( this.collection, 'add remove reset', function ()
249
- {
250
- if ( this.props.maxFiles > 0 && this.collection.length >= this.props.maxFiles )
251
- {
252
- this.$el.hide();
253
- }
254
- else
255
- {
256
- this.$el.show();
257
- }
258
- } );
259
- }
260
- } );
261
-
262
  MediaItem = views.MediaItem = Backbone.View.extend( {
263
  tagName : 'li',
264
  className : 'rwmb-media-item',
@@ -267,7 +224,6 @@ jQuery( function ( $ )
267
  {
268
  this.props = options.props;
269
  this.render();
270
- this.$el.data( 'cid', this.model.cid );
271
  this.listenTo( this.model, 'destroy', function ( model )
272
  {
273
  this.collection.remove( this.model );
@@ -278,7 +234,7 @@ jQuery( function ( $ )
278
  'click .rwmb-remove-media': function ( e )
279
  {
280
  this.collection.remove( this.model );
281
- if ( this.props.forceDelete )
282
  {
283
  this.model.destroy();
284
  }
@@ -290,6 +246,7 @@ jQuery( function ( $ )
290
  render: function ()
291
  {
292
  var attrs = _.clone( this.model.attributes );
 
293
  this.$el.html( this.template( attrs ) );
294
  return this;
295
  }
@@ -314,17 +271,9 @@ jQuery( function ( $ )
314
  new ImageField( { input: this, el: $( this ).siblings( 'div.rwmb-media-view' ) } );
315
  }
316
 
317
- $( ':input.rwmb-media' ).each( initMediaField );
318
- $( ':input.rwmb-image-advanced' ).each( initImageField );
319
  $( '.rwmb-input' )
320
- .on( 'clone', ':input.rwmb-media', initMediaField )
321
- .on( 'remove', '.rwmb-media-clone', function ()
322
- {
323
- $( this ).find( 'div.rwmb-media-view' ).trigger( 'destroy' );
324
- } )
325
- .on( 'clone', ':input.rwmb-image-advanced', initImageField )
326
- .on( 'remove', '.rwmb-image_advanced-clone', function ()
327
- {
328
- $( this ).find( 'div.rwmb-media-view' ).trigger( 'destroy' );
329
- } );
330
  } );
8
  MediaField, MediaList, MediaItem, ImageField, ImageList, ImageItem, MediaButton, MediaStatus, UploadButton;
9
 
10
  MediaList = views.MediaList = Backbone.View.extend( {
11
+ tagName : 'ul',
12
+ className : 'rwmb-media-list',
13
  createItemView: function ( options )
14
  {
15
  return new MediaItem( options );
49
  } );
50
 
51
  //Sort media using sortable
52
+ this.$el.sortable( { delay: 150 } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
  this.render();
55
  }
63
  } );
64
 
65
  MediaField = views.MediaField = Backbone.View.extend( {
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  initialize: function ( options )
67
  {
68
  var that = this;
69
+ this.$input = $( options.input );
70
+ this.values = this.$input.val().split( ',' );
71
+ this.props = new Backbone.Model( this.$el.data() );
72
+ this.props.set( 'fieldName', this.$input.attr( 'name' ) );
73
 
74
  //Create collection
75
  this.collection = new wp.media.model.Attachments();
77
  //Render
78
  this.render();
79
 
 
 
 
 
 
 
 
 
80
  //Limit max files
81
  this.listenTo( this.collection, 'add', function ( item, collection )
82
  {
83
+ var maxFiles = this.props.get( 'maxFiles' );
84
+ if ( maxFiles > 0 && this.collection.length > maxFiles )
85
  {
86
  this.collection.pop();
87
  }
95
  include: this.values,
96
  orderby: 'post__in',
97
  order : 'ASC',
98
+ type : this.props.get( 'mimeType' ),
99
+ perPage: this.props.get( 'maxFiles' ) || -1
100
  } );
101
  this.collection.more();
102
  }
103
+
104
+ //Listen for destroy event on input
105
+ this.$input
106
+ .on( 'remove', function(){
107
+ if ( that.props.gat( 'forceDelete' ) )
108
+ {
109
+ _.each( _.clone( that.collection.models ), function ( model )
110
+ {
111
+ model.destroy();
112
+ } );
113
+ }
114
+ } )
115
  },
116
 
117
  render: function ()
149
  {
150
  var data = {
151
  items : this.collection.length,
152
+ maxFiles: this.props.get( 'maxFiles' )
153
  };
154
  this.$el.html( this.template( data ) );
155
  }
177
  title : 'Select Media',
178
  editing : true,
179
  library : {
180
+ type: this.props.get( 'mimeType' )
181
  }
182
  } );
183
 
201
  this.props = options.props;
202
  this.listenTo( this.collection, 'add remove reset', function ()
203
  {
204
+ var maxFiles = this.props.get( 'maxFiles' );
205
+ if ( maxFiles > 0 && this.collection.length >= maxFiles )
206
  {
207
  this.$el.hide();
208
  }
216
  }
217
  } );
218
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  MediaItem = views.MediaItem = Backbone.View.extend( {
220
  tagName : 'li',
221
  className : 'rwmb-media-item',
224
  {
225
  this.props = options.props;
226
  this.render();
 
227
  this.listenTo( this.model, 'destroy', function ( model )
228
  {
229
  this.collection.remove( this.model );
234
  'click .rwmb-remove-media': function ( e )
235
  {
236
  this.collection.remove( this.model );
237
+ if ( this.props.get( 'forceDelete' ) )
238
  {
239
  this.model.destroy();
240
  }
246
  render: function ()
247
  {
248
  var attrs = _.clone( this.model.attributes );
249
+ attrs.fieldName = this.props.get( 'fieldName' );
250
  this.$el.html( this.template( attrs ) );
251
  return this;
252
  }
271
  new ImageField( { input: this, el: $( this ).siblings( 'div.rwmb-media-view' ) } );
272
  }
273
 
274
+ $( ':input.rwmb-file_advanced' ).each( initMediaField );
275
+ $( ':input.rwmb-image_advanced' ).each( initImageField );
276
  $( '.rwmb-input' )
277
+ .on( 'clone', ':input.rwmb-file_advanced', initMediaField )
278
+ .on( 'clone', ':input.rwmb-image_advanced', initImageField )
 
 
 
 
 
 
 
 
279
  } );
js/object-choice.js ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( function( $ )
2
+ {
3
+ 'use strict';
4
+ function updateChecklist()
5
+ {
6
+ var $this = $( this ),
7
+ $children = $this.closest( 'li' ).children('ul');
8
+
9
+ if ( $this.is( ':checked' ) )
10
+ {
11
+ $children.removeClass( 'hidden' );
12
+ }
13
+ else
14
+ {
15
+ $children
16
+ .addClass( 'hidden' )
17
+ .find( 'input' )
18
+ .removeAttr( 'checked' );
19
+ }
20
+ }
21
+
22
+ $( '.rwmb-input' )
23
+ .on( 'change', '.rwmb-choice-list.collapse :checkbox', updateChecklist )
24
+ .on( 'clone', '.rwmb-choice-list.collapse :checkbox', updateChecklist );
25
+ $( '.rwmb-choice-list.collapse :checkbox' ).each( updateChecklist );
26
+
27
+
28
+ function updateSelectTree()
29
+ {
30
+ var $this = $( this ),
31
+ val = $this.val(),
32
+ $selected = $this.siblings( "[data-parent-id='" + val + "']" ),
33
+ $notSelected = $this.parent().find( '.rwmb-select-tree' ).not( $selected );
34
+
35
+ $selected.removeClass( 'hidden' );
36
+ $notSelected
37
+ .addClass( 'hidden' )
38
+ .find( 'select' )
39
+ .prop( 'selectedIndex', 0 );
40
+ }
41
+
42
+ $( '.rwmb-input' )
43
+ .on( 'change', '.rwmb-select-tree select', updateSelectTree )
44
+ .on( 'clone', '.rwmb-select-tree select', updateSelectTree );
45
+ } );
js/plupload-image.js CHANGED
@@ -18,7 +18,7 @@ jQuery( function ( $ )
18
  var $dropArea = $( this ),
19
  $imageList = $dropArea.siblings( '.rwmb-uploaded' ),
20
  uploaderData = $dropArea.data( 'js_options' ),
21
- uploader = {};
22
 
23
  // Extend uploaderData
24
  uploaderData.multipart_params = $.extend(
@@ -74,7 +74,6 @@ jQuery( function ( $ )
74
  } );
75
  up.refresh();
76
  up.start();
77
-
78
  } );
79
 
80
  uploader.bind( 'Error', function ( up, e )
@@ -115,8 +114,7 @@ jQuery( function ( $ )
115
  .fadeOut( 'slow', function ()
116
  {
117
  $( this ).remove();
118
- }
119
- );
120
  }
121
 
122
  /**
18
  var $dropArea = $( this ),
19
  $imageList = $dropArea.siblings( '.rwmb-uploaded' ),
20
  uploaderData = $dropArea.data( 'js_options' ),
21
+ uploader;
22
 
23
  // Extend uploaderData
24
  uploaderData.multipart_params = $.extend(
74
  } );
75
  up.refresh();
76
  up.start();
 
77
  } );
78
 
79
  uploader.bind( 'Error', function ( up, e )
114
  .fadeOut( 'slow', function ()
115
  {
116
  $( this ).remove();
117
+ } );
 
118
  }
119
 
120
  /**
js/select-advanced.js CHANGED
@@ -18,6 +18,6 @@ jQuery( function ( $ )
18
  rwmbSelect.bindEvents( $this );
19
  }
20
 
21
- $( ':input.rwmb-select-advanced' ).each( update );
22
- $( '.rwmb-input' ).on( 'clone', ':input.rwmb-select-advanced', update );
23
  } );
18
  rwmbSelect.bindEvents( $this );
19
  }
20
 
21
+ $( ':input.rwmb-select_advanced' ).each( update );
22
+ $( '.rwmb-input' ).on( 'clone', ':input.rwmb-select_advanced', update );
23
  } );
js/select2/select2.min.js CHANGED
@@ -1,23 +1,2 @@
1
- /*
2
- Copyright 2014 Igor Vaynberg
3
-
4
- Version: 3.5.2 Timestamp: Sat Nov 1 14:43:36 EDT 2014
5
-
6
- This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
7
- General Public License version 2 (the "GPL License"). You may choose either license to govern your
8
- use of this software only upon the condition that you accept all of the terms of either the Apache
9
- License or the GPL License.
10
-
11
- You may obtain a copy of the Apache License and the GPL License at:
12
-
13
- http://www.apache.org/licenses/LICENSE-2.0
14
- http://www.gnu.org/licenses/gpl-2.0.html
15
-
16
- Unless required by applicable law or agreed to in writing, software distributed under the Apache License
17
- or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
18
- either express or implied. See the Apache License and the GPL License for the specific language governing
19
- permissions and limitations under the Apache License and the GPL License.
20
- */
21
- !function(a){"undefined"==typeof a.fn.each2&&a.extend(a.fn,{each2:function(b){for(var c=a([0]),d=-1,e=this.length;++d<e&&(c.context=c[0]=this[d])&&b.call(c[0],d,c)!==!1;);return this}})}(jQuery),function(a,b){"use strict";function n(b){var c=a(document.createTextNode(""));b.before(c),c.before(b),c.remove()}function o(a){function b(a){return m[a]||a}return a.replace(/[^\u0000-\u007E]/g,b)}function p(a,b){for(var c=0,d=b.length;d>c;c+=1)if(r(a,b[c]))return c;return-1}function q(){var b=a(l);b.appendTo(document.body);var c={width:b.width()-b[0].clientWidth,height:b.height()-b[0].clientHeight};return b.remove(),c}function r(a,c){return a===c?!0:a===b||c===b?!1:null===a||null===c?!1:a.constructor===String?a+""==c+"":c.constructor===String?c+""==a+"":!1}function s(a,b,c){var d,e,f;if(null===a||a.length<1)return[];for(d=a.split(b),e=0,f=d.length;f>e;e+=1)d[e]=c(d[e]);return d}function t(a){return a.outerWidth(!1)-a.width()}function u(c){var d="keyup-change-value";c.on("keydown",function(){a.data(c,d)===b&&a.data(c,d,c.val())}),c.on("keyup",function(){var e=a.data(c,d);e!==b&&c.val()!==e&&(a.removeData(c,d),c.trigger("keyup-change"))})}function v(c){c.on("mousemove",function(c){var d=h;(d===b||d.x!==c.pageX||d.y!==c.pageY)&&a(c.target).trigger("mousemove-filtered",c)})}function w(a,c,d){d=d||b;var e;return function(){var b=arguments;window.clearTimeout(e),e=window.setTimeout(function(){c.apply(d,b)},a)}}function x(a,b){var c=w(a,function(a){b.trigger("scroll-debounced",a)});b.on("scroll",function(a){p(a.target,b.get())>=0&&c(a)})}function y(a){a[0]!==document.activeElement&&window.setTimeout(function(){var d,b=a[0],c=a.val().length;a.focus();var e=b.offsetWidth>0||b.offsetHeight>0;e&&b===document.activeElement&&(b.setSelectionRange?b.setSelectionRange(c,c):b.createTextRange&&(d=b.createTextRange(),d.collapse(!1),d.select()))},0)}function z(b){b=a(b)[0];var c=0,d=0;if("selectionStart"in b)c=b.selectionStart,d=b.selectionEnd-c;else if("selection"in document){b.focus();var e=document.selection.createRange();d=document.selection.createRange().text.length,e.moveStart("character",-b.value.length),c=e.text.length-d}return{offset:c,length:d}}function A(a){a.preventDefault(),a.stopPropagation()}function B(a){a.preventDefault(),a.stopImmediatePropagation()}function C(b){if(!g){var c=b[0].currentStyle||window.getComputedStyle(b[0],null);g=a(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:c.fontSize,fontFamily:c.fontFamily,fontStyle:c.fontStyle,fontWeight:c.fontWeight,letterSpacing:c.letterSpacing,textTransform:c.textTransform,whiteSpace:"nowrap"}),g.attr("class","select2-sizer"),a(document.body).append(g)}return g.text(b.val()),g.width()}function D(b,c,d){var e,g,f=[];e=a.trim(b.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0===this.indexOf("select2-")&&f.push(this)})),e=a.trim(c.attr("class")),e&&(e=""+e,a(e.split(/\s+/)).each2(function(){0!==this.indexOf("select2-")&&(g=d(this),g&&f.push(g))})),b.attr("class",f.join(" "))}function E(a,b,c,d){var e=o(a.toUpperCase()).indexOf(o(b.toUpperCase())),f=b.length;return 0>e?(c.push(d(a)),void 0):(c.push(d(a.substring(0,e))),c.push("<span class='select2-match'>"),c.push(d(a.substring(e,e+f))),c.push("</span>"),c.push(d(a.substring(e+f,a.length))),void 0)}function F(a){var b={"\\":"&#92;","&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#47;"};return String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})}function G(c){var d,e=null,f=c.quietMillis||100,g=c.url,h=this;return function(i){window.clearTimeout(d),d=window.setTimeout(function(){var d=c.data,f=g,j=c.transport||a.fn.select2.ajaxDefaults.transport,k={type:c.type||"GET",cache:c.cache||!1,jsonpCallback:c.jsonpCallback||b,dataType:c.dataType||"json"},l=a.extend({},a.fn.select2.ajaxDefaults.params,k);d=d?d.call(h,i.term,i.page,i.context):null,f="function"==typeof f?f.call(h,i.term,i.page,i.context):f,e&&"function"==typeof e.abort&&e.abort(),c.params&&(a.isFunction(c.params)?a.extend(l,c.params.call(h)):a.extend(l,c.params)),a.extend(l,{url:f,dataType:c.dataType,data:d,success:function(a){var b=c.results(a,i.page,i);i.callback(b)},error:function(a,b,c){var d={hasError:!0,jqXHR:a,textStatus:b,errorThrown:c};i.callback(d)}}),e=j.call(h,l)},f)}}function H(b){var d,e,c=b,f=function(a){return""+a.text};a.isArray(c)&&(e=c,c={results:e}),a.isFunction(c)===!1&&(e=c,c=function(){return e});var g=c();return g.text&&(f=g.text,a.isFunction(f)||(d=g.text,f=function(a){return a[d]})),function(b){var g,d=b.term,e={results:[]};return""===d?(b.callback(c()),void 0):(g=function(c,e){var h,i;if(c=c[0],c.children){h={};for(i in c)c.hasOwnProperty(i)&&(h[i]=c[i]);h.children=[],a(c.children).each2(function(a,b){g(b,h.children)}),(h.children.length||b.matcher(d,f(h),c))&&e.push(h)}else b.matcher(d,f(c),c)&&e.push(c)},a(c().results).each2(function(a,b){g(b,e.results)}),b.callback(e),void 0)}}function I(c){var d=a.isFunction(c);return function(e){var f=e.term,g={results:[]},h=d?c(e):c;a.isArray(h)&&(a(h).each(function(){var a=this.text!==b,c=a?this.text:this;(""===f||e.matcher(f,c))&&g.results.push(a?this:{id:this,text:this})}),e.callback(g))}}function J(b,c){if(a.isFunction(b))return!0;if(!b)return!1;if("string"==typeof b)return!0;throw new Error(c+" must be a string, function, or falsy value")}function K(b,c){if(a.isFunction(b)){var d=Array.prototype.slice.call(arguments,2);return b.apply(c,d)}return b}function L(b){var c=0;return a.each(b,function(a,b){b.children?c+=L(b.children):c++}),c}function M(a,c,d,e){var h,i,j,k,l,f=a,g=!1;if(!e.createSearchChoice||!e.tokenSeparators||e.tokenSeparators.length<1)return b;for(;;){for(i=-1,j=0,k=e.tokenSeparators.length;k>j&&(l=e.tokenSeparators[j],i=a.indexOf(l),!(i>=0));j++);if(0>i)break;if(h=a.substring(0,i),a=a.substring(i+l.length),h.length>0&&(h=e.createSearchChoice.call(this,h,c),h!==b&&null!==h&&e.id(h)!==b&&null!==e.id(h))){for(g=!1,j=0,k=c.length;k>j;j++)if(r(e.id(h),e.id(c[j]))){g=!0;break}g||d(h)}}return f!==a?a:void 0}function N(){var b=this;a.each(arguments,function(a,c){b[c].remove(),b[c]=null})}function O(b,c){var d=function(){};return d.prototype=new b,d.prototype.constructor=d,d.prototype.parent=b.prototype,d.prototype=a.extend(d.prototype,c),d}if(window.Select2===b){var c,d,e,f,g,i,j,h={x:0,y:0},k={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(a){switch(a=a.which?a.which:a){case k.LEFT:case k.RIGHT:case k.UP:case k.DOWN:return!0}return!1},isControl:function(a){var b=a.which;switch(b){case k.SHIFT:case k.CTRL:case k.ALT:return!0}return a.metaKey?!0:!1},isFunctionKey:function(a){return a=a.which?a.which:a,a>=112&&123>=a}},l="<div class='select2-measure-scrollbar'></div>",m={"\u24b6":"A","\uff21":"A","\xc0":"A","\xc1":"A","\xc2":"A","\u1ea6":"A","\u1ea4":"A","\u1eaa":"A","\u1ea8":"A","\xc3":"A","\u0100":"A","\u0102":"A","\u1eb0":"A","\u1eae":"A","\u1eb4":"A","\u1eb2":"A","\u0226":"A","\u01e0":"A","\xc4":"A","\u01de":"A","\u1ea2":"A","\xc5":"A","\u01fa":"A","\u01cd":"A","\u0200":"A","\u0202":"A","\u1ea0":"A","\u1eac":"A","\u1eb6":"A","\u1e00":"A","\u0104":"A","\u023a":"A","\u2c6f":"A","\ua732":"AA","\xc6":"AE","\u01fc":"AE","\u01e2":"AE","\ua734":"AO","\ua736":"AU","\ua738":"AV","\ua73a":"AV","\ua73c":"AY","\u24b7":"B","\uff22":"B","\u1e02":"B","\u1e04":"B","\u1e06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24b8":"C","\uff23":"C","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\xc7":"C","\u1e08":"C","\u0187":"C","\u023b":"C","\ua73e":"C","\u24b9":"D","\uff24":"D","\u1e0a":"D","\u010e":"D","\u1e0c":"D","\u1e10":"D","\u1e12":"D","\u1e0e":"D","\u0110":"D","\u018b":"D","\u018a":"D","\u0189":"D","\ua779":"D","\u01f1":"DZ","\u01c4":"DZ","\u01f2":"Dz","\u01c5":"Dz","\u24ba":"E","\uff25":"E","\xc8":"E","\xc9":"E","\xca":"E","\u1ec0":"E","\u1ebe":"E","\u1ec4":"E","\u1ec2":"E","\u1ebc":"E","\u0112":"E","\u1e14":"E","\u1e16":"E","\u0114":"E","\u0116":"E","\xcb":"E","\u1eba":"E","\u011a":"E","\u0204":"E","\u0206":"E","\u1eb8":"E","\u1ec6":"E","\u0228":"E","\u1e1c":"E","\u0118":"E","\u1e18":"E","\u1e1a":"E","\u0190":"E","\u018e":"E","\u24bb":"F","\uff26":"F","\u1e1e":"F","\u0191":"F","\ua77b":"F","\u24bc":"G","\uff27":"G","\u01f4":"G","\u011c":"G","\u1e20":"G","\u011e":"G","\u0120":"G","\u01e6":"G","\u0122":"G","\u01e4":"G","\u0193":"G","\ua7a0":"G","\ua77d":"G","\ua77e":"G","\u24bd":"H","\uff28":"H","\u0124":"H","\u1e22":"H","\u1e26":"H","\u021e":"H","\u1e24":"H","\u1e28":"H","\u1e2a":"H","\u0126":"H","\u2c67":"H","\u2c75":"H","\ua78d":"H","\u24be":"I","\uff29":"I","\xcc":"I","\xcd":"I","\xce":"I","\u0128":"I","\u012a":"I","\u012c":"I","\u0130":"I","\xcf":"I","\u1e2e":"I","\u1ec8":"I","\u01cf":"I","\u0208":"I","\u020a":"I","\u1eca":"I","\u012e":"I","\u1e2c":"I","\u0197":"I","\u24bf":"J","\uff2a":"J","\u0134":"J","\u0248":"J","\u24c0":"K","\uff2b":"K","\u1e30":"K","\u01e8":"K","\u1e32":"K","\u0136":"K","\u1e34":"K","\u0198":"K","\u2c69":"K","\ua740":"K","\ua742":"K","\ua744":"K","\ua7a2":"K","\u24c1":"L","\uff2c":"L","\u013f":"L","\u0139":"L","\u013d":"L","\u1e36":"L","\u1e38":"L","\u013b":"L","\u1e3c":"L","\u1e3a":"L","\u0141":"L","\u023d":"L","\u2c62":"L","\u2c60":"L","\ua748":"L","\ua746":"L","\ua780":"L","\u01c7":"LJ","\u01c8":"Lj","\u24c2":"M","\uff2d":"M","\u1e3e":"M","\u1e40":"M","\u1e42":"M","\u2c6e":"M","\u019c":"M","\u24c3":"N","\uff2e":"N","\u01f8":"N","\u0143":"N","\xd1":"N","\u1e44":"N","\u0147":"N","\u1e46":"N","\u0145":"N","\u1e4a":"N","\u1e48":"N","\u0220":"N","\u019d":"N","\ua790":"N","\ua7a4":"N","\u01ca":"NJ","\u01cb":"Nj","\u24c4":"O","\uff2f":"O","\xd2":"O","\xd3":"O","\xd4":"O","\u1ed2":"O","\u1ed0":"O","\u1ed6":"O","\u1ed4":"O","\xd5":"O","\u1e4c":"O","\u022c":"O","\u1e4e":"O","\u014c":"O","\u1e50":"O","\u1e52":"O","\u014e":"O","\u022e":"O","\u0230":"O","\xd6":"O","\u022a":"O","\u1ece":"O","\u0150":"O","\u01d1":"O","\u020c":"O","\u020e":"O","\u01a0":"O","\u1edc":"O","\u1eda":"O","\u1ee0":"O","\u1ede":"O","\u1ee2":"O","\u1ecc":"O","\u1ed8":"O","\u01ea":"O","\u01ec":"O","\xd8":"O","\u01fe":"O","\u0186":"O","\u019f":"O","\ua74a":"O","\ua74c":"O","\u01a2":"OI","\ua74e":"OO","\u0222":"OU","\u24c5":"P","\uff30":"P","\u1e54":"P","\u1e56":"P","\u01a4":"P","\u2c63":"P","\ua750":"P","\ua752":"P","\ua754":"P","\u24c6":"Q","\uff31":"Q","\ua756":"Q","\ua758":"Q","\u024a":"Q","\u24c7":"R","\uff32":"R","\u0154":"R","\u1e58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1e5a":"R","\u1e5c":"R","\u0156":"R","\u1e5e":"R","\u024c":"R","\u2c64":"R","\ua75a":"R","\ua7a6":"R","\ua782":"R","\u24c8":"S","\uff33":"S","\u1e9e":"S","\u015a":"S","\u1e64":"S","\u015c":"S","\u1e60":"S","\u0160":"S","\u1e66":"S","\u1e62":"S","\u1e68":"S","\u0218":"S","\u015e":"S","\u2c7e":"S","\ua7a8":"S","\ua784":"S","\u24c9":"T","\uff34":"T","\u1e6a":"T","\u0164":"T","\u1e6c":"T","\u021a":"T","\u0162":"T","\u1e70":"T","\u1e6e":"T","\u0166":"T","\u01ac":"T","\u01ae":"T","\u023e":"T","\ua786":"T","\ua728":"TZ","\u24ca":"U","\uff35":"U","\xd9":"U","\xda":"U","\xdb":"U","\u0168":"U","\u1e78":"U","\u016a":"U","\u1e7a":"U","\u016c":"U","\xdc":"U","\u01db":"U","\u01d7":"U","\u01d5":"U","\u01d9":"U","\u1ee6":"U","\u016e":"U","\u0170":"U","\u01d3":"U","\u0214":"U","\u0216":"U","\u01af":"U","\u1eea":"U","\u1ee8":"U","\u1eee":"U","\u1eec":"U","\u1ef0":"U","\u1ee4":"U","\u1e72":"U","\u0172":"U","\u1e76":"U","\u1e74":"U","\u0244":"U","\u24cb":"V","\uff36":"V","\u1e7c":"V","\u1e7e":"V","\u01b2":"V","\ua75e":"V","\u0245":"V","\ua760":"VY","\u24cc":"W","\uff37":"W","\u1e80":"W","\u1e82":"W","\u0174":"W","\u1e86":"W","\u1e84":"W","\u1e88":"W","\u2c72":"W","\u24cd":"X","\uff38":"X","\u1e8a":"X","\u1e8c":"X","\u24ce":"Y","\uff39":"Y","\u1ef2":"Y","\xdd":"Y","\u0176":"Y","\u1ef8":"Y","\u0232":"Y","\u1e8e":"Y","\u0178":"Y","\u1ef6":"Y","\u1ef4":"Y","\u01b3":"Y","\u024e":"Y","\u1efe":"Y","\u24cf":"Z","\uff3a":"Z","\u0179":"Z","\u1e90":"Z","\u017b":"Z","\u017d":"Z","\u1e92":"Z","\u1e94":"Z","\u01b5":"Z","\u0224":"Z","\u2c7f":"Z","\u2c6b":"Z","\ua762":"Z","\u24d0":"a","\uff41":"a","\u1e9a":"a","\xe0":"a","\xe1":"a","\xe2":"a","\u1ea7":"a","\u1ea5":"a","\u1eab":"a","\u1ea9":"a","\xe3":"a","\u0101":"a","\u0103":"a","\u1eb1":"a","\u1eaf":"a","\u1eb5":"a","\u1eb3":"a","\u0227":"a","\u01e1":"a","\xe4":"a","\u01df":"a","\u1ea3":"a","\xe5":"a","\u01fb":"a","\u01ce":"a","\u0201":"a","\u0203":"a","\u1ea1":"a","\u1ead":"a","\u1eb7":"a","\u1e01":"a","\u0105":"a","\u2c65":"a","\u0250":"a","\ua733":"aa","\xe6":"ae","\u01fd":"ae","\u01e3":"ae","\ua735":"ao","\ua737":"au","\ua739":"av","\ua73b":"av","\ua73d":"ay","\u24d1":"b","\uff42":"b","\u1e03":"b","\u1e05":"b","\u1e07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24d2":"c","\uff43":"c","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\xe7":"c","\u1e09":"c","\u0188":"c","\u023c":"c","\ua73f":"c","\u2184":"c","\u24d3":"d","\uff44":"d","\u1e0b":"d","\u010f":"d","\u1e0d":"d","\u1e11":"d","\u1e13":"d","\u1e0f":"d","\u0111":"d","\u018c":"d","\u0256":"d","\u0257":"d","\ua77a":"d","\u01f3":"dz","\u01c6":"dz","\u24d4":"e","\uff45":"e","\xe8":"e","\xe9":"e","\xea":"e","\u1ec1":"e","\u1ebf":"e","\u1ec5":"e","\u1ec3":"e","\u1ebd":"e","\u0113":"e","\u1e15":"e","\u1e17":"e","\u0115":"e","\u0117":"e","\xeb":"e","\u1ebb":"e","\u011b":"e","\u0205":"e","\u0207":"e","\u1eb9":"e","\u1ec7":"e","\u0229":"e","\u1e1d":"e","\u0119":"e","\u1e19":"e","\u1e1b":"e","\u0247":"e","\u025b":"e","\u01dd":"e","\u24d5":"f","\uff46":"f","\u1e1f":"f","\u0192":"f","\ua77c":"f","\u24d6":"g","\uff47":"g","\u01f5":"g","\u011d":"g","\u1e21":"g","\u011f":"g","\u0121":"g","\u01e7":"g","\u0123":"g","\u01e5":"g","\u0260":"g","\ua7a1":"g","\u1d79":"g","\ua77f":"g","\u24d7":"h","\uff48":"h","\u0125":"h","\u1e23":"h","\u1e27":"h","\u021f":"h","\u1e25":"h","\u1e29":"h","\u1e2b":"h","\u1e96":"h","\u0127":"h","\u2c68":"h","\u2c76":"h","\u0265":"h","\u0195":"hv","\u24d8":"i","\uff49":"i","\xec":"i","\xed":"i","\xee":"i","\u0129":"i","\u012b":"i","\u012d":"i","\xef":"i","\u1e2f":"i","\u1ec9":"i","\u01d0":"i","\u0209":"i","\u020b":"i","\u1ecb":"i","\u012f":"i","\u1e2d":"i","\u0268":"i","\u0131":"i","\u24d9":"j","\uff4a":"j","\u0135":"j","\u01f0":"j","\u0249":"j","\u24da":"k","\uff4b":"k","\u1e31":"k","\u01e9":"k","\u1e33":"k","\u0137":"k","\u1e35":"k","\u0199":"k","\u2c6a":"k","\ua741":"k","\ua743":"k","\ua745":"k","\ua7a3":"k","\u24db":"l","\uff4c":"l","\u0140":"l","\u013a":"l","\u013e":"l","\u1e37":"l","\u1e39":"l","\u013c":"l","\u1e3d":"l","\u1e3b":"l","\u017f":"l","\u0142":"l","\u019a":"l","\u026b":"l","\u2c61":"l","\ua749":"l","\ua781":"l","\ua747":"l","\u01c9":"lj","\u24dc":"m","\uff4d":"m","\u1e3f":"m","\u1e41":"m","\u1e43":"m","\u0271":"m","\u026f":"m","\u24dd":"n","\uff4e":"n","\u01f9":"n","\u0144":"n","\xf1":"n","\u1e45":"n","\u0148":"n","\u1e47":"n","\u0146":"n","\u1e4b":"n","\u1e49":"n","\u019e":"n","\u0272":"n","\u0149":"n","\ua791":"n","\ua7a5":"n","\u01cc":"nj","\u24de":"o","\uff4f":"o","\xf2":"o","\xf3":"o","\xf4":"o","\u1ed3":"o","\u1ed1":"o","\u1ed7":"o","\u1ed5":"o","\xf5":"o","\u1e4d":"o","\u022d":"o","\u1e4f":"o","\u014d":"o","\u1e51":"o","\u1e53":"o","\u014f":"o","\u022f":"o","\u0231":"o","\xf6":"o","\u022b":"o","\u1ecf":"o","\u0151":"o","\u01d2":"o","\u020d":"o","\u020f":"o","\u01a1":"o","\u1edd":"o","\u1edb":"o","\u1ee1":"o","\u1edf":"o","\u1ee3":"o","\u1ecd":"o","\u1ed9":"o","\u01eb":"o","\u01ed":"o","\xf8":"o","\u01ff":"o","\u0254":"o","\ua74b":"o","\ua74d":"o","\u0275":"o","\u01a3":"oi","\u0223":"ou","\ua74f":"oo","\u24df":"p","\uff50":"p","\u1e55":"p","\u1e57":"p","\u01a5":"p","\u1d7d":"p","\ua751":"p","\ua753":"p","\ua755":"p","\u24e0":"q","\uff51":"q","\u024b":"q","\ua757":"q","\ua759":"q","\u24e1":"r","\uff52":"r","\u0155":"r","\u1e59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1e5b":"r","\u1e5d":"r","\u0157":"r","\u1e5f":"r","\u024d":"r","\u027d":"r","\ua75b":"r","\ua7a7":"r","\ua783":"r","\u24e2":"s","\uff53":"s","\xdf":"s","\u015b":"s","\u1e65":"s","\u015d":"s","\u1e61":"s","\u0161":"s","\u1e67":"s","\u1e63":"s","\u1e69":"s","\u0219":"s","\u015f":"s","\u023f":"s","\ua7a9":"s","\ua785":"s","\u1e9b":"s","\u24e3":"t","\uff54":"t","\u1e6b":"t","\u1e97":"t","\u0165":"t","\u1e6d":"t","\u021b":"t","\u0163":"t","\u1e71":"t","\u1e6f":"t","\u0167":"t","\u01ad":"t","\u0288":"t","\u2c66":"t","\ua787":"t","\ua729":"tz","\u24e4":"u","\uff55":"u","\xf9":"u","\xfa":"u","\xfb":"u","\u0169":"u","\u1e79":"u","\u016b":"u","\u1e7b":"u","\u016d":"u","\xfc":"u","\u01dc":"u","\u01d8":"u","\u01d6":"u","\u01da":"u","\u1ee7":"u","\u016f":"u","\u0171":"u","\u01d4":"u","\u0215":"u","\u0217":"u","\u01b0":"u","\u1eeb":"u","\u1ee9":"u","\u1eef":"u","\u1eed":"u","\u1ef1":"u","\u1ee5":"u","\u1e73":"u","\u0173":"u","\u1e77":"u","\u1e75":"u","\u0289":"u","\u24e5":"v","\uff56":"v","\u1e7d":"v","\u1e7f":"v","\u028b":"v","\ua75f":"v","\u028c":"v","\ua761":"vy","\u24e6":"w","\uff57":"w","\u1e81":"w","\u1e83":"w","\u0175":"w","\u1e87":"w","\u1e85":"w","\u1e98":"w","\u1e89":"w","\u2c73":"w","\u24e7":"x","\uff58":"x","\u1e8b":"x","\u1e8d":"x","\u24e8":"y","\uff59":"y","\u1ef3":"y","\xfd":"y","\u0177":"y","\u1ef9":"y","\u0233":"y","\u1e8f":"y","\xff":"y","\u1ef7":"y","\u1e99":"y","\u1ef5":"y","\u01b4":"y","\u024f":"y","\u1eff":"y","\u24e9":"z","\uff5a":"z","\u017a":"z","\u1e91":"z","\u017c":"z","\u017e":"z","\u1e93":"z","\u1e95":"z","\u01b6":"z","\u0225":"z","\u0240":"z","\u2c6c":"z","\ua763":"z","\u0386":"\u0391","\u0388":"\u0395","\u0389":"\u0397","\u038a":"\u0399","\u03aa":"\u0399","\u038c":"\u039f","\u038e":"\u03a5","\u03ab":"\u03a5","\u038f":"\u03a9","\u03ac":"\u03b1","\u03ad":"\u03b5","\u03ae":"\u03b7","\u03af":"\u03b9","\u03ca":"\u03b9","\u0390":"\u03b9","\u03cc":"\u03bf","\u03cd":"\u03c5","\u03cb":"\u03c5","\u03b0":"\u03c5","\u03c9":"\u03c9","\u03c2":"\u03c3"};i=a(document),f=function(){var a=1;return function(){return a++}}(),c=O(Object,{bind:function(a){var b=this;return function(){a.apply(b,arguments)}},init:function(c){var d,e,g=".select2-results";this.opts=c=this.prepareOpts(c),this.id=c.id,c.element.data("select2")!==b&&null!==c.element.data("select2")&&c.element.data("select2").destroy(),this.container=this.createContainer(),this.liveRegion=a(".select2-hidden-accessible"),0==this.liveRegion.length&&(this.liveRegion=a("<span>",{role:"status","aria-live":"polite"}).addClass("select2-hidden-accessible").appendTo(document.body)),this.containerId="s2id_"+(c.element.attr("id")||"autogen"+f()),this.containerEventName=this.containerId.replace(/([.])/g,"_").replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1"),this.container.attr("id",this.containerId),this.container.attr("title",c.element.attr("title")),this.body=a(document.body),D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.attr("style",c.element.attr("style")),this.container.css(K(c.containerCss,this.opts.element)),this.container.addClass(K(c.containerCssClass,this.opts.element)),this.elementTabIndex=this.opts.element.attr("tabindex"),this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container).on("click.select2",A),this.container.data("select2",this),this.dropdown=this.container.find(".select2-drop"),D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(c.dropdownCssClass,this.opts.element)),this.dropdown.data("select2",this),this.dropdown.on("click",A),this.results=d=this.container.find(g),this.search=e=this.container.find("input.select2-input"),this.queryCount=0,this.resultsPage=0,this.context=null,this.initContainer(),this.container.on("click",A),v(this.results),this.dropdown.on("mousemove-filtered",g,this.bind(this.highlightUnderEvent)),this.dropdown.on("touchstart touchmove touchend",g,this.bind(function(a){this._touchEvent=!0,this.highlightUnderEvent(a)})),this.dropdown.on("touchmove",g,this.bind(this.touchMoved)),this.dropdown.on("touchstart touchend",g,this.bind(this.clearTouchMoved)),this.dropdown.on("click",this.bind(function(){this._touchEvent&&(this._touchEvent=!1,this.selectHighlighted())})),x(80,this.results),this.dropdown.on("scroll-debounced",g,this.bind(this.loadMoreIfNeeded)),a(this.container).on("change",".select2-input",function(a){a.stopPropagation()}),a(this.dropdown).on("change",".select2-input",function(a){a.stopPropagation()}),a.fn.mousewheel&&d.mousewheel(function(a,b,c,e){var f=d.scrollTop();e>0&&0>=f-e?(d.scrollTop(0),A(a)):0>e&&d.get(0).scrollHeight-d.scrollTop()+e<=d.height()&&(d.scrollTop(d.get(0).scrollHeight-d.height()),A(a))}),u(e),e.on("keyup-change input paste",this.bind(this.updateResults)),e.on("focus",function(){e.addClass("select2-focused")}),e.on("blur",function(){e.removeClass("select2-focused")}),this.dropdown.on("mouseup",g,this.bind(function(b){a(b.target).closest(".select2-result-selectable").length>0&&(this.highlightUnderEvent(b),this.selectHighlighted(b))})),this.dropdown.on("click mouseup mousedown touchstart touchend focusin",function(a){a.stopPropagation()}),this.nextSearchTerm=b,a.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource()),null!==c.maximumInputLength&&this.search.attr("maxlength",c.maximumInputLength);var h=c.element.prop("disabled");h===b&&(h=!1),this.enable(!h);var i=c.element.prop("readonly");i===b&&(i=!1),this.readonly(i),j=j||q(),this.autofocus=c.element.prop("autofocus"),c.element.prop("autofocus",!1),this.autofocus&&this.focus(),this.search.attr("placeholder",c.searchInputPlaceholder)},destroy:function(){var a=this.opts.element,c=a.data("select2"),d=this;this.close(),a.length&&a[0].detachEvent&&d._sync&&a.each(function(){d._sync&&this.detachEvent("onpropertychange",d._sync)}),this.propertyObserver&&(this.propertyObserver.disconnect(),this.propertyObserver=null),this._sync=null,c!==b&&(c.container.remove(),c.liveRegion.remove(),c.dropdown.remove(),a.show().removeData("select2").off(".select2").prop("autofocus",this.autofocus||!1),this.elementTabIndex?a.attr({tabindex:this.elementTabIndex}):a.removeAttr("tabindex"),a.show()),N.call(this,"container","liveRegion","dropdown","results","search")},optionToData:function(a){return a.is("option")?{id:a.prop("value"),text:a.text(),element:a.get(),css:a.attr("class"),disabled:a.prop("disabled"),locked:r(a.attr("locked"),"locked")||r(a.data("locked"),!0)}:a.is("optgroup")?{text:a.attr("label"),children:[],element:a.get(),css:a.attr("class")}:void 0},prepareOpts:function(c){var d,e,g,h,i=this;if(d=c.element,"select"===d.get(0).tagName.toLowerCase()&&(this.select=e=c.element),e&&a.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in c)throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a <select> element.")}),c=a.extend({},{populateResults:function(d,e,g){var h,j=this.opts.id,k=this.liveRegion;h=function(d,e,l){var m,n,o,p,q,r,s,t,u,v;d=c.sortResults(d,e,g);var w=[];for(m=0,n=d.length;n>m;m+=1)o=d[m],q=o.disabled===!0,p=!q&&j(o)!==b,r=o.children&&o.children.length>0,s=a("<li></li>"),s.addClass("select2-results-dept-"+l),s.addClass("select2-result"),s.addClass(p?"select2-result-selectable":"select2-result-unselectable"),q&&s.addClass("select2-disabled"),r&&s.addClass("select2-result-with-children"),s.addClass(i.opts.formatResultCssClass(o)),s.attr("role","presentation"),t=a(document.createElement("div")),t.addClass("select2-result-label"),t.attr("id","select2-result-label-"+f()),t.attr("role","option"),v=c.formatResult(o,t,g,i.opts.escapeMarkup),v!==b&&(t.html(v),s.append(t)),r&&(u=a("<ul></ul>"),u.addClass("select2-result-sub"),h(o.children,u,l+1),s.append(u)),s.data("select2-data",o),w.push(s[0]);e.append(w),k.text(c.formatMatches(d.length))},h(e,d,0)}},a.fn.select2.defaults,c),"function"!=typeof c.id&&(g=c.id,c.id=function(a){return a[g]}),a.isArray(c.element.data("select2Tags"))){if("tags"in c)throw"tags specified as both an attribute 'data-select2-tags' and in options of Select2 "+c.element.attr("id");c.tags=c.element.data("select2Tags")}if(e?(c.query=this.bind(function(a){var f,g,h,c={results:[],more:!1},e=a.term;h=function(b,c){var d;b.is("option")?a.matcher(e,b.text(),b)&&c.push(i.optionToData(b)):b.is("optgroup")&&(d=i.optionToData(b),b.children().each2(function(a,b){h(b,d.children)}),d.children.length>0&&c.push(d))},f=d.children(),this.getPlaceholder()!==b&&f.length>0&&(g=this.getPlaceholderOption(),g&&(f=f.not(g))),f.each2(function(a,b){h(b,c.results)}),a.callback(c)}),c.id=function(a){return a.id}):"query"in c||("ajax"in c?(h=c.element.data("ajax-url"),h&&h.length>0&&(c.ajax.url=h),c.query=G.call(c.element,c.ajax)):"data"in c?c.query=H(c.data):"tags"in c&&(c.query=I(c.tags),c.createSearchChoice===b&&(c.createSearchChoice=function(b){return{id:a.trim(b),text:a.trim(b)}}),c.initSelection===b&&(c.initSelection=function(b,d){var e=[];a(s(b.val(),c.separator,c.transformVal)).each(function(){var b={id:this,text:this},d=c.tags;a.isFunction(d)&&(d=d()),a(d).each(function(){return r(this.id,b.id)?(b=this,!1):void 0}),e.push(b)}),d(e)}))),"function"!=typeof c.query)throw"query function not defined for Select2 "+c.element.attr("id");if("top"===c.createSearchChoicePosition)c.createSearchChoicePosition=function(a,b){a.unshift(b)};else if("bottom"===c.createSearchChoicePosition)c.createSearchChoicePosition=function(a,b){a.push(b)};else if("function"!=typeof c.createSearchChoicePosition)throw"invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function";return c},monitorSource:function(){var d,c=this.opts.element,e=this;c.on("change.select2",this.bind(function(){this.opts.element.data("select2-change-triggered")!==!0&&this.initSelection()})),this._sync=this.bind(function(){var a=c.prop("disabled");a===b&&(a=!1),this.enable(!a);var d=c.prop("readonly");d===b&&(d=!1),this.readonly(d),this.container&&(D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.addClass(K(this.opts.containerCssClass,this.opts.element))),this.dropdown&&(D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(this.opts.dropdownCssClass,this.opts.element)))}),c.length&&c[0].attachEvent&&c.each(function(){this.attachEvent("onpropertychange",e._sync)}),d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver,d!==b&&(this.propertyObserver&&(delete this.propertyObserver,this.propertyObserver=null),this.propertyObserver=new d(function(b){a.each(b,e._sync)}),this.propertyObserver.observe(c.get(0),{attributes:!0,subtree:!1}))},triggerSelect:function(b){var c=a.Event("select2-selecting",{val:this.id(b),object:b,choice:b});return this.opts.element.trigger(c),!c.isDefaultPrevented()},triggerChange:function(b){b=b||{},b=a.extend({},b,{type:"change",val:this.val()}),this.opts.element.data("select2-change-triggered",!0),this.opts.element.trigger(b),this.opts.element.data("select2-change-triggered",!1),this.opts.element.click(),this.opts.blurOnChange&&this.opts.element.blur()},isInterfaceEnabled:function(){return this.enabledInterface===!0},enableInterface:function(){var a=this._enabled&&!this._readonly,b=!a;return a===this.enabledInterface?!1:(this.container.toggleClass("select2-container-disabled",b),this.close(),this.enabledInterface=a,!0)},enable:function(a){a===b&&(a=!0),this._enabled!==a&&(this._enabled=a,this.opts.element.prop("disabled",!a),this.enableInterface())},disable:function(){this.enable(!1)},readonly:function(a){a===b&&(a=!1),this._readonly!==a&&(this._readonly=a,this.opts.element.prop("readonly",a),this.enableInterface())},opened:function(){return this.container?this.container.hasClass("select2-dropdown-open"):!1},positionDropdown:function(){var v,w,x,y,z,b=this.dropdown,c=this.container,d=c.offset(),e=c.outerHeight(!1),f=c.outerWidth(!1),g=b.outerHeight(!1),h=a(window),i=h.width(),k=h.height(),l=h.scrollLeft()+i,m=h.scrollTop()+k,n=d.top+e,o=d.left,p=m>=n+g,q=d.top-g>=h.scrollTop(),r=b.outerWidth(!1),s=function(){return l>=o+r},t=function(){return d.left+l+c.outerWidth(!1)>r},u=b.hasClass("select2-drop-above");u?(w=!0,!q&&p&&(x=!0,w=!1)):(w=!1,!p&&q&&(x=!0,w=!0)),x&&(b.hide(),d=this.container.offset(),e=this.container.outerHeight(!1),f=this.container.outerWidth(!1),g=b.outerHeight(!1),l=h.scrollLeft()+i,m=h.scrollTop()+k,n=d.top+e,o=d.left,r=b.outerWidth(!1),b.show(),this.focusSearch()),this.opts.dropdownAutoWidth?(z=a(".select2-results",b)[0],b.addClass("select2-drop-auto-width"),b.css("width",""),r=b.outerWidth(!1)+(z.scrollHeight===z.clientHeight?0:j.width),r>f?f=r:r=f,g=b.outerHeight(!1)):this.container.removeClass("select2-drop-auto-width"),"static"!==this.body.css("position")&&(v=this.body.offset(),n-=v.top,o-=v.left),!s()&&t()&&(o=d.left+this.container.outerWidth(!1)-r),y={left:o,width:f},w?(y.top=d.top-g,y.bottom="auto",this.container.addClass("select2-drop-above"),b.addClass("select2-drop-above")):(y.top=n,y.bottom="auto",this.container.removeClass("select2-drop-above"),b.removeClass("select2-drop-above")),y=a.extend(y,K(this.opts.dropdownCss,this.opts.element)),b.css(y)},shouldOpen:function(){var b;return this.opened()?!1:this._enabled===!1||this._readonly===!0?!1:(b=a.Event("select2-opening"),this.opts.element.trigger(b),!b.isDefaultPrevented())},clearDropdownAlignmentPreference:function(){this.container.removeClass("select2-drop-above"),this.dropdown.removeClass("select2-drop-above")},open:function(){return this.shouldOpen()?(this.opening(),i.on("mousemove.select2Event",function(a){h.x=a.pageX,h.y=a.pageY}),!0):!1},opening:function(){var f,b=this.containerEventName,c="scroll."+b,d="resize."+b,e="orientationchange."+b;this.container.addClass("select2-dropdown-open").addClass("select2-container-active"),this.clearDropdownAlignmentPreference(),this.dropdown[0]!==this.body.children().last()[0]&&this.dropdown.detach().appendTo(this.body),f=a("#select2-drop-mask"),0===f.length&&(f=a(document.createElement("div")),f.attr("id","select2-drop-mask").attr("class","select2-drop-mask"),f.hide(),f.appendTo(this.body),f.on("mousedown touchstart click",function(b){n(f);var d,c=a("#select2-drop");c.length>0&&(d=c.data("select2"),d.opts.selectOnBlur&&d.selectHighlighted({noFocus:!0}),d.close(),b.preventDefault(),b.stopPropagation())})),this.dropdown.prev()[0]!==f[0]&&this.dropdown.before(f),a("#select2-drop").removeAttr("id"),this.dropdown.attr("id","select2-drop"),f.show(),this.positionDropdown(),this.dropdown.show(),this.positionDropdown(),this.dropdown.addClass("select2-drop-active");var g=this;this.container.parents().add(window).each(function(){a(this).on(d+" "+c+" "+e,function(){g.opened()&&g.positionDropdown()})})},close:function(){if(this.opened()){var b=this.containerEventName,c="scroll."+b,d="resize."+b,e="orientationchange."+b;this.container.parents().add(window).each(function(){a(this).off(c).off(d).off(e)}),this.clearDropdownAlignmentPreference(),a("#select2-drop-mask").hide(),this.dropdown.removeAttr("id"),this.dropdown.hide(),this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"),this.results.empty(),i.off("mousemove.select2Event"),this.clearSearch(),this.search.removeClass("select2-active"),this.opts.element.trigger(a.Event("select2-close"))}},externalSearch:function(a){this.open(),this.search.val(a),this.updateResults(!1)},clearSearch:function(){},getMaximumSelectionSize:function(){return K(this.opts.maximumSelectionSize,this.opts.element)},ensureHighlightVisible:function(){var c,d,e,f,g,h,i,j,b=this.results;if(d=this.highlight(),!(0>d)){if(0==d)return b.scrollTop(0),void 0;c=this.findHighlightableChoices().find(".select2-result-label"),e=a(c[d]),j=(e.offset()||{}).top||0,f=j+e.outerHeight(!0),d===c.length-1&&(i=b.find("li.select2-more-results"),i.length>0&&(f=i.offset().top+i.outerHeight(!0))),g=b.offset().top+b.outerHeight(!1),f>g&&b.scrollTop(b.scrollTop()+(f-g)),h=j-b.offset().top,0>h&&"none"!=e.css("display")&&b.scrollTop(b.scrollTop()+h)}},findHighlightableChoices:function(){return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)")},moveHighlight:function(b){for(var c=this.findHighlightableChoices(),d=this.highlight();d>-1&&d<c.length;){d+=b;
22
- var e=a(c[d]);if(e.hasClass("select2-result-selectable")&&!e.hasClass("select2-disabled")&&!e.hasClass("select2-selected")){this.highlight(d);break}}},highlight:function(b){var d,e,c=this.findHighlightableChoices();return 0===arguments.length?p(c.filter(".select2-highlighted")[0],c.get()):(b>=c.length&&(b=c.length-1),0>b&&(b=0),this.removeHighlight(),d=a(c[b]),d.addClass("select2-highlighted"),this.search.attr("aria-activedescendant",d.find(".select2-result-label").attr("id")),this.ensureHighlightVisible(),this.liveRegion.text(d.text()),e=d.data("select2-data"),e&&this.opts.element.trigger({type:"select2-highlight",val:this.id(e),choice:e}),void 0)},removeHighlight:function(){this.results.find(".select2-highlighted").removeClass("select2-highlighted")},touchMoved:function(){this._touchMoved=!0},clearTouchMoved:function(){this._touchMoved=!1},countSelectableResults:function(){return this.findHighlightableChoices().length},highlightUnderEvent:function(b){var c=a(b.target).closest(".select2-result-selectable");if(c.length>0&&!c.is(".select2-highlighted")){var d=this.findHighlightableChoices();this.highlight(d.index(c))}else 0==c.length&&this.removeHighlight()},loadMoreIfNeeded:function(){var c,a=this.results,b=a.find("li.select2-more-results"),d=this.resultsPage+1,e=this,f=this.search.val(),g=this.context;0!==b.length&&(c=b.offset().top-a.offset().top-a.height(),c<=this.opts.loadMorePadding&&(b.addClass("select2-active"),this.opts.query({element:this.opts.element,term:f,page:d,context:g,matcher:this.opts.matcher,callback:this.bind(function(c){e.opened()&&(e.opts.populateResults.call(this,a,c.results,{term:f,page:d,context:g}),e.postprocessResults(c,!1,!1),c.more===!0?(b.detach().appendTo(a).html(e.opts.escapeMarkup(K(e.opts.formatLoadMore,e.opts.element,d+1))),window.setTimeout(function(){e.loadMoreIfNeeded()},10)):b.remove(),e.positionDropdown(),e.resultsPage=d,e.context=c.context,this.opts.element.trigger({type:"select2-loaded",items:c}))})})))},tokenize:function(){},updateResults:function(c){function m(){d.removeClass("select2-active"),h.positionDropdown(),e.find(".select2-no-results,.select2-selection-limit,.select2-searching").length?h.liveRegion.text(e.text()):h.liveRegion.text(h.opts.formatMatches(e.find('.select2-result-selectable:not(".select2-selected")').length))}function n(a){e.html(a),m()}var g,i,l,d=this.search,e=this.results,f=this.opts,h=this,j=d.val(),k=a.data(this.container,"select2-last-term");if((c===!0||!k||!r(j,k))&&(a.data(this.container,"select2-last-term",j),c===!0||this.showSearchInput!==!1&&this.opened())){l=++this.queryCount;var o=this.getMaximumSelectionSize();if(o>=1&&(g=this.data(),a.isArray(g)&&g.length>=o&&J(f.formatSelectionTooBig,"formatSelectionTooBig")))return n("<li class='select2-selection-limit'>"+K(f.formatSelectionTooBig,f.element,o)+"</li>"),void 0;if(d.val().length<f.minimumInputLength)return J(f.formatInputTooShort,"formatInputTooShort")?n("<li class='select2-no-results'>"+K(f.formatInputTooShort,f.element,d.val(),f.minimumInputLength)+"</li>"):n(""),c&&this.showSearch&&this.showSearch(!0),void 0;if(f.maximumInputLength&&d.val().length>f.maximumInputLength)return J(f.formatInputTooLong,"formatInputTooLong")?n("<li class='select2-no-results'>"+K(f.formatInputTooLong,f.element,d.val(),f.maximumInputLength)+"</li>"):n(""),void 0;f.formatSearching&&0===this.findHighlightableChoices().length&&n("<li class='select2-searching'>"+K(f.formatSearching,f.element)+"</li>"),d.addClass("select2-active"),this.removeHighlight(),i=this.tokenize(),i!=b&&null!=i&&d.val(i),this.resultsPage=1,f.query({element:f.element,term:d.val(),page:this.resultsPage,context:null,matcher:f.matcher,callback:this.bind(function(g){var i;if(l==this.queryCount){if(!this.opened())return this.search.removeClass("select2-active"),void 0;if(g.hasError!==b&&J(f.formatAjaxError,"formatAjaxError"))return n("<li class='select2-ajax-error'>"+K(f.formatAjaxError,f.element,g.jqXHR,g.textStatus,g.errorThrown)+"</li>"),void 0;if(this.context=g.context===b?null:g.context,this.opts.createSearchChoice&&""!==d.val()&&(i=this.opts.createSearchChoice.call(h,d.val(),g.results),i!==b&&null!==i&&h.id(i)!==b&&null!==h.id(i)&&0===a(g.results).filter(function(){return r(h.id(this),h.id(i))}).length&&this.opts.createSearchChoicePosition(g.results,i)),0===g.results.length&&J(f.formatNoMatches,"formatNoMatches"))return n("<li class='select2-no-results'>"+K(f.formatNoMatches,f.element,d.val())+"</li>"),void 0;e.empty(),h.opts.populateResults.call(this,e,g.results,{term:d.val(),page:this.resultsPage,context:null}),g.more===!0&&J(f.formatLoadMore,"formatLoadMore")&&(e.append("<li class='select2-more-results'>"+f.escapeMarkup(K(f.formatLoadMore,f.element,this.resultsPage))+"</li>"),window.setTimeout(function(){h.loadMoreIfNeeded()},10)),this.postprocessResults(g,c),m(),this.opts.element.trigger({type:"select2-loaded",items:g})}})})}},cancel:function(){this.close()},blur:function(){this.opts.selectOnBlur&&this.selectHighlighted({noFocus:!0}),this.close(),this.container.removeClass("select2-container-active"),this.search[0]===document.activeElement&&this.search.blur(),this.clearSearch(),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus")},focusSearch:function(){y(this.search)},selectHighlighted:function(a){if(this._touchMoved)return this.clearTouchMoved(),void 0;var b=this.highlight(),c=this.results.find(".select2-highlighted"),d=c.closest(".select2-result").data("select2-data");d?(this.highlight(b),this.onSelect(d,a)):a&&a.noFocus&&this.close()},getPlaceholder:function(){var a;return this.opts.element.attr("placeholder")||this.opts.element.attr("data-placeholder")||this.opts.element.data("placeholder")||this.opts.placeholder||((a=this.getPlaceholderOption())!==b?a.text():b)},getPlaceholderOption:function(){if(this.select){var c=this.select.children("option").first();if(this.opts.placeholderOption!==b)return"first"===this.opts.placeholderOption&&c||"function"==typeof this.opts.placeholderOption&&this.opts.placeholderOption(this.select);if(""===a.trim(c.text())&&""===c.val())return c}},initContainerWidth:function(){function c(){var c,d,e,f,g,h;if("off"===this.opts.width)return null;if("element"===this.opts.width)return 0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px";if("copy"===this.opts.width||"resolve"===this.opts.width){if(c=this.opts.element.attr("style"),c!==b)for(d=c.split(";"),f=0,g=d.length;g>f;f+=1)if(h=d[f].replace(/\s/g,""),e=h.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i),null!==e&&e.length>=1)return e[1];return"resolve"===this.opts.width?(c=this.opts.element.css("width"),c.indexOf("%")>0?c:0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px"):null}return a.isFunction(this.opts.width)?this.opts.width():this.opts.width}var d=c.call(this);null!==d&&this.container.css("width",d)}}),d=O(c,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container"}).html(["<a href='javascript:void(0)' class='select2-choice' tabindex='-1'>"," <span class='select2-chosen'>&#160;</span><abbr class='select2-search-choice-close'></abbr>"," <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>","</a>","<label for='' class='select2-offscreen'></label>","<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />","<div class='select2-drop select2-display-none'>"," <div class='select2-search'>"," <label for='' class='select2-offscreen'></label>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'"," aria-autocomplete='list' />"," </div>"," <ul class='select2-results' role='listbox'>"," </ul>","</div>"].join(""));return b},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.focusser.prop("disabled",!this.isInterfaceEnabled())},opening:function(){var c,d,e;this.opts.minimumResultsForSearch>=0&&this.showSearch(!0),this.parent.opening.apply(this,arguments),this.showSearchInput!==!1&&this.search.val(this.focusser.val()),this.opts.shouldFocusInput(this)&&(this.search.focus(),c=this.search.get(0),c.createTextRange?(d=c.createTextRange(),d.collapse(!1),d.select()):c.setSelectionRange&&(e=this.search.val().length,c.setSelectionRange(e,e))),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.focusser.prop("disabled",!0).val(""),this.updateResults(!0),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&(this.parent.close.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},focus:function(){this.opened()?this.close():(this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus()},destroy:function(){a("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments),N.call(this,"selection","focusser")},initContainer:function(){var b,g,c=this.container,d=this.dropdown,e=f();this.opts.minimumResultsForSearch<0?this.showSearch(!1):this.showSearch(!0),this.selection=b=c.find(".select2-choice"),this.focusser=c.find(".select2-focusser"),b.find(".select2-chosen").attr("id","select2-chosen-"+e),this.focusser.attr("aria-labelledby","select2-chosen-"+e),this.results.attr("id","select2-results-"+e),this.search.attr("aria-owns","select2-results-"+e),this.focusser.attr("id","s2id_autogen"+e),g=a("label[for='"+this.opts.element.attr("id")+"']"),this.opts.element.focus(this.bind(function(){this.focus()})),this.focusser.prev().text(g.text()).attr("for",this.focusser.attr("id"));var h=this.opts.element.attr("title");this.opts.element.attr("title",h||g.text()),this.focusser.attr("tabindex",this.elementTabIndex),this.search.attr("id",this.focusser.attr("id")+"_search"),this.search.prev().text(a("label[for='"+this.focusser.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&229!=a.keyCode){if(a.which===k.PAGE_UP||a.which===k.PAGE_DOWN)return A(a),void 0;switch(a.which){case k.UP:case k.DOWN:return this.moveHighlight(a.which===k.UP?-1:1),A(a),void 0;case k.ENTER:return this.selectHighlighted(),A(a),void 0;case k.TAB:return this.selectHighlighted({noFocus:!0}),void 0;case k.ESC:return this.cancel(a),A(a),void 0}}})),this.search.on("blur",this.bind(function(){document.activeElement===this.body.get(0)&&window.setTimeout(this.bind(function(){this.opened()&&this.search.focus()}),0)})),this.focusser.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&a.which!==k.TAB&&!k.isControl(a)&&!k.isFunctionKey(a)&&a.which!==k.ESC){if(this.opts.openOnEnter===!1&&a.which===k.ENTER)return A(a),void 0;if(a.which==k.DOWN||a.which==k.UP||a.which==k.ENTER&&this.opts.openOnEnter){if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return;return this.open(),A(a),void 0}return a.which==k.DELETE||a.which==k.BACKSPACE?(this.opts.allowClear&&this.clear(),A(a),void 0):void 0}})),u(this.focusser),this.focusser.on("keyup-change input",this.bind(function(a){if(this.opts.minimumResultsForSearch>=0){if(a.stopPropagation(),this.opened())return;this.open()}})),b.on("mousedown touchstart","abbr",this.bind(function(a){this.isInterfaceEnabled()&&(this.clear(),B(a),this.close(),this.selection&&this.selection.focus())})),b.on("mousedown touchstart",this.bind(function(c){n(b),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.opened()?this.close():this.isInterfaceEnabled()&&this.open(),A(c)})),d.on("mousedown touchstart",this.bind(function(){this.opts.shouldFocusInput(this)&&this.search.focus()})),b.on("focus",this.bind(function(a){A(a)})),this.focusser.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){this.opened()||(this.container.removeClass("select2-container-active"),this.opts.element.trigger(a.Event("select2-blur")))})),this.search.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})),this.initContainerWidth(),this.opts.element.hide(),this.setPlaceholder()},clear:function(b){var c=this.selection.data("select2-data");if(c){var d=a.Event("select2-clearing");if(this.opts.element.trigger(d),d.isDefaultPrevented())return;var e=this.getPlaceholderOption();this.opts.element.val(e?e.val():""),this.selection.find(".select2-chosen").empty(),this.selection.removeData("select2-data"),this.setPlaceholder(),b!==!1&&(this.opts.element.trigger({type:"select2-removed",val:this.id(c),choice:c}),this.triggerChange({removed:c}))}},initSelection:function(){if(this.isPlaceholderOptionSelected())this.updateSelection(null),this.close(),this.setPlaceholder();else{var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.setPlaceholder(),c.nextSearchTerm=c.opts.nextSearchTerm(a,c.search.val()))})}},isPlaceholderOptionSelected:function(){var a;return this.getPlaceholder()===b?!1:(a=this.getPlaceholderOption())!==b&&a.prop("selected")||""===this.opts.element.val()||this.opts.element.val()===b||null===this.opts.element.val()},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=a.find("option").filter(function(){return this.selected&&!this.disabled});b(c.optionToData(d))}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=c.val(),f=null;b.query({matcher:function(a,c,d){var g=r(e,b.id(d));return g&&(f=d),g},callback:a.isFunction(d)?function(){d(f)}:a.noop})}),b},getPlaceholder:function(){return this.select&&this.getPlaceholderOption()===b?b:this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var a=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&a!==b){if(this.select&&this.getPlaceholderOption()===b)return;this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(a)),this.selection.addClass("select2-default"),this.container.removeClass("select2-allowclear")}},postprocessResults:function(a,b,c){var d=0,e=this;if(this.findHighlightableChoices().each2(function(a,b){return r(e.id(b.data("select2-data")),e.opts.element.val())?(d=a,!1):void 0}),c!==!1&&(b===!0&&d>=0?this.highlight(d):this.highlight(0)),b===!0){var g=this.opts.minimumResultsForSearch;g>=0&&this.showSearch(L(a.results)>=g)}},showSearch:function(b){this.showSearchInput!==b&&(this.showSearchInput=b,this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!b),this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!b),a(this.dropdown,this.container).toggleClass("select2-with-searchbox",b))},onSelect:function(a,b){if(this.triggerSelect(a)){var c=this.opts.element.val(),d=this.data();this.opts.element.val(this.id(a)),this.updateSelection(a),this.opts.element.trigger({type:"select2-selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.close(),b&&b.noFocus||!this.opts.shouldFocusInput(this)||this.focusser.focus(),r(c,this.id(a))||this.triggerChange({added:a,removed:d})}},updateSelection:function(a){var d,e,c=this.selection.find(".select2-chosen");this.selection.data("select2-data",a),c.empty(),null!==a&&(d=this.opts.formatSelection(a,c,this.opts.escapeMarkup)),d!==b&&c.append(d),e=this.opts.formatSelectionCssClass(a,c),e!==b&&c.addClass(e),this.selection.removeClass("select2-default"),this.opts.allowClear&&this.getPlaceholder()!==b&&this.container.addClass("select2-allowclear")},val:function(){var a,c=!1,d=null,e=this,f=this.data();if(0===arguments.length)return this.opts.element.val();if(a=arguments[0],arguments.length>1&&(c=arguments[1]),this.select)this.select.val(a).find("option").filter(function(){return this.selected}).each2(function(a,b){return d=e.optionToData(b),!1}),this.updateSelection(d),this.setPlaceholder(),c&&this.triggerChange({added:d,removed:f});else{if(!a&&0!==a)return this.clear(c),void 0;if(this.opts.initSelection===b)throw new Error("cannot call val() if initSelection() is not defined");this.opts.element.val(a),this.opts.initSelection(this.opts.element,function(a){e.opts.element.val(a?e.id(a):""),e.updateSelection(a),e.setPlaceholder(),c&&e.triggerChange({added:a,removed:f})})}},clearSearch:function(){this.search.val(""),this.focusser.val("")},data:function(a){var c,d=!1;return 0===arguments.length?(c=this.selection.data("select2-data"),c==b&&(c=null),c):(arguments.length>1&&(d=arguments[1]),a?(c=this.data(),this.opts.element.val(a?this.id(a):""),this.updateSelection(a),d&&this.triggerChange({added:a,removed:c})):this.clear(d),void 0)}}),e=O(c,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["<ul class='select2-choices'>"," <li class='select2-search-field'>"," <label for='' class='select2-offscreen'></label>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>"," </li>","</ul>","<div class='select2-drop select2-drop-multi select2-display-none'>"," <ul class='select2-results'>"," </ul>","</div>"].join(""));return b},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=[];a.find("option").filter(function(){return this.selected&&!this.disabled}).each2(function(a,b){d.push(c.optionToData(b))}),b(d)}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=s(c.val(),b.separator,b.transformVal),f=[];b.query({matcher:function(c,d,g){var h=a.grep(e,function(a){return r(a,b.id(g))}).length;return h&&f.push(g),h},callback:a.isFunction(d)?function(){for(var a=[],c=0;c<e.length;c++)for(var g=e[c],h=0;h<f.length;h++){var i=f[h];if(r(g,b.id(i))){a.push(i),f.splice(h,1);break}}d(a)}:a.noop})}),b},selectChoice:function(a){var b=this.container.find(".select2-search-choice-focus");b.length&&a&&a[0]==b[0]||(b.length&&this.opts.element.trigger("choice-deselected",b),b.removeClass("select2-search-choice-focus"),a&&a.length&&(this.close(),a.addClass("select2-search-choice-focus"),this.opts.element.trigger("choice-selected",a)))},destroy:function(){a("label[for='"+this.search.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments),N.call(this,"searchContainer","selection")},initContainer:function(){var c,b=".select2-choices";this.searchContainer=this.container.find(".select2-search-field"),this.selection=c=this.container.find(b);var d=this;this.selection.on("click",".select2-container:not(.select2-container-disabled) .select2-search-choice:not(.select2-locked)",function(){d.search[0].focus(),d.selectChoice(a(this))}),this.search.attr("id","s2id_autogen"+f()),this.search.prev().text(a("label[for='"+this.opts.element.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.opts.element.focus(this.bind(function(){this.focus()})),this.search.on("input paste",this.bind(function(){this.search.attr("placeholder")&&0==this.search.val().length||this.isInterfaceEnabled()&&(this.opened()||this.open())})),this.search.attr("tabindex",this.elementTabIndex),this.keydowns=0,this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()){++this.keydowns;var b=c.find(".select2-search-choice-focus"),d=b.prev(".select2-search-choice:not(.select2-locked)"),e=b.next(".select2-search-choice:not(.select2-locked)"),f=z(this.search);if(b.length&&(a.which==k.LEFT||a.which==k.RIGHT||a.which==k.BACKSPACE||a.which==k.DELETE||a.which==k.ENTER)){var g=b;return a.which==k.LEFT&&d.length?g=d:a.which==k.RIGHT?g=e.length?e:null:a.which===k.BACKSPACE?this.unselect(b.first())&&(this.search.width(10),g=d.length?d:e):a.which==k.DELETE?this.unselect(b.first())&&(this.search.width(10),g=e.length?e:null):a.which==k.ENTER&&(g=null),this.selectChoice(g),A(a),g&&g.length||this.open(),void 0}if((a.which===k.BACKSPACE&&1==this.keydowns||a.which==k.LEFT)&&0==f.offset&&!f.length)return this.selectChoice(c.find(".select2-search-choice:not(.select2-locked)").last()),A(a),void 0;if(this.selectChoice(null),this.opened())switch(a.which){case k.UP:case k.DOWN:return this.moveHighlight(a.which===k.UP?-1:1),A(a),void 0;case k.ENTER:return this.selectHighlighted(),A(a),void 0;case k.TAB:return this.selectHighlighted({noFocus:!0}),this.close(),void 0;case k.ESC:return this.cancel(a),A(a),void 0}if(a.which!==k.TAB&&!k.isControl(a)&&!k.isFunctionKey(a)&&a.which!==k.BACKSPACE&&a.which!==k.ESC){if(a.which===k.ENTER){if(this.opts.openOnEnter===!1)return;if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return}this.open(),(a.which===k.PAGE_UP||a.which===k.PAGE_DOWN)&&A(a),a.which===k.ENTER&&A(a)}}})),this.search.on("keyup",this.bind(function(){this.keydowns=0,this.resizeSearch()})),this.search.on("blur",this.bind(function(b){this.container.removeClass("select2-container-active"),this.search.removeClass("select2-focused"),this.selectChoice(null),this.opened()||this.clearSearch(),b.stopImmediatePropagation(),this.opts.element.trigger(a.Event("select2-blur"))})),this.container.on("click",b,this.bind(function(b){this.isInterfaceEnabled()&&(a(b.target).closest(".select2-search-choice").length>0||(this.selectChoice(null),this.clearPlaceholder(),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.open(),this.focusSearch(),b.preventDefault()))})),this.container.on("focus",b,this.bind(function(){this.isInterfaceEnabled()&&(this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())})),this.initContainerWidth(),this.opts.element.hide(),this.clearSearch()},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.search.prop("disabled",!this.isInterfaceEnabled())},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text()&&(this.updateSelection([]),this.close(),this.clearSearch()),this.select||""!==this.opts.element.val()){var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.clearSearch())})}},clearSearch:function(){var a=this.getPlaceholder(),c=this.getMaxSearchWidth();a!==b&&0===this.getVal().length&&this.search.hasClass("select2-focused")===!1?(this.search.val(a).addClass("select2-default"),this.search.width(c>0?c:this.container.css("width"))):this.search.val("").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")&&this.search.val("").removeClass("select2-default")},opening:function(){this.clearPlaceholder(),this.resizeSearch(),this.parent.opening.apply(this,arguments),this.focusSearch(),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.updateResults(!0),this.opts.shouldFocusInput(this)&&this.search.focus(),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&this.parent.close.apply(this,arguments)},focus:function(){this.close(),this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(b){var c=[],d=[],e=this;a(b).each(function(){p(e.id(this),c)<0&&(c.push(e.id(this)),d.push(this))}),b=d,this.selection.find(".select2-search-choice").remove(),a(b).each(function(){e.addSelectedChoice(this)}),e.postprocessResults()},tokenize:function(){var a=this.search.val();a=this.opts.tokenizer.call(this,a,this.data(),this.bind(this.onSelect),this.opts),null!=a&&a!=b&&(this.search.val(a),a.length>0&&this.open())},onSelect:function(a,c){this.triggerSelect(a)&&""!==a.text&&(this.addSelectedChoice(a),this.opts.element.trigger({type:"selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.clearSearch(),this.updateResults(),(this.select||!this.opts.closeOnSelect)&&this.postprocessResults(a,!1,this.opts.closeOnSelect===!0),this.opts.closeOnSelect?(this.close(),this.search.width(10)):this.countSelectableResults()>0?(this.search.width(10),this.resizeSearch(),this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()?this.updateResults(!0):this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.updateResults(),this.search.select()),this.positionDropdown()):(this.close(),this.search.width(10)),this.triggerChange({added:a}),c&&c.noFocus||this.focusSearch())},cancel:function(){this.close(),this.focusSearch()},addSelectedChoice:function(c){var j,k,d=!c.locked,e=a("<li class='select2-search-choice'> <div></div> <a href='#' class='select2-search-choice-close' tabindex='-1'></a></li>"),f=a("<li class='select2-search-choice select2-locked'><div></div></li>"),g=d?e:f,h=this.id(c),i=this.getVal();j=this.opts.formatSelection(c,g.find("div"),this.opts.escapeMarkup),j!=b&&g.find("div").replaceWith(a("<div></div>").html(j)),k=this.opts.formatSelectionCssClass(c,g.find("div")),k!=b&&g.addClass(k),d&&g.find(".select2-search-choice-close").on("mousedown",A).on("click dblclick",this.bind(function(b){this.isInterfaceEnabled()&&(this.unselect(a(b.target)),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"),A(b),this.close(),this.focusSearch())})).on("focus",this.bind(function(){this.isInterfaceEnabled()&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))})),g.data("select2-data",c),g.insertBefore(this.searchContainer),i.push(h),this.setVal(i)},unselect:function(b){var d,e,c=this.getVal();if(b=b.closest(".select2-search-choice"),0===b.length)throw"Invalid argument: "+b+". Must be .select2-search-choice";if(d=b.data("select2-data")){var f=a.Event("select2-removing");if(f.val=this.id(d),f.choice=d,this.opts.element.trigger(f),f.isDefaultPrevented())return!1;for(;(e=p(this.id(d),c))>=0;)c.splice(e,1),this.setVal(c),this.select&&this.postprocessResults();return b.remove(),this.opts.element.trigger({type:"select2-removed",val:this.id(d),choice:d}),this.triggerChange({removed:d}),!0}},postprocessResults:function(a,b,c){var d=this.getVal(),e=this.results.find(".select2-result"),f=this.results.find(".select2-result-with-children"),g=this;e.each2(function(a,b){var c=g.id(b.data("select2-data"));p(c,d)>=0&&(b.addClass("select2-selected"),b.find(".select2-result-selectable").addClass("select2-selected"))}),f.each2(function(a,b){b.is(".select2-result-selectable")||0!==b.find(".select2-result-selectable:not(.select2-selected)").length||b.addClass("select2-selected")}),-1==this.highlight()&&c!==!1&&this.opts.closeOnSelect===!0&&g.highlight(0),!this.opts.createSearchChoice&&!e.filter(".select2-result:not(.select2-selected)").length>0&&(!a||a&&!a.more&&0===this.results.find(".select2-no-results").length)&&J(g.opts.formatNoMatches,"formatNoMatches")&&this.results.append("<li class='select2-no-results'>"+K(g.opts.formatNoMatches,g.opts.element,g.search.val())+"</li>")},getMaxSearchWidth:function(){return this.selection.width()-t(this.search)},resizeSearch:function(){var a,b,c,d,e,f=t(this.search);a=C(this.search)+10,b=this.search.offset().left,c=this.selection.width(),d=this.selection.offset().left,e=c-(b-d)-f,a>e&&(e=c-f),40>e&&(e=c-f),0>=e&&(e=a),this.search.width(Math.floor(e))},getVal:function(){var a;return this.select?(a=this.select.val(),null===a?[]:a):(a=this.opts.element.val(),s(a,this.opts.separator,this.opts.transformVal))},setVal:function(b){var c;this.select?this.select.val(b):(c=[],a(b).each(function(){p(this,c)<0&&c.push(this)}),this.opts.element.val(0===c.length?"":c.join(this.opts.separator)))},buildChangeDetails:function(a,b){for(var b=b.slice(0),a=a.slice(0),c=0;c<b.length;c++)for(var d=0;d<a.length;d++)r(this.opts.id(b[c]),this.opts.id(a[d]))&&(b.splice(c,1),c>0&&c--,a.splice(d,1),d--);return{added:b,removed:a}},val:function(c,d){var e,f=this;if(0===arguments.length)return this.getVal();if(e=this.data(),e.length||(e=[]),!c&&0!==c)return this.opts.element.val(""),this.updateSelection([]),this.clearSearch(),d&&this.triggerChange({added:this.data(),removed:e}),void 0;if(this.setVal(c),this.select)this.opts.initSelection(this.select,this.bind(this.updateSelection)),d&&this.triggerChange(this.buildChangeDetails(e,this.data()));else{if(this.opts.initSelection===b)throw new Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,function(b){var c=a.map(b,f.id);f.setVal(c),f.updateSelection(b),f.clearSearch(),d&&f.triggerChange(f.buildChangeDetails(e,f.data()))})}this.clearSearch()},onSortStart:function(){if(this.select)throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");this.search.width(0),this.searchContainer.hide()},onSortEnd:function(){var b=[],c=this;this.searchContainer.show(),this.searchContainer.appendTo(this.searchContainer.parent()),this.resizeSearch(),this.selection.find(".select2-search-choice").each(function(){b.push(c.opts.id(a(this).data("select2-data")))}),this.setVal(b),this.triggerChange()},data:function(b,c){var e,f,d=this;return 0===arguments.length?this.selection.children(".select2-search-choice").map(function(){return a(this).data("select2-data")}).get():(f=this.data(),b||(b=[]),e=a.map(b,function(a){return d.opts.id(a)}),this.setVal(e),this.updateSelection(b),this.clearSearch(),c&&this.triggerChange(this.buildChangeDetails(f,this.data())),void 0)}}),a.fn.select2=function(){var d,e,f,g,h,c=Array.prototype.slice.call(arguments,0),i=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],j=["opened","isFocused","container","dropdown"],k=["val","data"],l={search:"externalSearch"};return this.each(function(){if(0===c.length||"object"==typeof c[0])d=0===c.length?{}:a.extend({},c[0]),d.element=a(this),"select"===d.element.get(0).tagName.toLowerCase()?h=d.element.prop("multiple"):(h=d.multiple||!1,"tags"in d&&(d.multiple=h=!0)),e=h?new window.Select2["class"].multi:new window.Select2["class"].single,e.init(d);else{if("string"!=typeof c[0])throw"Invalid arguments to select2 plugin: "+c;if(p(c[0],i)<0)throw"Unknown method: "+c[0];if(g=b,e=a(this).data("select2"),e===b)return;if(f=c[0],"container"===f?g=e.container:"dropdown"===f?g=e.dropdown:(l[f]&&(f=l[f]),g=e[f].apply(e,c.slice(1))),p(c[0],j)>=0||p(c[0],k)>=0&&1==c.length)return!1}}),g===b?this:g},a.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(a,b,c,d){var e=[];return E(this.text(a),c.term,e,d),e.join("")},transformVal:function(b){return a.trim(b)},formatSelection:function(a,c,d){return a?d(this.text(a)):b},sortResults:function(a){return a},formatResultCssClass:function(a){return a.css},formatSelectionCssClass:function(){return b},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(a){return a==b?null:a.id},text:function(b){return b&&this.data&&this.data.text?a.isFunction(this.data.text)?this.data.text(b):b[this.data.text]:b.text
23
- },matcher:function(a,b){return o(""+b).toUpperCase().indexOf(o(""+a).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:M,escapeMarkup:F,blurOnChange:!1,selectOnBlur:!1,adaptContainerCssClass:function(a){return a},adaptDropdownCssClass:function(){return null},nextSearchTerm:function(){return b},searchInputPlaceholder:"",createSearchChoicePosition:"top",shouldFocusInput:function(a){var b="ontouchstart"in window||navigator.msMaxTouchPoints>0;return b?a.opts.minimumResultsForSearch<0?!1:!0:!0}},a.fn.select2.locales=[],a.fn.select2.locales.en={formatMatches:function(a){return 1===a?"One result is available, press enter to select it.":a+" results are available, use up and down arrow keys to navigate."},formatNoMatches:function(){return"No matches found"},formatAjaxError:function(){return"Loading failed"},formatInputTooShort:function(a,b){var c=b-a.length;return"Please enter "+c+" or more character"+(1==c?"":"s")},formatInputTooLong:function(a,b){var c=a.length-b;return"Please delete "+c+" character"+(1==c?"":"s")},formatSelectionTooBig:function(a){return"You can only select "+a+" item"+(1==a?"":"s")},formatLoadMore:function(){return"Loading more results\u2026"},formatSearching:function(){return"Searching\u2026"}},a.extend(a.fn.select2.defaults,a.fn.select2.locales.en),a.fn.select2.ajaxDefaults={transport:a.ajax,params:{type:"GET",cache:!1,dataType:"json"}},window.Select2={query:{ajax:G,local:H,tags:I},util:{debounce:w,markMatch:E,escapeMarkup:F,stripDiacritics:o},"class":{"abstract":c,single:d,multi:e}}}}(jQuery);
1
+ /*! Select2 4.0.1 | https://github.com/select2/select2/blob/master/LICENSE.md */!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){var b=function(){if(a&&a.fn&&a.fn.select2&&a.fn.select2.amd)var b=a.fn.select2.amd;var b;return function(){if(!b||!b.requirejs){b?c=b:b={};var a,c,d;!function(b){function e(a,b){return u.call(a,b)}function f(a,b){var c,d,e,f,g,h,i,j,k,l,m,n=b&&b.split("/"),o=s.map,p=o&&o["*"]||{};if(a&&"."===a.charAt(0))if(b){for(a=a.split("/"),g=a.length-1,s.nodeIdCompat&&w.test(a[g])&&(a[g]=a[g].replace(w,"")),a=n.slice(0,n.length-1).concat(a),k=0;k<a.length;k+=1)if(m=a[k],"."===m)a.splice(k,1),k-=1;else if(".."===m){if(1===k&&(".."===a[2]||".."===a[0]))break;k>0&&(a.splice(k-1,2),k-=2)}a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if((n||p)&&o){for(c=a.split("/"),k=c.length;k>0;k-=1){if(d=c.slice(0,k).join("/"),n)for(l=n.length;l>0;l-=1)if(e=o[n.slice(0,l).join("/")],e&&(e=e[d])){f=e,h=k;break}if(f)break;!i&&p&&p[d]&&(i=p[d],j=k)}!f&&i&&(f=i,h=j),f&&(c.splice(0,h,f),a=c.join("/"))}return a}function g(a,c){return function(){var d=v.call(arguments,0);return"string"!=typeof d[0]&&1===d.length&&d.push(null),n.apply(b,d.concat([a,c]))}}function h(a){return function(b){return f(b,a)}}function i(a){return function(b){q[a]=b}}function j(a){if(e(r,a)){var c=r[a];delete r[a],t[a]=!0,m.apply(b,c)}if(!e(q,a)&&!e(t,a))throw new Error("No "+a);return q[a]}function k(a){var b,c=a?a.indexOf("!"):-1;return c>-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function l(a){return function(){return s&&s.config&&s.config[a]||{}}}var m,n,o,p,q={},r={},s={},t={},u=Object.prototype.hasOwnProperty,v=[].slice,w=/\.js$/;o=function(a,b){var c,d=k(a),e=d[0];return a=d[1],e&&(e=f(e,b),c=j(e)),e?a=c&&c.normalize?c.normalize(a,h(b)):f(a,b):(a=f(a,b),d=k(a),e=d[0],a=d[1],e&&(c=j(e))),{f:e?e+"!"+a:a,n:a,pr:e,p:c}},p={require:function(a){return g(a)},exports:function(a){var b=q[a];return"undefined"!=typeof b?b:q[a]={}},module:function(a){return{id:a,uri:"",exports:q[a],config:l(a)}}},m=function(a,c,d,f){var h,k,l,m,n,s,u=[],v=typeof d;if(f=f||a,"undefined"===v||"function"===v){for(c=!c.length&&d.length?["require","exports","module"]:c,n=0;n<c.length;n+=1)if(m=o(c[n],f),k=m.f,"require"===k)u[n]=p.require(a);else if("exports"===k)u[n]=p.exports(a),s=!0;else if("module"===k)h=u[n]=p.module(a);else if(e(q,k)||e(r,k)||e(t,k))u[n]=j(k);else{if(!m.p)throw new Error(a+" missing "+k);m.p.load(m.n,g(f,!0),i(k),{}),u[n]=q[k]}l=d?d.apply(q[a],u):void 0,a&&(h&&h.exports!==b&&h.exports!==q[a]?q[a]=h.exports:l===b&&s||(q[a]=l))}else a&&(q[a]=d)},a=c=n=function(a,c,d,e,f){if("string"==typeof a)return p[a]?p[a](c):j(o(a,c).f);if(!a.splice){if(s=a,s.deps&&n(s.deps,s.callback),!c)return;c.splice?(a=c,c=d,d=null):a=b}return c=c||function(){},"function"==typeof d&&(d=e,e=f),e?m(b,a,c,d):setTimeout(function(){m(b,a,c,d)},4),n},n.config=function(a){return n(a)},a._defined=q,d=function(a,b,c){if("string"!=typeof a)throw new Error("See almond README: incorrect module build, no module name");b.splice||(c=b,b=[]),e(q,a)||e(r,a)||(r[a]=[a,b,c])},d.amd={jQuery:!0}}(),b.requirejs=a,b.require=c,b.define=d}}(),b.define("almond",function(){}),b.define("jquery",[],function(){var b=a||$;return null==b&&console&&console.error&&console.error("Select2: An instance of jQuery or a jQuery-compatible library was not found. Make sure that you are including jQuery before Select2 on your web page."),b}),b.define("select2/utils",["jquery"],function(a){function b(a){var b=a.prototype,c=[];for(var d in b){var e=b[d];"function"==typeof e&&"constructor"!==d&&c.push(d)}return c}var c={};c.Extend=function(a,b){function c(){this.constructor=a}var d={}.hasOwnProperty;for(var e in b)d.call(b,e)&&(a[e]=b[e]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},c.Decorate=function(a,c){function d(){var b=Array.prototype.unshift,d=c.prototype.constructor.length,e=a.prototype.constructor;d>0&&(b.call(arguments,a.prototype.constructor),e=c.prototype.constructor),e.apply(this,arguments)}function e(){this.constructor=d}var f=b(c),g=b(a);c.displayName=a.displayName,d.prototype=new e;for(var h=0;h<g.length;h++){var i=g[h];d.prototype[i]=a.prototype[i]}for(var j=(function(a){var b=function(){};a in d.prototype&&(b=d.prototype[a]);var e=c.prototype[a];return function(){var a=Array.prototype.unshift;return a.call(arguments,b),e.apply(this,arguments)}}),k=0;k<f.length;k++){var l=f[k];d.prototype[l]=j(l)}return d};var d=function(){this.listeners={}};return d.prototype.on=function(a,b){this.listeners=this.listeners||{},a in this.listeners?this.listeners[a].push(b):this.listeners[a]=[b]},d.prototype.trigger=function(a){var b=Array.prototype.slice;this.listeners=this.listeners||{},a in this.listeners&&this.invoke(this.listeners[a],b.call(arguments,1)),"*"in this.listeners&&this.invoke(this.listeners["*"],arguments)},d.prototype.invoke=function(a,b){for(var c=0,d=a.length;d>c;c++)a[c].apply(this,b)},c.Observable=d,c.generateChars=function(a){for(var b="",c=0;a>c;c++){var d=Math.floor(36*Math.random());b+=d.toString(36)}return b},c.bind=function(a,b){return function(){a.apply(b,arguments)}},c._convertData=function(a){for(var b in a){var c=b.split("-"),d=a;if(1!==c.length){for(var e=0;e<c.length;e++){var f=c[e];f=f.substring(0,1).toLowerCase()+f.substring(1),f in d||(d[f]={}),e==c.length-1&&(d[f]=a[b]),d=d[f]}delete a[b]}}return a},c.hasScroll=function(b,c){var d=a(c),e=c.style.overflowX,f=c.style.overflowY;return e!==f||"hidden"!==f&&"visible"!==f?"scroll"===e||"scroll"===f?!0:d.innerHeight()<c.scrollHeight||d.innerWidth()<c.scrollWidth:!1},c.escapeMarkup=function(a){var b={"\\":"&#92;","&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#47;"};return"string"!=typeof a?a:String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})},c.appendMany=function(b,c){if("1.7"===a.fn.jquery.substr(0,3)){var d=a();a.map(c,function(a){d=d.add(a)}),c=d}b.append(c)},c}),b.define("select2/results",["jquery","./utils"],function(a,b){function c(a,b,d){this.$element=a,this.data=d,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<ul class="select2-results__options" role="tree"></ul>');return this.options.get("multiple")&&b.attr("aria-multiselectable","true"),this.$results=b,b},c.prototype.clear=function(){this.$results.empty()},c.prototype.displayMessage=function(b){var c=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var d=a('<li role="treeitem" aria-live="assertive" class="select2-results__option"></li>'),e=this.options.get("translations").get(b.message);d.append(c(e(b.args))),d[0].className+=" select2-results__message",this.$results.append(d)},c.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},c.prototype.append=function(a){this.hideLoading();var b=[];if(null==a.results||0===a.results.length)return void(0===this.$results.children().length&&this.trigger("results:message",{message:"noResults"}));a.results=this.sort(a.results);for(var c=0;c<a.results.length;c++){var d=a.results[c],e=this.option(d);b.push(e)}this.$results.append(b)},c.prototype.position=function(a,b){var c=b.find(".select2-results");c.append(a)},c.prototype.sort=function(a){var b=this.options.get("sorter");return b(a)},c.prototype.setClasses=function(){var b=this;this.data.current(function(c){var d=a.map(c,function(a){return a.id.toString()}),e=b.$results.find(".select2-results__option[aria-selected]");e.each(function(){var b=a(this),c=a.data(this,"data"),e=""+c.id;null!=c.element&&c.element.selected||null==c.element&&a.inArray(e,d)>-1?b.attr("aria-selected","true"):b.attr("aria-selected","false")});var f=e.filter("[aria-selected=true]");f.length>0?f.first().trigger("mouseenter"):e.first().trigger("mouseenter")})},c.prototype.showLoading=function(a){this.hideLoading();var b=this.options.get("translations").get("searching"),c={disabled:!0,loading:!0,text:b(a)},d=this.option(c);d.className+=" loading-results",this.$results.prepend(d)},c.prototype.hideLoading=function(){this.$results.find(".loading-results").remove()},c.prototype.option=function(b){var c=document.createElement("li");c.className="select2-results__option";var d={role:"treeitem","aria-selected":"false"};b.disabled&&(delete d["aria-selected"],d["aria-disabled"]="true"),null==b.id&&delete d["aria-selected"],null!=b._resultId&&(c.id=b._resultId),b.title&&(c.title=b.title),b.children&&(d.role="group",d["aria-label"]=b.text,delete d["aria-selected"]);for(var e in d){var f=d[e];c.setAttribute(e,f)}if(b.children){var g=a(c),h=document.createElement("strong");h.className="select2-results__group";a(h);this.template(b,h);for(var i=[],j=0;j<b.children.length;j++){var k=b.children[j],l=this.option(k);i.push(l)}var m=a("<ul></ul>",{"class":"select2-results__options select2-results__options--nested"});m.append(i),g.append(h),g.append(m)}else this.template(b,c);return a.data(c,"data",b),c},c.prototype.bind=function(b,c){var d=this,e=b.id+"-results";this.$results.attr("id",e),b.on("results:all",function(a){d.clear(),d.append(a.data),b.isOpen()&&d.setClasses()}),b.on("results:append",function(a){d.append(a.data),b.isOpen()&&d.setClasses()}),b.on("query",function(a){d.hideMessages(),d.showLoading(a)}),b.on("select",function(){b.isOpen()&&d.setClasses()}),b.on("unselect",function(){b.isOpen()&&d.setClasses()}),b.on("open",function(){d.$results.attr("aria-expanded","true"),d.$results.attr("aria-hidden","false"),d.setClasses(),d.ensureHighlightVisible()}),b.on("close",function(){d.$results.attr("aria-expanded","false"),d.$results.attr("aria-hidden","true"),d.$results.removeAttr("aria-activedescendant")}),b.on("results:toggle",function(){var a=d.getHighlightedResults();0!==a.length&&a.trigger("mouseup")}),b.on("results:select",function(){var a=d.getHighlightedResults();if(0!==a.length){var b=a.data("data");"true"==a.attr("aria-selected")?d.trigger("close",{}):d.trigger("select",{data:b})}}),b.on("results:previous",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a);if(0!==c){var e=c-1;0===a.length&&(e=0);var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top,h=f.offset().top,i=d.$results.scrollTop()+(h-g);0===e?d.$results.scrollTop(0):0>h-g&&d.$results.scrollTop(i)}}),b.on("results:next",function(){var a=d.getHighlightedResults(),b=d.$results.find("[aria-selected]"),c=b.index(a),e=c+1;if(!(e>=b.length)){var f=b.eq(e);f.trigger("mouseenter");var g=d.$results.offset().top+d.$results.outerHeight(!1),h=f.offset().top+f.outerHeight(!1),i=d.$results.scrollTop()+h-g;0===e?d.$results.scrollTop(0):h>g&&d.$results.scrollTop(i)}}),b.on("results:focus",function(a){a.element.addClass("select2-results__option--highlighted")}),b.on("results:message",function(a){d.displayMessage(a)}),a.fn.mousewheel&&this.$results.on("mousewheel",function(a){var b=d.$results.scrollTop(),c=d.$results.get(0).scrollHeight-d.$results.scrollTop()+a.deltaY,e=a.deltaY>0&&b-a.deltaY<=0,f=a.deltaY<0&&c<=d.$results.height();e?(d.$results.scrollTop(0),a.preventDefault(),a.stopPropagation()):f&&(d.$results.scrollTop(d.$results.get(0).scrollHeight-d.$results.height()),a.preventDefault(),a.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(b){var c=a(this),e=c.data("data");return"true"===c.attr("aria-selected")?void(d.options.get("multiple")?d.trigger("unselect",{originalEvent:b,data:e}):d.trigger("close",{})):void d.trigger("select",{originalEvent:b,data:e})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(b){var c=a(this).data("data");d.getHighlightedResults().removeClass("select2-results__option--highlighted"),d.trigger("results:focus",{data:c,element:a(this)})})},c.prototype.getHighlightedResults=function(){var a=this.$results.find(".select2-results__option--highlighted");return a},c.prototype.destroy=function(){this.$results.remove()},c.prototype.ensureHighlightVisible=function(){var a=this.getHighlightedResults();if(0!==a.length){var b=this.$results.find("[aria-selected]"),c=b.index(a),d=this.$results.offset().top,e=a.offset().top,f=this.$results.scrollTop()+(e-d),g=e-d;f-=2*a.outerHeight(!1),2>=c?this.$results.scrollTop(0):(g>this.$results.outerHeight()||0>g)&&this.$results.scrollTop(f)}},c.prototype.template=function(b,c){var d=this.options.get("templateResult"),e=this.options.get("escapeMarkup"),f=d(b,c);null==f?c.style.display="none":"string"==typeof f?c.innerHTML=e(f):a(c).append(f)},c}),b.define("select2/keys",[],function(){var a={BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46};return a}),b.define("select2/selection/base",["jquery","../utils","../keys"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,b.Observable),d.prototype.render=function(){var b=a('<span class="select2-selection" role="combobox" aria-haspopup="true" aria-expanded="false"></span>');return this._tabindex=0,null!=this.$element.data("old-tabindex")?this._tabindex=this.$element.data("old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),b.attr("title",this.$element.attr("title")),b.attr("tabindex",this._tabindex),this.$selection=b,b},d.prototype.bind=function(a,b){var d=this,e=(a.id+"-container",a.id+"-results");this.container=a,this.$selection.on("focus",function(a){d.trigger("focus",a)}),this.$selection.on("blur",function(a){d._handleBlur(a)}),this.$selection.on("keydown",function(a){d.trigger("keypress",a),a.which===c.SPACE&&a.preventDefault()}),a.on("results:focus",function(a){d.$selection.attr("aria-activedescendant",a.data._resultId)}),a.on("selection:update",function(a){d.update(a.data)}),a.on("open",function(){d.$selection.attr("aria-expanded","true"),d.$selection.attr("aria-owns",e),d._attachCloseHandler(a)}),a.on("close",function(){d.$selection.attr("aria-expanded","false"),d.$selection.removeAttr("aria-activedescendant"),d.$selection.removeAttr("aria-owns"),d.$selection.focus(),d._detachCloseHandler(a)}),a.on("enable",function(){d.$selection.attr("tabindex",d._tabindex)}),a.on("disable",function(){d.$selection.attr("tabindex","-1")})},d.prototype._handleBlur=function(b){var c=this;window.setTimeout(function(){document.activeElement==c.$selection[0]||a.contains(c.$selection[0],document.activeElement)||c.trigger("blur",b)},1)},d.prototype._attachCloseHandler=function(b){a(document.body).on("mousedown.select2."+b.id,function(b){var c=a(b.target),d=c.closest(".select2"),e=a(".select2.select2-container--open");e.each(function(){var b=a(this);if(this!=d[0]){var c=b.data("element");c.select2("close")}})})},d.prototype._detachCloseHandler=function(b){a(document.body).off("mousedown.select2."+b.id)},d.prototype.position=function(a,b){var c=b.find(".selection");c.append(a)},d.prototype.destroy=function(){this._detachCloseHandler(this.container)},d.prototype.update=function(a){throw new Error("The `update` method must be defined in child classes.")},d}),b.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(a,b,c,d){function e(){e.__super__.constructor.apply(this,arguments)}return c.Extend(e,b),e.prototype.render=function(){var a=e.__super__.render.call(this);return a.addClass("select2-selection--single"),a.html('<span class="select2-selection__rendered"></span><span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span>'),a},e.prototype.bind=function(a,b){var c=this;e.__super__.bind.apply(this,arguments);var d=a.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",d),this.$selection.attr("aria-labelledby",d),this.$selection.on("mousedown",function(a){1===a.which&&c.trigger("toggle",{originalEvent:a})}),this.$selection.on("focus",function(a){}),this.$selection.on("blur",function(a){}),a.on("selection:update",function(a){c.update(a.data)})},e.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},e.prototype.display=function(a,b){var c=this.options.get("templateSelection"),d=this.options.get("escapeMarkup");return d(c(a,b))},e.prototype.selectionContainer=function(){return a("<span></span>")},e.prototype.update=function(a){if(0===a.length)return void this.clear();var b=a[0],c=this.$selection.find(".select2-selection__rendered"),d=this.display(b,c);c.empty().append(d),c.prop("title",b.title||b.text)},e}),b.define("select2/selection/multiple",["jquery","./base","../utils"],function(a,b,c){function d(a,b){d.__super__.constructor.apply(this,arguments)}return c.Extend(d,b),d.prototype.render=function(){var a=d.__super__.render.call(this);return a.addClass("select2-selection--multiple"),a.html('<ul class="select2-selection__rendered"></ul>'),a},d.prototype.bind=function(b,c){var e=this;d.__super__.bind.apply(this,arguments),this.$selection.on("click",function(a){e.trigger("toggle",{originalEvent:a})}),this.$selection.on("click",".select2-selection__choice__remove",function(b){if(!e.options.get("disabled")){var c=a(this),d=c.parent(),f=d.data("data");e.trigger("unselect",{originalEvent:b,data:f})}})},d.prototype.clear=function(){this.$selection.find(".select2-selection__rendered").empty()},d.prototype.display=function(a,b){var c=this.options.get("templateSelection"),d=this.options.get("escapeMarkup");return d(c(a,b))},d.prototype.selectionContainer=function(){var b=a('<li class="select2-selection__choice"><span class="select2-selection__choice__remove" role="presentation">&times;</span></li>');return b},d.prototype.update=function(a){if(this.clear(),0!==a.length){for(var b=[],d=0;d<a.length;d++){var e=a[d],f=this.selectionContainer(),g=this.display(e,f);f.append(g),f.prop("title",e.title||e.text),f.data("data",e),b.push(f)}var h=this.$selection.find(".select2-selection__rendered");c.appendMany(h,b)}},d}),b.define("select2/selection/placeholder",["../utils"],function(a){function b(a,b,c){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c)}return b.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},b.prototype.createPlaceholder=function(a,b){var c=this.selectionContainer();return c.html(this.display(b)),c.addClass("select2-selection__placeholder").removeClass("select2-selection__choice"),c},b.prototype.update=function(a,b){var c=1==b.length&&b[0].id!=this.placeholder.id,d=b.length>1;if(d||c)return a.call(this,b);this.clear();var e=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(e)},b}),b.define("select2/selection/allowClear",["jquery","../keys"],function(a,b){function c(){}return c.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(a){d._handleClear(a)}),b.on("keypress",function(a){d._handleKeyboardClear(a,b)})},c.prototype._handleClear=function(a,b){if(!this.options.get("disabled")){var c=this.$selection.find(".select2-selection__clear");if(0!==c.length){b.stopPropagation();for(var d=c.data("data"),e=0;e<d.length;e++){var f={data:d[e]};if(this.trigger("unselect",f),f.prevented)return}this.$element.val(this.placeholder.id).trigger("change"),this.trigger("toggle",{})}}},c.prototype._handleKeyboardClear=function(a,c,d){d.isOpen()||(c.which==b.DELETE||c.which==b.BACKSPACE)&&this._handleClear(c)},c.prototype.update=function(b,c){if(b.call(this,c),!(this.$selection.find(".select2-selection__placeholder").length>0||0===c.length)){var d=a('<span class="select2-selection__clear">&times;</span>');d.data("data",c),this.$selection.find(".select2-selection__rendered").prepend(d)}},c}),b.define("select2/selection/search",["jquery","../utils","../keys"],function(a,b,c){function d(a,b,c){a.call(this,b,c)}return d.prototype.render=function(b){var c=a('<li class="select2-search select2-search--inline"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" aria-autocomplete="list" /></li>');this.$searchContainer=c,this.$search=c.find("input");var d=b.call(this);return this._transferTabIndex(),d},d.prototype.bind=function(a,b,d){var e=this;a.call(this,b,d),b.on("open",function(){e.$search.trigger("focus")}),b.on("close",function(){e.$search.val(""),e.$search.removeAttr("aria-activedescendant"),e.$search.trigger("focus")}),b.on("enable",function(){e.$search.prop("disabled",!1),e._transferTabIndex()}),b.on("disable",function(){e.$search.prop("disabled",!0)}),b.on("focus",function(a){e.$search.trigger("focus")}),b.on("results:focus",function(a){e.$search.attr("aria-activedescendant",a.id)}),this.$selection.on("focusin",".select2-search--inline",function(a){e.trigger("focus",a)}),this.$selection.on("focusout",".select2-search--inline",function(a){e._handleBlur(a)}),this.$selection.on("keydown",".select2-search--inline",function(a){a.stopPropagation(),e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented();var b=a.which;if(b===c.BACKSPACE&&""===e.$search.val()){var d=e.$searchContainer.prev(".select2-selection__choice");if(d.length>0){var f=d.data("data");e.searchRemoveChoice(f),a.preventDefault()}}});var f=document.documentMode,g=f&&11>=f;this.$selection.on("input.searchcheck",".select2-search--inline",function(a){return g?void e.$selection.off("input.search input.searchcheck"):void e.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(a){if(g&&"input"===a.type)return void e.$selection.off("input.search input.searchcheck");var b=a.which;b!=c.SHIFT&&b!=c.CTRL&&b!=c.ALT&&b!=c.TAB&&e.handleSearch(a)})},d.prototype._transferTabIndex=function(a){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},d.prototype.createPlaceholder=function(a,b){this.$search.attr("placeholder",b.text)},d.prototype.update=function(a,b){var c=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),a.call(this,b),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch(),c&&this.$search.focus()},d.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var a=this.$search.val();this.trigger("query",{term:a})}this._keyUpPrevented=!1},d.prototype.searchRemoveChoice=function(a,b){this.trigger("unselect",{data:b}),this.$search.val(b.text),this.handleSearch()},d.prototype.resizeSearch=function(){this.$search.css("width","25px");var a="";if(""!==this.$search.attr("placeholder"))a=this.$selection.find(".select2-selection__rendered").innerWidth();else{var b=this.$search.val().length+1;a=.75*b+"em"}this.$search.css("width",a)},d}),b.define("select2/selection/eventRelay",["jquery"],function(a){function b(){}return b.prototype.bind=function(b,c,d){var e=this,f=["open","opening","close","closing","select","selecting","unselect","unselecting"],g=["opening","closing","selecting","unselecting"];b.call(this,c,d),c.on("*",function(b,c){if(-1!==a.inArray(b,f)){c=c||{};var d=a.Event("select2:"+b,{params:c});e.$element.trigger(d),-1!==a.inArray(b,g)&&(c.prevented=d.isDefaultPrevented())}})},b}),b.define("select2/translation",["jquery","require"],function(a,b){function c(a){this.dict=a||{}}return c.prototype.all=function(){return this.dict},c.prototype.get=function(a){return this.dict[a]},c.prototype.extend=function(b){this.dict=a.extend({},b.all(),this.dict)},c._cache={},c.loadPath=function(a){if(!(a in c._cache)){var d=b(a);c._cache[a]=d}return new c(c._cache[a])},c}),b.define("select2/diacritics",[],function(){var a={"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"};return a}),b.define("select2/data/base",["../utils"],function(a){function b(a,c){b.__super__.constructor.call(this)}return a.Extend(b,a.Observable),b.prototype.current=function(a){throw new Error("The `current` method must be defined in child classes.")},b.prototype.query=function(a,b){throw new Error("The `query` method must be defined in child classes.")},b.prototype.bind=function(a,b){},b.prototype.destroy=function(){},b.prototype.generateResultId=function(b,c){var d=b.id+"-result-";return d+=a.generateChars(4),d+=null!=c.id?"-"+c.id.toString():"-"+a.generateChars(4)},b}),b.define("select2/data/select",["./base","../utils","jquery"],function(a,b,c){function d(a,b){this.$element=a,this.options=b,d.__super__.constructor.call(this)}return b.Extend(d,a),d.prototype.current=function(a){var b=[],d=this;this.$element.find(":selected").each(function(){var a=c(this),e=d.item(a);b.push(e)}),a(b)},d.prototype.select=function(a){var b=this;if(a.selected=!0,c(a.element).is("option"))return a.element.selected=!0,void this.$element.trigger("change");if(this.$element.prop("multiple"))this.current(function(d){var e=[];a=[a],a.push.apply(a,d);for(var f=0;f<a.length;f++){var g=a[f].id;-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")});else{var d=a.id;this.$element.val(d),this.$element.trigger("change")}},d.prototype.unselect=function(a){
2
+ var b=this;if(this.$element.prop("multiple"))return a.selected=!1,c(a.element).is("option")?(a.element.selected=!1,void this.$element.trigger("change")):void this.current(function(d){for(var e=[],f=0;f<d.length;f++){var g=d[f].id;g!==a.id&&-1===c.inArray(g,e)&&e.push(g)}b.$element.val(e),b.$element.trigger("change")})},d.prototype.bind=function(a,b){var c=this;this.container=a,a.on("select",function(a){c.select(a.data)}),a.on("unselect",function(a){c.unselect(a.data)})},d.prototype.destroy=function(){this.$element.find("*").each(function(){c.removeData(this,"data")})},d.prototype.query=function(a,b){var d=[],e=this,f=this.$element.children();f.each(function(){var b=c(this);if(b.is("option")||b.is("optgroup")){var f=e.item(b),g=e.matches(a,f);null!==g&&d.push(g)}}),b({results:d})},d.prototype.addOptions=function(a){b.appendMany(this.$element,a)},d.prototype.option=function(a){var b;a.children?(b=document.createElement("optgroup"),b.label=a.text):(b=document.createElement("option"),void 0!==b.textContent?b.textContent=a.text:b.innerText=a.text),a.id&&(b.value=a.id),a.disabled&&(b.disabled=!0),a.selected&&(b.selected=!0),a.title&&(b.title=a.title);var d=c(b),e=this._normalizeItem(a);return e.element=b,c.data(b,"data",e),d},d.prototype.item=function(a){var b={};if(b=c.data(a[0],"data"),null!=b)return b;if(a.is("option"))b={id:a.val(),text:a.text(),disabled:a.prop("disabled"),selected:a.prop("selected"),title:a.prop("title")};else if(a.is("optgroup")){b={text:a.prop("label"),children:[],title:a.prop("title")};for(var d=a.children("option"),e=[],f=0;f<d.length;f++){var g=c(d[f]),h=this.item(g);e.push(h)}b.children=e}return b=this._normalizeItem(b),b.element=a[0],c.data(a[0],"data",b),b},d.prototype._normalizeItem=function(a){c.isPlainObject(a)||(a={id:a,text:a}),a=c.extend({},{text:""},a);var b={selected:!1,disabled:!1};return null!=a.id&&(a.id=a.id.toString()),null!=a.text&&(a.text=a.text.toString()),null==a._resultId&&a.id&&null!=this.container&&(a._resultId=this.generateResultId(this.container,a)),c.extend({},b,a)},d.prototype.matches=function(a,b){var c=this.options.get("matcher");return c(a,b)},d}),b.define("select2/data/array",["./select","../utils","jquery"],function(a,b,c){function d(a,b){var c=b.get("data")||[];d.__super__.constructor.call(this,a,b),this.addOptions(this.convertToOptions(c))}return b.Extend(d,a),d.prototype.select=function(a){var b=this.$element.find("option").filter(function(b,c){return c.value==a.id.toString()});0===b.length&&(b=this.option(a),this.addOptions(b)),d.__super__.select.call(this,a)},d.prototype.convertToOptions=function(a){function d(a){return function(){return c(this).val()==a.id}}for(var e=this,f=this.$element.find("option"),g=f.map(function(){return e.item(c(this)).id}).get(),h=[],i=0;i<a.length;i++){var j=this._normalizeItem(a[i]);if(c.inArray(j.id,g)>=0){var k=f.filter(d(j)),l=this.item(k),m=c.extend(!0,{},l,j),n=this.option(m);k.replaceWith(n)}else{var o=this.option(j);if(j.children){var p=this.convertToOptions(j.children);b.appendMany(o,p)}h.push(o)}}return h},d}),b.define("select2/data/ajax",["./array","../utils","jquery"],function(a,b,c){function d(a,b){this.ajaxOptions=this._applyDefaults(b.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),d.__super__.constructor.call(this,a,b)}return b.Extend(d,a),d.prototype._applyDefaults=function(a){var b={data:function(a){return c.extend({},a,{q:a.term})},transport:function(a,b,d){var e=c.ajax(a);return e.then(b),e.fail(d),e}};return c.extend({},b,a,!0)},d.prototype.processResults=function(a){return a},d.prototype.query=function(a,b){function d(){var d=f.transport(f,function(d){var f=e.processResults(d,a);e.options.get("debug")&&window.console&&console.error&&(f&&f.results&&c.isArray(f.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),b(f)},function(){});e._request=d}var e=this;null!=this._request&&(c.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var f=c.extend({type:"GET"},this.ajaxOptions);"function"==typeof f.url&&(f.url=f.url.call(this.$element,a)),"function"==typeof f.data&&(f.data=f.data.call(this.$element,a)),this.ajaxOptions.delay&&""!==a.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(d,this.ajaxOptions.delay)):d()},d}),b.define("select2/data/tags",["jquery"],function(a){function b(b,c,d){var e=d.get("tags"),f=d.get("createTag");if(void 0!==f&&(this.createTag=f),b.call(this,c,d),a.isArray(e))for(var g=0;g<e.length;g++){var h=e[g],i=this._normalizeItem(h),j=this.option(i);this.$element.append(j)}}return b.prototype.query=function(a,b,c){function d(a,f){for(var g=a.results,h=0;h<g.length;h++){var i=g[h],j=null!=i.children&&!d({results:i.children},!0),k=i.text===b.term;if(k||j)return f?!1:(a.data=g,void c(a))}if(f)return!0;var l=e.createTag(b);if(null!=l){var m=e.option(l);m.attr("data-select2-tag",!0),e.addOptions([m]),e.insertTag(g,l)}a.results=g,c(a)}var e=this;return this._removeOldTags(),null==b.term||null!=b.page?void a.call(this,b,c):void a.call(this,b,d)},b.prototype.createTag=function(b,c){var d=a.trim(c.term);return""===d?null:{id:d,text:d}},b.prototype.insertTag=function(a,b,c){b.unshift(c)},b.prototype._removeOldTags=function(b){var c=(this._lastTag,this.$element.find("option[data-select2-tag]"));c.each(function(){this.selected||a(this).remove()})},b}),b.define("select2/data/tokenizer",["jquery"],function(a){function b(a,b,c){var d=c.get("tokenizer");void 0!==d&&(this.tokenizer=d),a.call(this,b,c)}return b.prototype.bind=function(a,b,c){a.call(this,b,c),this.$search=b.dropdown.$search||b.selection.$search||c.find(".select2-search__field")},b.prototype.query=function(a,b,c){function d(a){e.trigger("select",{data:a})}var e=this;b.term=b.term||"";var f=this.tokenizer(b,this.options,d);f.term!==b.term&&(this.$search.length&&(this.$search.val(f.term),this.$search.focus()),b.term=f.term),a.call(this,b,c)},b.prototype.tokenizer=function(b,c,d,e){for(var f=d.get("tokenSeparators")||[],g=c.term,h=0,i=this.createTag||function(a){return{id:a.term,text:a.term}};h<g.length;){var j=g[h];if(-1!==a.inArray(j,f)){var k=g.substr(0,h),l=a.extend({},c,{term:k}),m=i(l);null!=m?(e(m),g=g.substr(h+1)||"",h=0):h++}else h++}return{term:g}},b}),b.define("select2/data/minimumInputLength",[],function(){function a(a,b,c){this.minimumInputLength=c.get("minimumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",b.term.length<this.minimumInputLength?void this.trigger("results:message",{message:"inputTooShort",args:{minimum:this.minimumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumInputLength",[],function(){function a(a,b,c){this.maximumInputLength=c.get("maximumInputLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){return b.term=b.term||"",this.maximumInputLength>0&&b.term.length>this.maximumInputLength?void this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:b.term,params:b}}):void a.call(this,b,c)},a}),b.define("select2/data/maximumSelectionLength",[],function(){function a(a,b,c){this.maximumSelectionLength=c.get("maximumSelectionLength"),a.call(this,b,c)}return a.prototype.query=function(a,b,c){var d=this;this.current(function(e){var f=null!=e?e.length:0;return d.maximumSelectionLength>0&&f>=d.maximumSelectionLength?void d.trigger("results:message",{message:"maximumSelected",args:{maximum:d.maximumSelectionLength}}):void a.call(d,b,c)})},a}),b.define("select2/dropdown",["jquery","./utils"],function(a,b){function c(a,b){this.$element=a,this.options=b,c.__super__.constructor.call(this)}return b.Extend(c,b.Observable),c.prototype.render=function(){var b=a('<span class="select2-dropdown"><span class="select2-results"></span></span>');return b.attr("dir",this.options.get("dir")),this.$dropdown=b,b},c.prototype.bind=function(){},c.prototype.position=function(a,b){},c.prototype.destroy=function(){this.$dropdown.remove()},c}),b.define("select2/dropdown/search",["jquery","../utils"],function(a,b){function c(){}return c.prototype.render=function(b){var c=b.call(this),d=a('<span class="select2-search select2-search--dropdown"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="textbox" /></span>');return this.$searchContainer=d,this.$search=d.find("input"),c.prepend(d),c},c.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),this.$search.on("keydown",function(a){e.trigger("keypress",a),e._keyUpPrevented=a.isDefaultPrevented()}),this.$search.on("input",function(b){a(this).off("keyup")}),this.$search.on("keyup input",function(a){e.handleSearch(a)}),c.on("open",function(){e.$search.attr("tabindex",0),e.$search.focus(),window.setTimeout(function(){e.$search.focus()},0)}),c.on("close",function(){e.$search.attr("tabindex",-1),e.$search.val("")}),c.on("results:all",function(a){if(null==a.query.term||""===a.query.term){var b=e.showSearch(a);b?e.$searchContainer.removeClass("select2-search--hide"):e.$searchContainer.addClass("select2-search--hide")}})},c.prototype.handleSearch=function(a){if(!this._keyUpPrevented){var b=this.$search.val();this.trigger("query",{term:b})}this._keyUpPrevented=!1},c.prototype.showSearch=function(a,b){return!0},c}),b.define("select2/dropdown/hidePlaceholder",[],function(){function a(a,b,c,d){this.placeholder=this.normalizePlaceholder(c.get("placeholder")),a.call(this,b,c,d)}return a.prototype.append=function(a,b){b.results=this.removePlaceholder(b.results),a.call(this,b)},a.prototype.normalizePlaceholder=function(a,b){return"string"==typeof b&&(b={id:"",text:b}),b},a.prototype.removePlaceholder=function(a,b){for(var c=b.slice(0),d=b.length-1;d>=0;d--){var e=b[d];this.placeholder.id===e.id&&c.splice(d,1)}return c},a}),b.define("select2/dropdown/infiniteScroll",["jquery"],function(a){function b(a,b,c,d){this.lastParams={},a.call(this,b,c,d),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return b.prototype.append=function(a,b){this.$loadingMore.remove(),this.loading=!1,a.call(this,b),this.showLoadingMore(b)&&this.$results.append(this.$loadingMore)},b.prototype.bind=function(b,c,d){var e=this;b.call(this,c,d),c.on("query",function(a){e.lastParams=a,e.loading=!0}),c.on("query:append",function(a){e.lastParams=a,e.loading=!0}),this.$results.on("scroll",function(){var b=a.contains(document.documentElement,e.$loadingMore[0]);if(!e.loading&&b){var c=e.$results.offset().top+e.$results.outerHeight(!1),d=e.$loadingMore.offset().top+e.$loadingMore.outerHeight(!1);c+50>=d&&e.loadMore()}})},b.prototype.loadMore=function(){this.loading=!0;var b=a.extend({},{page:1},this.lastParams);b.page++,this.trigger("query:append",b)},b.prototype.showLoadingMore=function(a,b){return b.pagination&&b.pagination.more},b.prototype.createLoadingMore=function(){var b=a('<li class="select2-results__option select2-results__option--load-more"role="treeitem" aria-disabled="true"></li>'),c=this.options.get("translations").get("loadingMore");return b.html(c(this.lastParams)),b},b}),b.define("select2/dropdown/attachBody",["jquery","../utils"],function(a,b){function c(b,c,d){this.$dropdownParent=d.get("dropdownParent")||a(document.body),b.call(this,c,d)}return c.prototype.bind=function(a,b,c){var d=this,e=!1;a.call(this,b,c),b.on("open",function(){d._showDropdown(),d._attachPositioningHandler(b),e||(e=!0,b.on("results:all",function(){d._positionDropdown(),d._resizeDropdown()}),b.on("results:append",function(){d._positionDropdown(),d._resizeDropdown()}))}),b.on("close",function(){d._hideDropdown(),d._detachPositioningHandler(b)}),this.$dropdownContainer.on("mousedown",function(a){a.stopPropagation()})},c.prototype.destroy=function(a){a.call(this),this.$dropdownContainer.remove()},c.prototype.position=function(a,b,c){b.attr("class",c.attr("class")),b.removeClass("select2"),b.addClass("select2-container--open"),b.css({position:"absolute",top:-999999}),this.$container=c},c.prototype.render=function(b){var c=a("<span></span>"),d=b.call(this);return c.append(d),this.$dropdownContainer=c,c},c.prototype._hideDropdown=function(a){this.$dropdownContainer.detach()},c.prototype._attachPositioningHandler=function(c,d){var e=this,f="scroll.select2."+d.id,g="resize.select2."+d.id,h="orientationchange.select2."+d.id,i=this.$container.parents().filter(b.hasScroll);i.each(function(){a(this).data("select2-scroll-position",{x:a(this).scrollLeft(),y:a(this).scrollTop()})}),i.on(f,function(b){var c=a(this).data("select2-scroll-position");a(this).scrollTop(c.y)}),a(window).on(f+" "+g+" "+h,function(a){e._positionDropdown(),e._resizeDropdown()})},c.prototype._detachPositioningHandler=function(c,d){var e="scroll.select2."+d.id,f="resize.select2."+d.id,g="orientationchange.select2."+d.id,h=this.$container.parents().filter(b.hasScroll);h.off(e),a(window).off(e+" "+f+" "+g)},c.prototype._positionDropdown=function(){var b=a(window),c=this.$dropdown.hasClass("select2-dropdown--above"),d=this.$dropdown.hasClass("select2-dropdown--below"),e=null,f=(this.$container.position(),this.$container.offset());f.bottom=f.top+this.$container.outerHeight(!1);var g={height:this.$container.outerHeight(!1)};g.top=f.top,g.bottom=f.top+g.height;var h={height:this.$dropdown.outerHeight(!1)},i={top:b.scrollTop(),bottom:b.scrollTop()+b.height()},j=i.top<f.top-h.height,k=i.bottom>f.bottom+h.height,l={left:f.left,top:g.bottom};if("static"!==this.$dropdownParent[0].style.position){var m=this.$dropdownParent.offset();l.top-=m.top,l.left-=m.left}c||d||(e="below"),k||!j||c?!j&&k&&c&&(e="below"):e="above",("above"==e||c&&"below"!==e)&&(l.top=g.top-h.height),null!=e&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+e),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+e)),this.$dropdownContainer.css(l)},c.prototype._resizeDropdown=function(){var a={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(a.minWidth=a.width,a.width="auto"),this.$dropdown.css(a)},c.prototype._showDropdown=function(a){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},c}),b.define("select2/dropdown/minimumResultsForSearch",[],function(){function a(b){for(var c=0,d=0;d<b.length;d++){var e=b[d];e.children?c+=a(e.children):c++}return c}function b(a,b,c,d){this.minimumResultsForSearch=c.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),a.call(this,b,c,d)}return b.prototype.showSearch=function(b,c){return a(c.data.results)<this.minimumResultsForSearch?!1:b.call(this,c)},b}),b.define("select2/dropdown/selectOnClose",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("close",function(){d._handleSelectOnClose()})},a.prototype._handleSelectOnClose=function(){var a=this.getHighlightedResults();if(!(a.length<1)){var b=a.data("data");null!=b.element&&b.element.selected||null==b.element&&b.selected||this.trigger("select",{data:b})}},a}),b.define("select2/dropdown/closeOnSelect",[],function(){function a(){}return a.prototype.bind=function(a,b,c){var d=this;a.call(this,b,c),b.on("select",function(a){d._selectTriggered(a)}),b.on("unselect",function(a){d._selectTriggered(a)})},a.prototype._selectTriggered=function(a,b){var c=b.originalEvent;c&&c.ctrlKey||this.trigger("close",{})},a}),b.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(a){var b=a.input.length-a.maximum,c="Please delete "+b+" character";return 1!=b&&(c+="s"),c},inputTooShort:function(a){var b=a.minimum-a.input.length,c="Please enter "+b+" or more characters";return c},loadingMore:function(){return"Loading more results…"},maximumSelected:function(a){var b="You can only select "+a.maximum+" item";return 1!=a.maximum&&(b+="s"),b},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),b.define("select2/defaults",["jquery","require","./results","./selection/single","./selection/multiple","./selection/placeholder","./selection/allowClear","./selection/search","./selection/eventRelay","./utils","./translation","./diacritics","./data/select","./data/array","./data/ajax","./data/tags","./data/tokenizer","./data/minimumInputLength","./data/maximumInputLength","./data/maximumSelectionLength","./dropdown","./dropdown/search","./dropdown/hidePlaceholder","./dropdown/infiniteScroll","./dropdown/attachBody","./dropdown/minimumResultsForSearch","./dropdown/selectOnClose","./dropdown/closeOnSelect","./i18n/en"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C){function D(){this.reset()}D.prototype.apply=function(l){if(l=a.extend({},this.defaults,l),null==l.dataAdapter){if(null!=l.ajax?l.dataAdapter=o:null!=l.data?l.dataAdapter=n:l.dataAdapter=m,l.minimumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,r)),l.maximumInputLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,s)),l.maximumSelectionLength>0&&(l.dataAdapter=j.Decorate(l.dataAdapter,t)),l.tags&&(l.dataAdapter=j.Decorate(l.dataAdapter,p)),(null!=l.tokenSeparators||null!=l.tokenizer)&&(l.dataAdapter=j.Decorate(l.dataAdapter,q)),null!=l.query){var C=b(l.amdBase+"compat/query");l.dataAdapter=j.Decorate(l.dataAdapter,C)}if(null!=l.initSelection){var D=b(l.amdBase+"compat/initSelection");l.dataAdapter=j.Decorate(l.dataAdapter,D)}}if(null==l.resultsAdapter&&(l.resultsAdapter=c,null!=l.ajax&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,x)),null!=l.placeholder&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,w)),l.selectOnClose&&(l.resultsAdapter=j.Decorate(l.resultsAdapter,A))),null==l.dropdownAdapter){if(l.multiple)l.dropdownAdapter=u;else{var E=j.Decorate(u,v);l.dropdownAdapter=E}if(0!==l.minimumResultsForSearch&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,z)),l.closeOnSelect&&(l.dropdownAdapter=j.Decorate(l.dropdownAdapter,B)),null!=l.dropdownCssClass||null!=l.dropdownCss||null!=l.adaptDropdownCssClass){var F=b(l.amdBase+"compat/dropdownCss");l.dropdownAdapter=j.Decorate(l.dropdownAdapter,F)}l.dropdownAdapter=j.Decorate(l.dropdownAdapter,y)}if(null==l.selectionAdapter){if(l.multiple?l.selectionAdapter=e:l.selectionAdapter=d,null!=l.placeholder&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,f)),l.allowClear&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,g)),l.multiple&&(l.selectionAdapter=j.Decorate(l.selectionAdapter,h)),null!=l.containerCssClass||null!=l.containerCss||null!=l.adaptContainerCssClass){var G=b(l.amdBase+"compat/containerCss");l.selectionAdapter=j.Decorate(l.selectionAdapter,G)}l.selectionAdapter=j.Decorate(l.selectionAdapter,i)}if("string"==typeof l.language)if(l.language.indexOf("-")>0){var H=l.language.split("-"),I=H[0];l.language=[l.language,I]}else l.language=[l.language];if(a.isArray(l.language)){var J=new k;l.language.push("en");for(var K=l.language,L=0;L<K.length;L++){var M=K[L],N={};try{N=k.loadPath(M)}catch(O){try{M=this.defaults.amdLanguageBase+M,N=k.loadPath(M)}catch(P){l.debug&&window.console&&console.warn&&console.warn('Select2: The language file for "'+M+'" could not be automatically loaded. A fallback will be used instead.');continue}}J.extend(N)}l.translations=J}else{var Q=k.loadPath(this.defaults.amdLanguageBase+"en"),R=new k(l.language);R.extend(Q),l.translations=R}return l},D.prototype.reset=function(){function b(a){function b(a){return l[a]||a}return a.replace(/[^\u0000-\u007E]/g,b)}function c(d,e){if(""===a.trim(d.term))return e;if(e.children&&e.children.length>0){for(var f=a.extend(!0,{},e),g=e.children.length-1;g>=0;g--){var h=e.children[g],i=c(d,h);null==i&&f.children.splice(g,1)}return f.children.length>0?f:c(d,f)}var j=b(e.text).toUpperCase(),k=b(d.term).toUpperCase();return j.indexOf(k)>-1?e:null}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:j.escapeMarkup,language:C,matcher:c,minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,sorter:function(a){return a},templateResult:function(a){return a.text},templateSelection:function(a){return a.text},theme:"default",width:"resolve"}},D.prototype.set=function(b,c){var d=a.camelCase(b),e={};e[d]=c;var f=j._convertData(e);a.extend(this.defaults,f)};var E=new D;return E}),b.define("select2/options",["require","jquery","./defaults","./utils"],function(a,b,c,d){function e(b,e){if(this.options=b,null!=e&&this.fromElement(e),this.options=c.apply(this.options),e&&e.is("input")){var f=a(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=d.Decorate(this.options.dataAdapter,f)}}return e.prototype.fromElement=function(a){var c=["select2"];null==this.options.multiple&&(this.options.multiple=a.prop("multiple")),null==this.options.disabled&&(this.options.disabled=a.prop("disabled")),null==this.options.language&&(a.prop("lang")?this.options.language=a.prop("lang").toLowerCase():a.closest("[lang]").prop("lang")&&(this.options.language=a.closest("[lang]").prop("lang"))),null==this.options.dir&&(a.prop("dir")?this.options.dir=a.prop("dir"):a.closest("[dir]").prop("dir")?this.options.dir=a.closest("[dir]").prop("dir"):this.options.dir="ltr"),a.prop("disabled",this.options.disabled),a.prop("multiple",this.options.multiple),a.data("select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),a.data("data",a.data("select2Tags")),a.data("tags",!0)),a.data("ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),a.attr("ajax--url",a.data("ajaxUrl")),a.data("ajax--url",a.data("ajaxUrl")));var e={};e=b.fn.jquery&&"1."==b.fn.jquery.substr(0,2)&&a[0].dataset?b.extend(!0,{},a[0].dataset,a.data()):a.data();var f=b.extend(!0,{},e);f=d._convertData(f);for(var g in f)b.inArray(g,c)>-1||(b.isPlainObject(this.options[g])?b.extend(this.options[g],f[g]):this.options[g]=f[g]);return this},e.prototype.get=function(a){return this.options[a]},e.prototype.set=function(a,b){this.options[a]=b},e}),b.define("select2/core",["jquery","./options","./utils","./keys"],function(a,b,c,d){var e=function(a,c){null!=a.data("select2")&&a.data("select2").destroy(),this.$element=a,this.id=this._generateId(a),c=c||{},this.options=new b(c,a),e.__super__.constructor.call(this);var d=a.attr("tabindex")||0;a.data("old-tabindex",d),a.attr("tabindex","-1");var f=this.options.get("dataAdapter");this.dataAdapter=new f(a,this.options);var g=this.render();this._placeContainer(g);var h=this.options.get("selectionAdapter");this.selection=new h(a,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,g);var i=this.options.get("dropdownAdapter");this.dropdown=new i(a,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,g);var j=this.options.get("resultsAdapter");this.results=new j(a,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var k=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(a){k.trigger("selection:update",{data:a})}),a.addClass("select2-hidden-accessible"),a.attr("aria-hidden","true"),this._syncAttributes(),a.data("select2",this)};return c.Extend(e,c.Observable),e.prototype._generateId=function(a){var b="";return b=null!=a.attr("id")?a.attr("id"):null!=a.attr("name")?a.attr("name")+"-"+c.generateChars(2):c.generateChars(4),b="select2-"+b},e.prototype._placeContainer=function(a){a.insertAfter(this.$element);var b=this._resolveWidth(this.$element,this.options.get("width"));null!=b&&a.css("width",b)},e.prototype._resolveWidth=function(a,b){var c=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==b){var d=this._resolveWidth(a,"style");return null!=d?d:this._resolveWidth(a,"element")}if("element"==b){var e=a.outerWidth(!1);return 0>=e?"auto":e+"px"}if("style"==b){var f=a.attr("style");if("string"!=typeof f)return null;for(var g=f.split(";"),h=0,i=g.length;i>h;h+=1){var j=g[h].replace(/\s/g,""),k=j.match(c);if(null!==k&&k.length>=1)return k[1]}return null}return b},e.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},e.prototype._registerDomEvents=function(){var b=this;this.$element.on("change.select2",function(){b.dataAdapter.current(function(a){b.trigger("selection:update",{data:a})})}),this._sync=c.bind(this._syncAttributes,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._sync);var d=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=d?(this._observer=new d(function(c){a.each(c,b._sync)}),this._observer.observe(this.$element[0],{attributes:!0,subtree:!1})):this.$element[0].addEventListener&&this.$element[0].addEventListener("DOMAttrModified",b._sync,!1)},e.prototype._registerDataEvents=function(){var a=this;this.dataAdapter.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerSelectionEvents=function(){var b=this,c=["toggle","focus"];this.selection.on("toggle",function(){b.toggleDropdown()}),this.selection.on("focus",function(a){b.focus(a)}),this.selection.on("*",function(d,e){-1===a.inArray(d,c)&&b.trigger(d,e)})},e.prototype._registerDropdownEvents=function(){var a=this;this.dropdown.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerResultsEvents=function(){var a=this;this.results.on("*",function(b,c){a.trigger(b,c)})},e.prototype._registerEvents=function(){var a=this;this.on("open",function(){a.$container.addClass("select2-container--open")}),this.on("close",function(){a.$container.removeClass("select2-container--open")}),this.on("enable",function(){a.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){a.$container.addClass("select2-container--disabled")}),this.on("blur",function(){a.$container.removeClass("select2-container--focus")}),this.on("query",function(b){a.isOpen()||a.trigger("open",{}),this.dataAdapter.query(b,function(c){a.trigger("results:all",{data:c,query:b})})}),this.on("query:append",function(b){this.dataAdapter.query(b,function(c){a.trigger("results:append",{data:c,query:b})})}),this.on("keypress",function(b){var c=b.which;a.isOpen()?c===d.ESC||c===d.TAB||c===d.UP&&b.altKey?(a.close(),b.preventDefault()):c===d.ENTER?(a.trigger("results:select",{}),b.preventDefault()):c===d.SPACE&&b.ctrlKey?(a.trigger("results:toggle",{}),b.preventDefault()):c===d.UP?(a.trigger("results:previous",{}),b.preventDefault()):c===d.DOWN&&(a.trigger("results:next",{}),b.preventDefault()):(c===d.ENTER||c===d.SPACE||c===d.DOWN&&b.altKey)&&(a.open(),b.preventDefault())})},e.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable",{})):this.trigger("enable",{})},e.prototype.trigger=function(a,b){var c=e.__super__.trigger,d={open:"opening",close:"closing",select:"selecting",unselect:"unselecting"};if(void 0===b&&(b={}),a in d){var f=d[a],g={prevented:!1,name:a,args:b};if(c.call(this,f,g),g.prevented)return void(b.prevented=!0)}c.call(this,a,b)},e.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},e.prototype.open=function(){this.isOpen()||this.trigger("query",{})},e.prototype.close=function(){this.isOpen()&&this.trigger("close",{})},e.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},e.prototype.hasFocus=function(){return this.$container.hasClass("select2-container--focus")},e.prototype.focus=function(a){this.hasFocus()||(this.$container.addClass("select2-container--focus"),this.trigger("focus",{}))},e.prototype.enable=function(a){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),(null==a||0===a.length)&&(a=[!0]);var b=!a[0];this.$element.prop("disabled",b)},e.prototype.data=function(){this.options.get("debug")&&arguments.length>0&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var a=[];return this.dataAdapter.current(function(b){a=b}),a},e.prototype.val=function(b){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==b||0===b.length)return this.$element.val();var c=b[0];a.isArray(c)&&(c=a.map(c,function(a){return a.toString()})),this.$element.val(c).trigger("change")},e.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._sync),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&this.$element[0].removeEventListener("DOMAttrModified",this._sync,!1),this._sync=null,this.$element.off(".select2"),this.$element.attr("tabindex",this.$element.data("old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null},e.prototype.render=function(){var b=a('<span class="select2 select2-container"><span class="selection"></span><span class="dropdown-wrapper" aria-hidden="true"></span></span>');return b.attr("dir",this.options.get("dir")),this.$container=b,this.$container.addClass("select2-container--"+this.options.get("theme")),b.data("element",this.$element),b},e}),b.define("jquery-mousewheel",["jquery"],function(a){return a}),b.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults"],function(a,b,c,d){if(null==a.fn.select2){var e=["open","close","destroy"];a.fn.select2=function(b){if(b=b||{},"object"==typeof b)return this.each(function(){var d=a.extend(!0,{},b);new c(a(this),d)}),this;if("string"==typeof b){var d;return this.each(function(){var c=a(this).data("select2");null==c&&window.console&&console.error&&console.error("The select2('"+b+"') method was called on an element that is not using Select2.");var e=Array.prototype.slice.call(arguments,1);d=c[b].apply(c,e)}),a.inArray(b,e)>-1?this:d}throw new Error("Invalid arguments for Select2: "+b)}}return null==a.fn.select2.defaults&&(a.fn.select2.defaults=d),c}),{define:b.define,require:b.require}}(),c=b.require("jquery.select2");return a.fn.select2.amd=b,c});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/taxonomy.js DELETED
@@ -1,31 +0,0 @@
1
- jQuery( function( $ )
2
- {
3
- 'use strict';
4
-
5
- $( '.rw-taxonomy-tree input:checkbox' ).change( function()
6
- {
7
- var $this = $( this ),
8
- $childList = $this.parent().siblings( '.rw-taxonomy-tree' );
9
- if ( $this.is( ':checked' ) )
10
- {
11
- $childList.removeClass( 'hidden' );
12
- }
13
- else
14
- {
15
- $childList.find( 'input' ).removeAttr( 'checked' );
16
- $childList.addClass( 'hidden' );
17
- }
18
- } );
19
-
20
- $( '.rw-taxonomy-tree select' ).change( function()
21
- {
22
- var $this = $( this ),
23
- $childList = $this.siblings( '.rw-taxonomy-tree' ),
24
- $value = $this.val();
25
- $childList.removeClass( 'active' ).addClass( 'disabled' ).find( 'select' ).each( function()
26
- {
27
- $( this ).val( $( 'options:first', this ).val() ).attr( 'disabled', 'disabled' );
28
- } );
29
- $childList.filter( '.rwmb-taxonomy-' + $value ).removeClass( 'disabled' ).addClass( 'active' ).children( 'select' ).removeAttr( 'disabled' );
30
- } );
31
- } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/time.js CHANGED
@@ -12,7 +12,7 @@ jQuery( function ( $ )
12
  options = $this.data( 'options' );
13
 
14
  $this.siblings( '.ui-datepicker-append' ).remove(); // Remove appended text
15
- $this.removeClass( 'hasDatepicker' ).attr( 'id', '' ).timepicker( options );
16
  }
17
 
18
  // Set language if available
12
  options = $this.data( 'options' );
13
 
14
  $this.siblings( '.ui-datepicker-append' ).remove(); // Remove appended text
15
+ $this.removeClass( 'hasDatepicker' ).timepicker( options );
16
  }
17
 
18
  // Set language if available
meta-box-loader.php DELETED
@@ -1,18 +0,0 @@
1
- <?php
2
-
3
- class RWMB_Loader
4
- {
5
- static function load( $url, $dir )
6
- {
7
- define( 'RWMB_VER', '4.7.3' );
8
-
9
- define( 'RWMB_URL', $url );
10
- define( 'RWMB_DIR', $dir );
11
-
12
- define( 'RWMB_JS_URL', trailingslashit( RWMB_URL . 'js' ) );
13
- define( 'RWMB_CSS_URL', trailingslashit( RWMB_URL . 'css' ) );
14
-
15
- define( 'RWMB_INC_DIR', trailingslashit( RWMB_DIR . 'inc' ) );
16
- define( 'RWMB_FIELDS_DIR', trailingslashit( RWMB_INC_DIR . 'fields' ) );
17
- }
18
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
meta-box.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Meta Box
4
  * Plugin URI: https://metabox.io
5
  * Description: Create custom meta boxes and custom fields for any post type in WordPress.
6
- * Version: 4.7.3
7
  * Author: Rilwis
8
  * Author URI: http://www.deluxeblogtips.com
9
  * License: GPL2+
@@ -11,43 +11,8 @@
11
  * Domain Path: /lang/
12
  */
13
 
14
- // Prevent loading this file directly
15
- defined( 'ABSPATH' ) || exit;
16
-
17
- // Script version, used to add version for scripts and styles
18
- define( 'RWMB_VER', '4.7.3' );
19
-
20
- // Define plugin URLs, for fast enqueuing scripts and styles
21
- if ( ! defined( 'RWMB_URL' ) )
22
- define( 'RWMB_URL', plugin_dir_url( __FILE__ ) );
23
- define( 'RWMB_JS_URL', trailingslashit( RWMB_URL . 'js' ) );
24
- define( 'RWMB_CSS_URL', trailingslashit( RWMB_URL . 'css' ) );
25
-
26
- // Plugin paths, for including files
27
- if ( ! defined( 'RWMB_DIR' ) )
28
- define( 'RWMB_DIR', plugin_dir_path( __FILE__ ) );
29
- define( 'RWMB_INC_DIR', trailingslashit( RWMB_DIR . 'inc' ) );
30
- define( 'RWMB_FIELDS_DIR', trailingslashit( RWMB_INC_DIR . 'fields' ) );
31
-
32
-
33
- require_once RWMB_INC_DIR . 'common.php';
34
- require_once RWMB_INC_DIR . 'field.php';
35
- require_once RWMB_INC_DIR . 'field-multiple-values.php';
36
-
37
- // Field classes
38
- foreach ( glob( RWMB_FIELDS_DIR . '*.php' ) as $file )
39
  {
40
- require_once $file;
 
41
  }
42
-
43
- // Meta box class
44
- require_once RWMB_INC_DIR . 'meta-box.php';
45
-
46
- // Validation module
47
- require_once RWMB_INC_DIR . 'validation.php';
48
-
49
- // Helper function to retrieve meta value
50
- require_once RWMB_INC_DIR . 'helpers.php';
51
-
52
- // Main file
53
- require_once RWMB_INC_DIR . 'init.php';
3
  * Plugin Name: Meta Box
4
  * Plugin URI: https://metabox.io
5
  * Description: Create custom meta boxes and custom fields for any post type in WordPress.
6
+ * Version: 4.8.0
7
  * Author: Rilwis
8
  * Author URI: http://www.deluxeblogtips.com
9
  * License: GPL2+
11
  * Domain Path: /lang/
12
  */
13
 
14
+ if ( defined( 'ABSPATH' ) && ! class_exists( 'RWMB_Loader' ) )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  {
16
+ require plugin_dir_path( __FILE__ ) . 'inc/loader.php';
17
+ new RWMB_Loader;
18
  }
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -2,9 +2,9 @@
2
  Contributors: rilwis, fitwp, f-j-kaiser, funkatronic, PerWiklander, ruanmer, Omnicia
3
  Donate link: http://www.deluxeblogtips.com/donate
4
  Tags: meta-box, custom fields, custom field, meta, meta-boxes, admin, advanced, custom, edit, field, file, image, magic fields, matrix, more fields, Post, repeater, simple fields, text, textarea, type, cms, fields post
5
- Requires at least: 3.5
6
- Tested up to: 4.4
7
- Stable tag: 4.7.3
8
  License: GPLv2 or later
9
 
10
  Meta Box plugin is a powerful, professional solution to create custom meta boxes and custom fields for WordPress websites.
@@ -77,6 +77,29 @@ To getting started with the plugin API, please read [this tutorial](https://meta
77
 
78
  == Changelog ==
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  = 4.7.3 =
81
 
82
  * Improvement: add `change` event for `file_advanced` and `image_advanced` fields.
2
  Contributors: rilwis, fitwp, f-j-kaiser, funkatronic, PerWiklander, ruanmer, Omnicia
3
  Donate link: http://www.deluxeblogtips.com/donate
4
  Tags: meta-box, custom fields, custom field, meta, meta-boxes, admin, advanced, custom, edit, field, file, image, magic fields, matrix, more fields, Post, repeater, simple fields, text, textarea, type, cms, fields post
5
+ Requires at least: 4.1
6
+ Tested up to: 4.4.2
7
+ Stable tag: 4.8.0
8
  License: GPLv2 or later
9
 
10
  Meta Box plugin is a powerful, professional solution to create custom meta boxes and custom fields for WordPress websites.
77
 
78
  == Changelog ==
79
 
80
+ = 4.8.0 =
81
+
82
+ * Improvement: rewrite the way the plugin loads file, which allows developers to include the plugin into themes/plugins simply by include the main file. The new loading mechanism also uses autoloading feature which prevents loading files twice and saves memory.
83
+ * Improvement: rewrite `user`, `post`, `taxonomy` fields using the same codebase as they're native WordPress objects and sharing similar options. Also changes the syntax of query parameters for these fields (old syntax still works). Please see docs for details.
84
+ * Improvement: add `srcset` in the returned value of helper function for image fields
85
+ * Improvement: better sanitize value for `url` field
86
+ * Improvement: prevent issues with dashes in field types
87
+ * Improvement: remove redundant value in checkbox
88
+ * Improvement: update CSS for date, time fields
89
+ * Improvement: select2 now updated to 4.0.1
90
+ * Improvement: optimize code for `file_advanced` and `image_advanced` fields which now submit array of values when saving instead of single CSV value
91
+ * Improvement: add `collapse` option to `checkbox_list` and `checkbox_tree` in `user`, `taxonomy`, `post` fields which prevents plugin save parent values.
92
+ * Improvement: secure password field so it is no longer saved in plain text. To check if a password matches the hash, please use `wp_check_password`.
93
+ * Improvement: change the output of `color` field in the helper function. Now it shows the color instead of hex value.
94
+ * Improvement: add `color:change` and `color:clear` JavaScript event for detecting changes in `color` field.
95
+ * Improvement: refactor code for better structure and security
96
+ * Fix: rewrite the JavaScript for cloning which causes bugs for date field.
97
+ * Fix: fix missing attributes if value is '0' or 0.
98
+ * Fix: add missing `class` attribute for fields
99
+ * Fix: do not auto populate color field with '#'
100
+ * Fix: wrong callback for fix page template
101
+
102
+
103
  = 4.7.3 =
104
 
105
  * Improvement: add `change` event for `file_advanced` and `image_advanced` fields.